Commit 86cb69b7 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390 (3/7): dasd driver.

 - Remove dynamic allocation of major numbers. Just use static major 94.
 - Use bus_id instead of device number where possible.
 - Don't check open_count in dasd_generic_set_offline.
parent 748f7f37
......@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
* $Revision: 1.110 $
* $Revision: 1.114 $
*/
#include <linux/config.h>
......@@ -1142,8 +1142,8 @@ __dasd_process_blk_queue(struct dasd_device * device)
req = elv_next_request(queue);
if (device->ro_flag && rq_data_dir(req) == WRITE) {
DBF_EVENT(DBF_ERR,
"(%04x) Rejecting write request %p",
_ccw_device_get_device_number(device->cdev),
"(%s) Rejecting write request %p",
device->cdev->dev.bus_id,
req);
blkdev_dequeue_request(req);
dasd_end_request(req, 0);
......@@ -1154,8 +1154,8 @@ __dasd_process_blk_queue(struct dasd_device * device)
if (PTR_ERR(cqr) == -ENOMEM)
break; /* terminate request queue loop */
DBF_EVENT(DBF_ERR,
"(%04x) CCW creation failed on request %p",
_ccw_device_get_device_number(device->cdev),
"(%s) CCW creation failed on request %p",
device->cdev->dev.bus_id,
req);
blkdev_dequeue_request(req);
dasd_end_request(req, 0);
......@@ -1728,12 +1728,10 @@ int
dasd_generic_probe (struct ccw_device *cdev,
struct dasd_discipline *discipline)
{
int devno;
int ret = 0;
devno = _ccw_device_get_device_number(cdev);
if (dasd_autodetect
&& (ret = dasd_add_range(devno, devno, DASD_FEATURE_DEFAULT))) {
if (dasd_autodetect &&
(ret = dasd_add_busid(cdev->dev.bus_id, DASD_FEATURE_DEFAULT))) {
printk (KERN_WARNING
"dasd_generic_probe: cannot autodetect %s\n",
cdev->dev.bus_id);
......@@ -1830,12 +1828,6 @@ dasd_generic_set_offline (struct ccw_device *cdev)
struct dasd_device *device;
device = cdev->dev.driver_data;
if (atomic_read(&device->open_count) > 0) {
printk (KERN_WARNING "Can't offline dasd device with open"
" count = %i.\n",
atomic_read(&device->open_count));
return -EBUSY;
}
dasd_set_target_state(device, DASD_STATE_NEW);
dasd_delete_device(device);
......@@ -1854,7 +1846,6 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
struct device_driver *drv;
struct device *d, *dev;
struct ccw_device *cdev;
int devno;
drv = get_driver(&dasd_discipline_driver->driver);
down_read(&drv->bus->subsys.rwsem);
......@@ -1864,8 +1855,7 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
if (!dev)
continue;
cdev = to_ccwdev(dev);
devno = _ccw_device_get_device_number(cdev);
if (dasd_autodetect || dasd_devno_in_range(devno) == 0)
if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0)
ccw_device_set_online(cdev);
put_device(dev);
}
......@@ -1934,31 +1924,6 @@ dasd_use_diag_store(struct device *dev, const char *buf, size_t count)
static
DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
#if 0
/* this file shows the same information as /proc/dasd/devices using
* an inaccaptable interface */
/* TODO: Split this up into smaller files! */
static ssize_t
dasd_devices_show(struct device *dev, char *buf)
{
struct dasd_device *device;
dasd_devmap_t *devmap;
devmap = NULL;
device = dev->driver_data;
if (device)
devmap = dasd_devmap_from_devno(device->devno);
if (!devmap)
return sprintf(buf, "unused\n");
return min ((size_t) dasd_devices_print(devmap, buf), PAGE_SIZE);
}
static DEVICE_ATTR(dasd, 0444, dasd_devices_show, 0);
#endif
static ssize_t
dasd_discipline_show(struct device *dev, char *buf)
{
......@@ -1973,7 +1938,6 @@ dasd_discipline_show(struct device *dev, char *buf)
static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
static struct attribute * dasd_attrs[] = {
//&dev_attr_dasd.attr,
&dev_attr_readonly.attr,
&dev_attr_discipline.attr,
&dev_attr_use_diag.attr,
......
......@@ -11,7 +11,7 @@
* functions may not be called from interrupt context. In particular
* dasd_get_device is a no-no from interrupt context.
*
* $Revision: 1.17 $
* $Revision: 1.19 $
*/
#include <linux/config.h>
......@@ -37,10 +37,9 @@
* to the device index.
*/
struct dasd_devmap {
struct list_head devindex_list;
struct list_head devno_list;
struct list_head list;
char bus_id[BUS_ID_SIZE];
unsigned int devindex;
unsigned short devno;
unsigned short features;
struct dasd_device *device;
};
......@@ -48,12 +47,15 @@ struct dasd_devmap {
/*
* Parameter parsing functions for dasd= parameter. The syntax is:
* <devno> : (0x)?[0-9a-fA-F]+
* <busid> : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
* <feature> : ro
* <feature_list> : \(<feature>(:<feature>)*\)
* <range> : <devno>(-<devno>)?<feature_list>?
* <devno-range> : <devno>(-<devno>)?<feature_list>?
* <busid-range> : <busid>(-<busid>)?<feature_list>?
* <devices> : <devno-range>|<busid-range>
* <dasd_module> : dasd_diag_mod|dasd_eckd_mod|dasd_fba_mod
*
* <dasd> : autodetect|probeonly|<range>(,<range>)*
* <dasd> : autodetect|probeonly|<devices>(,<devices>)*
*/
int dasd_probeonly = 0; /* is true, when probeonly mode is active */
......@@ -74,10 +76,20 @@ static spinlock_t dasd_devmap_lock = SPIN_LOCK_UNLOCKED;
/*
* Hash lists for devmap structures.
*/
static struct list_head dasd_devindex_hashlists[256];
static struct list_head dasd_devno_hashlists[256];
static struct list_head dasd_hashlists[256];
int dasd_max_devindex;
static inline int
dasd_hash_busid(char *bus_id)
{
int hash, i;
hash = 0;
for (i = 0; (i < BUS_ID_SIZE) && *bus_id; i++, bus_id++)
hash += *bus_id;
return hash & 0xff;
}
#ifndef MODULE
/*
* The parameter parsing functions for builtin-drivers are called
......@@ -98,27 +110,47 @@ __setup ("dasd=", dasd_call_setup);
#endif /* #ifndef MODULE */
/*
* Read a device number from a string. The number is always in hex,
* a leading 0x is accepted.
* Read a device busid/devno from a string.
*/
static inline int
dasd_devno(char *str, char **endp)
dasd_busid(char **str, int *id0, int *id1, int *devno)
{
int val;
int val, old_style;
/* remove leading '0x' */
if (*str == '0') {
str++;
if (*str == 'x')
str++;
/* check for leading '0x' */
old_style = 0;
if ((*str)[0] == '0' && (*str)[1] == 'x') {
*str += 2;
old_style = 1;
}
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
return -EINVAL;
val = simple_strtoul(*str, str, 16);
if (old_style || (*str)[0] != '.') {
*id0 = *id1 = 0;
if (val < 0 || val > 0xffff)
return -EINVAL;
*devno = val;
return 0;
}
/* We require at least one hex digit */
if (!isxdigit(*str))
/* New style x.y.z busid */
if (val < 0 || val > 0xff)
return -EINVAL;
*id0 = val;
(*str)++;
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
return -EINVAL;
val = simple_strtoul(*str, str, 16);
if (val < 0 || val > 0xff || (*str)++[0] != '.')
return -EINVAL;
val = simple_strtoul(str, endp, 16);
if ((val > 0xFFFF) || (val < 0))
*id1 = val;
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
return -EINVAL;
return val;
val = simple_strtoul(*str, str, 16);
if (val < 0 || val > 0xffff)
return -EINVAL;
*devno = val;
return 0;
}
/*
......@@ -171,18 +203,37 @@ dasd_feature_list(char *str, char **endp)
static inline int
dasd_ranges_list(char *str)
{
int from, to, features, rc;
int from, from_id0, from_id1;
int to, to_id0, to_id1;
int features, rc;
char bus_id[BUS_ID_SIZE+1], *orig_str;
orig_str = str;
while (1) {
to = from = dasd_devno(str, &str);
rc = dasd_busid(&str, &from_id0, &from_id1, &from);
if (rc == 0) {
to = from;
to_id0 = from_id0;
to_id1 = from_id1;
if (*str == '-') {
str++;
to = dasd_devno(str, &str);
rc = dasd_busid(&str, &to_id0, &to_id1, &to);
}
}
if (rc == 0 &&
(from_id0 != to_id0 || from_id1 != to_id1 || from > to))
rc = -EINVAL;
if (rc) {
MESSAGE(KERN_ERR, "Invalid device range %s", orig_str);
return rc;
}
features = dasd_feature_list(str, &str);
/* Negative numbers in from/to/features indicate errors */
if (from >= 0 && to >= 0 && features >= 0) {
rc = dasd_add_range(from, to, features);
if (features < 0)
return -EINVAL;
while (from <= to) {
sprintf(bus_id, "%01x.%01x.%04x",
from_id0, from_id1, from++);
rc = dasd_add_busid(bus_id, features);
if (rc)
return rc;
}
......@@ -243,77 +294,74 @@ dasd_parse(void)
}
/*
* Add a range of devices and creates the corresponding devreg_t
* structures. The order of the ranges added through this function
* will define the kdevs for the individual devices.
* Add a devmap for the device specified by busid. It is possible that
* the devmap already exists (dasd= parameter). The order of the devices
* added through this function will define the kdevs for the individual
* devices.
*/
int
dasd_add_range(int from, int to, int features)
dasd_add_busid(char *bus_id, int features)
{
int devindex;
int devno;
struct dasd_devmap *devmap, *new, *tmp;
int hash;
if (from > to) {
MESSAGE(KERN_ERR,
"Invalid device range %04x-%04x", from, to);
return -EINVAL;
}
new = (struct dasd_devmap *)
kmalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
if (!new)
return -ENOMEM;
spin_lock(&dasd_devmap_lock);
for (devno = from; devno <= to; devno++) {
struct dasd_devmap *devmap, *tmp;
devmap = NULL;
/* Find previous devmap for device number i */
list_for_each_entry(tmp, &dasd_devno_hashlists[devno & 255],
devno_list) {
if (tmp->devno == devno) {
devmap = 0;
hash = dasd_hash_busid(bus_id);
list_for_each_entry(tmp, &dasd_hashlists[hash], list)
if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
devmap = tmp;
break;
}
}
if (devmap == NULL) {
/* This devno is new. */
devmap = (struct dasd_devmap *)
kmalloc(sizeof(struct dasd_devmap),GFP_KERNEL);
if (devmap == NULL)
return -ENOMEM;
devindex = dasd_max_devindex++;
devmap->devindex = devindex;
devmap->devno = devno;
devmap->features = features;
devmap->device = NULL;
list_add(&devmap->devindex_list,
&dasd_devindex_hashlists[devindex & 255]);
list_add(&devmap->devno_list,
&dasd_devno_hashlists[devno & 255]);
}
if (!devmap) {
/* This bus_id is new. */
new->devindex = dasd_max_devindex++;
strncpy(new->bus_id, bus_id, BUS_ID_SIZE);
new->features = features;
new->device = 0;
list_add(&new->list, &dasd_hashlists[hash]);
devmap = new;
new = 0;
}
spin_unlock(&dasd_devmap_lock);
if (new)
kfree(new);
return 0;
}
/*
* Check if devno has been added to the list of dasd ranges.
* Find devmap for device with given bus_id.
*/
int
dasd_devno_in_range(int devno)
static struct dasd_devmap *
dasd_find_busid(char *bus_id)
{
struct dasd_devmap *devmap;
int ret;
struct dasd_devmap *devmap, *tmp;
int hash;
ret = -ENOENT;
spin_lock(&dasd_devmap_lock);
/* Find devmap for device with device number devno */
list_for_each_entry(devmap, &dasd_devno_hashlists[devno&255],
devno_list) {
if (devmap->devno == devno) {
/* Found the device. */
ret = 0;
devmap = 0;
hash = dasd_hash_busid(bus_id);
list_for_each_entry(tmp, &dasd_hashlists[hash], list) {
if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
devmap = tmp;
break;
}
}
spin_unlock(&dasd_devmap_lock);
return ret;
return devmap;
}
/*
* Check if busid has been added to the list of dasd ranges.
*/
int
dasd_busid_known(char *bus_id)
{
return dasd_find_busid(bus_id) ? 0 : -ENOENT;
}
/*
......@@ -323,18 +371,15 @@ dasd_devno_in_range(int devno)
static void
dasd_forget_ranges(void)
{
struct dasd_devmap *devmap, *n;
int i;
spin_lock(&dasd_devmap_lock);
for (i = 0; i < 256; i++) {
struct list_head *l, *next;
struct dasd_devmap *devmap;
list_for_each_safe(l, next, &dasd_devno_hashlists[i]) {
devmap = list_entry(l, struct dasd_devmap, devno_list);
list_for_each_entry_safe(devmap, n, &dasd_hashlists[i], list) {
if (devmap->device != NULL)
BUG();
list_del(&devmap->devindex_list);
list_del(&devmap->devno_list);
list_del(&devmap->list);
kfree(devmap);
}
}
......@@ -342,64 +387,28 @@ dasd_forget_ranges(void)
}
/*
* Find the devmap structure from a devno. Can be removed as soon
* as big minors are available.
*/
static struct dasd_devmap *
dasd_devmap_from_devno(int devno)
{
struct dasd_devmap *devmap, *tmp;
devmap = NULL;
spin_lock(&dasd_devmap_lock);
/* Find devmap for device with device number devno */
list_for_each_entry(tmp, &dasd_devno_hashlists[devno&255], devno_list) {
if (tmp->devno == devno) {
/* Found the device, return devmap */
devmap = tmp;
break;
}
}
spin_unlock(&dasd_devmap_lock);
return devmap;
}
/*
* Find the devmap for a device by its device index. Can be removed
* as soon as big minors are available.
* Find the device struct by its device index.
*/
static struct dasd_devmap *
dasd_devmap_from_devindex(int devindex)
struct dasd_device *
dasd_device_from_devindex(int devindex)
{
struct dasd_devmap *devmap, *tmp;
struct dasd_device *device;
int i;
devmap = NULL;
spin_lock(&dasd_devmap_lock);
/* Find devmap for device with device index devindex */
list_for_each_entry(tmp, &dasd_devindex_hashlists[devindex & 255],
devindex_list) {
devmap = 0;
for (i = 0; (i < 256) && !devmap; i++)
list_for_each_entry(tmp, &dasd_hashlists[i], list)
if (tmp->devindex == devindex) {
/* Found the device, return devno */
/* Found the devmap for the device. */
devmap = tmp;
break;
}
}
spin_unlock(&dasd_devmap_lock);
return devmap;
}
struct dasd_device *
dasd_device_from_devindex(int devindex)
{
struct dasd_devmap *devmap;
struct dasd_device *device;
devmap = dasd_devmap_from_devindex(devindex);
spin_lock(&dasd_devmap_lock);
if (devmap && devmap->device) {
device = devmap->device;
if (device)
dasd_get_device(device);
else
} else
device = ERR_PTR(-ENODEV);
spin_unlock(&dasd_devmap_lock);
return device;
......@@ -413,16 +422,15 @@ dasd_create_device(struct ccw_device *cdev)
{
struct dasd_devmap *devmap;
struct dasd_device *device;
int devno;
int rc;
devno = _ccw_device_get_device_number(cdev);
rc = dasd_add_range(devno, devno, DASD_FEATURE_DEFAULT);
rc = dasd_add_busid(cdev->dev.bus_id, DASD_FEATURE_DEFAULT);
if (rc)
return ERR_PTR(rc);
if (!(devmap = dasd_devmap_from_devno (devno)))
return ERR_PTR(-ENODEV);
devmap = dasd_find_busid(cdev->dev.bus_id);
if (IS_ERR(devmap))
return (void *) devmap;
device = dasd_alloc_device();
if (IS_ERR(device))
......@@ -467,11 +475,9 @@ dasd_delete_device(struct dasd_device *device)
{
struct ccw_device *cdev;
struct dasd_devmap *devmap;
int devno;
/* First remove device pointer from devmap. */
devno = _ccw_device_get_device_number(device->cdev);
devmap = dasd_devmap_from_devno (devno);
devmap = dasd_find_busid(device->cdev->dev.bus_id);
spin_lock(&dasd_devmap_lock);
devmap->device = NULL;
spin_unlock(&dasd_devmap_lock);
......@@ -509,10 +515,8 @@ dasd_devmap_init(void)
/* Initialize devmap structures. */
dasd_max_devindex = 0;
for (i = 0; i < 256; i++) {
INIT_LIST_HEAD(&dasd_devindex_hashlists[i]);
INIT_LIST_HEAD(&dasd_devno_hashlists[i]);
}
for (i = 0; i < 256; i++)
INIT_LIST_HEAD(&dasd_hashlists[i]);
return 0;
}
......
......@@ -7,9 +7,9 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
* Dealing with devices registered to multiple major numbers.
* gendisk related functions for the dasd driver.
*
* $Revision: 1.38 $
* $Revision: 1.41 $
*/
#include <linux/config.h>
......@@ -24,116 +24,26 @@
#include "dasd_int.h"
static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;
static struct list_head dasd_major_info = LIST_HEAD_INIT(dasd_major_info);
struct major_info {
struct list_head list;
int major;
};
/*
* Register major number for the dasd driver. Call with DASD_MAJOR to
* setup the static dasd device major 94 or with 0 to allocated a major
* dynamically.
*/
static int
dasd_register_major(int major)
{
struct major_info *mi;
int new_major;
/* Allocate major info structure. */
mi = kmalloc(sizeof(struct major_info), GFP_KERNEL);
/* Check if one of the allocations failed. */
if (mi == NULL) {
MESSAGE(KERN_WARNING, "%s",
"Cannot get memory to allocate another "
"major number");
return -ENOMEM;
}
/* Register block device. */
new_major = register_blkdev(major, "dasd");
if (new_major < 0) {
kfree(mi);
return new_major;
}
if (major != 0)
new_major = major;
/* Initialize major info structure. */
mi->major = new_major;
/* Insert the new major info structure into dasd_major_info list. */
spin_lock(&dasd_major_lock);
list_add_tail(&mi->list, &dasd_major_info);
spin_unlock(&dasd_major_lock);
return 0;
}
static void
dasd_unregister_major(struct major_info * mi)
{
int rc;
if (mi == NULL)
return;
/* Delete the major info from dasd_major_info. */
spin_lock(&dasd_major_lock);
list_del(&mi->list);
spin_unlock(&dasd_major_lock);
rc = unregister_blkdev(mi->major, "dasd");
if (rc < 0)
MESSAGE(KERN_WARNING,
"Cannot unregister from major no %d, rc = %d",
mi->major, rc);
/* Free memory. */
kfree(mi);
}
/*
* Allocate and register gendisk structure for device.
*/
int
dasd_gendisk_alloc(struct dasd_device *device)
{
struct major_info *mi;
struct gendisk *gdp;
int index, len, rc;
/* Make sure the major for this device exists. */
mi = NULL;
while (1) {
spin_lock(&dasd_major_lock);
index = device->devindex;
list_for_each_entry(mi, &dasd_major_info, list) {
if (index < DASD_PER_MAJOR)
break;
index -= DASD_PER_MAJOR;
}
spin_unlock(&dasd_major_lock);
if (index < DASD_PER_MAJOR)
break;
rc = dasd_register_major(0);
if (rc) {
DBF_EXC(DBF_ALERT, "%s", "out of major numbers!");
return rc;
}
}
int len;
/* Make sure the minor for this device exists. */
if (device->devindex >= DASD_PER_MAJOR)
return -EBUSY;
gdp = alloc_disk(1 << DASD_PARTN_BITS);
if (!gdp)
return -ENOMEM;
/* Initialize gendisk structure. */
gdp->major = mi->major;
gdp->first_minor = index << DASD_PARTN_BITS;
gdp->major = DASD_MAJOR;
gdp->first_minor = device->devindex << DASD_PARTN_BITS;
gdp->fops = &dasd_device_operations;
gdp->driverfs_dev = &device->cdev->dev;
......@@ -153,8 +63,7 @@ dasd_gendisk_alloc(struct dasd_device *device)
}
len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
sprintf(gdp->devfs_name, "dasd/%04x",
_ccw_device_get_device_number(device->cdev));
sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
if (device->ro_flag)
set_disk_ro(gdp, 1);
......@@ -173,6 +82,7 @@ void
dasd_gendisk_free(struct dasd_device *device)
{
del_gendisk(device->gdp);
device->gdp->queue = 0;
put_disk(device->gdp);
device->gdp = 0;
}
......@@ -221,7 +131,7 @@ dasd_gendisk_init(void)
int rc;
/* Register to static dasd major 94 */
rc = dasd_register_major(DASD_MAJOR);
rc = register_blkdev(DASD_MAJOR, "dasd");
if (rc != 0) {
MESSAGE(KERN_WARNING,
"Couldn't register successfully to "
......@@ -234,10 +144,5 @@ dasd_gendisk_init(void)
void
dasd_gendisk_exit(void)
{
struct list_head *l, *n;
spin_lock(&dasd_major_lock);
list_for_each_safe(l, n, &dasd_major_info)
dasd_unregister_major(list_entry(l, struct major_info, list));
spin_unlock(&dasd_major_lock);
unregister_blkdev(DASD_MAJOR, "dasd");
}
......@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
* $Revision: 1.45 $
* $Revision: 1.48 $
*/
#ifndef DASD_INT_H
......@@ -15,7 +15,7 @@
#ifdef __KERNEL__
/* we keep old device allocation scheme; IOW, minors are still in 0..255 */
#define DASD_PER_MAJOR ( 1U<<(8-DASD_PARTN_BITS))
#define DASD_PER_MAJOR (1U << (MINORBITS - DASD_PARTN_BITS))
#define DASD_PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
/*
......@@ -477,8 +477,8 @@ void dasd_delete_device(struct dasd_device *);
struct dasd_device *dasd_device_from_devindex(int);
int dasd_parse(void);
int dasd_add_range(int, int, int);
int dasd_devno_in_range(int);
int dasd_add_busid(char *, int);
int dasd_busid_known(char *);
/* externals in dasd_gendisk.c */
int dasd_gendisk_init(void);
......
......@@ -9,7 +9,7 @@
*
* /proc interface for the dasd driver.
*
* $Revision: 1.22 $
* $Revision: 1.23 $
*/
#include <linux/config.h>
......@@ -59,7 +59,7 @@ dasd_devices_show(struct seq_file *m, void *v)
if (IS_ERR(device))
return 0;
/* Print device number. */
seq_printf(m, "%04x", _ccw_device_get_device_number(device->cdev));
seq_printf(m, "%s", device->cdev->dev.bus_id);
/* Print discipline string. */
if (device != NULL && device->discipline != NULL)
seq_printf(m, "(%s)", device->discipline->name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment