diff --git a/drivers/zio-ad788x.c b/drivers/zio-ad788x.c index 7f3d644acf3bee90c33ecfcddaae90ff5a6f67ea..a9f49d27ddb80c62dcfe31247bc936c83ef89839 100644 --- a/drivers/zio-ad788x.c +++ b/drivers/zio-ad788x.c @@ -44,12 +44,11 @@ struct ad788x_context { }; struct ad788x { - struct zio_device zdev; + struct zio_device *zdev; enum ad788x_devices type; struct spi_device *spi; uint16_t cmd; }; -#define to_ad788x(_zdev) container_of(_zdev, struct ad788x, zdev) /* * AD788x don't have register to store data configuration; configuration * option are sent every time when we want acquire. So, there is no address @@ -85,25 +84,24 @@ static int ad788x_conf_set(struct device *dev, struct zio_attribute *zattr, uint32_t usr_val) { unsigned long mask = zattr->priv.addr; - struct ad788x *ad788x_tmp; + struct ad788x *ad788x; - ad788x_tmp = to_ad788x(to_zio_dev(dev)); + ad788x = to_zio_dev(dev)->private_data; switch (mask) { case AD788x_PM_ADDR: /* power management */ if (usr_val < 4) return -EINVAL; - ad788x_tmp->cmd = (ad788x_tmp->cmd & ~mask) | usr_val; + ad788x->cmd = (ad788x->cmd & ~mask) | usr_val; break; case AD7887_VREF_ADDR: /* v_ref source ad7887 */ case AD7888_VREF_ADDR: /* v_ref source ad7888 */ case AD7887_SINDUAL_ADDR: /* ad7887 single or dual */ if (usr_val > 1) /* single bit: 0 or 1 */ return -EINVAL; - ad788x_tmp->cmd = (ad788x_tmp->cmd & ~mask) | - (usr_val ? mask : 0); + ad788x->cmd = (ad788x->cmd & ~mask) | (usr_val ? mask : 0); break; } - pr_debug("%s:%d 0x%x\n", __func__, __LINE__, ad788x_tmp->cmd); + pr_debug("%s:%d 0x%x\n", __func__, __LINE__, ad788x->cmd); return 0; } @@ -111,14 +109,12 @@ static int ad788x_conf_set(struct device *dev, struct zio_attribute *zattr, static void ad788x_complete(void *cont) { struct ad788x_context *context = (struct ad788x_context *) cont; - struct ad788x *ad788x; struct zio_channel *chan; struct zio_cset *cset ; uint16_t *data, *buf; int i, j = 0; cset = context->cset; - ad788x = to_ad788x(cset->zdev); data = (uint16_t *) context->transfer.rx_buf; data = &data[1]; /* demux data */ @@ -149,7 +145,7 @@ static int ad788x_input_cset(struct zio_cset *cset) if (!context) return -ENOMEM; - ad788x = to_ad788x(cset->zdev); + ad788x = cset->zdev->private_data; context->chan_enable = __get_n_chan_enabled(cset); /* prepare SPI message and transfer */ @@ -214,10 +210,8 @@ static struct zio_cset ad7888_ain_cset[] = { /* ad7888 cset */ ZIO_DIR_INPUT /* is input */, }, }; -static struct ad788x ad788x_devices[] = { - [ID_AD7887] = { - .type = ID_AD7887, - .zdev = { /* ad7887 template */ +static struct zio_device ad788x_tmpl[] = { + [ID_AD7887] = { /* ad7887 template */ .owner = THIS_MODULE, .s_op = &ad788x_s_op, .flags = 0, @@ -228,11 +222,8 @@ static struct ad788x ad788x_devices[] = { .ext_zattr = zattr_dev_ext_ad7887, .n_ext_attr = ARRAY_SIZE(zattr_dev_ext_ad7887), }, - }, }, - [ID_AD7888] = { - .type = ID_AD7888, - .zdev = { /* ad7888 template */ + [ID_AD7888] = { /* ad7888 template */ .owner = THIS_MODULE, .s_op = &ad788x_s_op, .flags = 0, @@ -243,66 +234,94 @@ static struct ad788x ad788x_devices[] = { .ext_zattr = zattr_dev_ext_ad7888, .n_ext_attr = ARRAY_SIZE(zattr_dev_ext_ad7888), }, - }, }, }; -static int __devinit ad788x_probe(struct spi_device *spi) +static int ad788x_zio_probe(struct zio_device *zdev) +{ + struct zio_attribute_set *zattr_set; + struct ad788x *ad788x; + int vshift; + + pr_info("%s:%d\n", __func__, __LINE__); + ad788x = zdev->private_data; + zattr_set = &zdev->zattr_set; + ad788x->zdev = zdev; + + /* Setting up the default value for the SPI command */ + vshift = (ad788x->type == ID_AD7887 ? AD7887_VREF_SHIFT : + AD7888_VREF_SHIFT); + ad788x->cmd = zattr_set->std_zattr[ZATTR_VREFTYPE].value << vshift; + ad788x->cmd |= zattr_set->ext_zattr[0].value << AD788x_PM_SHIFT; + if (ad788x->type == ID_AD7887) + ad788x->cmd |= zattr_set->ext_zattr[1].value << + AD7887_SINDUAL_SHIFT; + return 0; +} + +static const struct zio_device_id ad788x_table[] = { + {"ad7887", &ad788x_tmpl[ID_AD7887]}, + {"ad7888", &ad788x_tmpl[ID_AD7888]}, + {}, +}; +static struct zio_driver ad788x_zdrv = { + .driver = { + .name = "zio-ad788x", + .owner = THIS_MODULE, + }, + .id_table = ad788x_table, + .probe = ad788x_zio_probe, +}; + +static int __devinit ad788x_spi_probe(struct spi_device *spi) { const struct spi_device_id *spi_id; - struct ad788x *ad788x_tmp; - int err; + struct zio_device *zdev; + struct ad788x *ad788x; + int err = 0; + uint32_t dev_id; - spi_id = spi_get_device_id(spi); - if (!spi_id) - return -ENODEV; + ad788x = kzalloc(sizeof(struct ad788x), GFP_KERNEL); + if (!ad788x) + return -ENOMEM; + /* Configure SPI */ - switch (spi_id->driver_data) { - case ID_AD7887: - ad788x_tmp = &ad788x_devices[ID_AD7887]; - ad788x_tmp->cmd = - zattr_dev_ad7887[ZATTR_VREFTYPE].value << - AD7887_VREF_SHIFT | - zattr_dev_ext_ad7887[1].value << - AD7887_SINDUAL_SHIFT; - break; - case ID_AD7888: - ad788x_tmp = &ad788x_devices[ID_AD7888]; - ad788x_tmp->cmd = - zattr_dev_ad7888[ZATTR_VREFTYPE].value << - AD7888_VREF_SHIFT; - break; - default: - WARN(1, "%s cannot identify device\n", __func__); - break; - } - /* default value for PM is the same for all the ad788x */ - ad788x_tmp->cmd |= zattr_dev_ext_ad7888[0].value << AD788x_PM_SHIFT; - - if (ad788x_trigger) - ad788x_devices[ad788x_tmp->type].zdev.preferred_trigger = - ad788x_trigger; - if (ad788x_buffer) - ad788x_devices[ad788x_tmp->type].zdev.preferred_buffer = - ad788x_buffer; - ad788x_tmp->spi = spi; - spi_set_drvdata(spi, &ad788x_tmp); spi->bits_per_word = 16; err = spi_setup(spi); if (err) return err; + spi_id = spi_get_device_id(spi); + if (!spi_id) + return -ENODEV; + ad788x->spi = spi; + ad788x->type = spi_id->driver_data; + + /* zdev here is the generic device */ + zdev = zio_allocate_device(); + zdev->private_data = ad788x; + zdev->owner = THIS_MODULE; + spi_set_drvdata(spi, zdev); + dev_id = spi->chip_select | (spi->master->bus_num << 8); - return zio_register_dev(&ad788x_devices[ad788x_tmp->type].zdev, - spi_id->name); + /* Register a ZIO device */ + err= zio_register_device(zdev, spi_id->name, dev_id); + if (err) + kfree(ad788x); + return err; } -static int __devexit ad788x_remove(struct spi_device *spi) +static int __devexit ad788x_spi_remove(struct spi_device *spi) { - struct ad788x *ad788x_tmp; + struct zio_device *zdev; + struct ad788x *ad788x; - ad788x_tmp = spi_get_drvdata(spi); - zio_unregister_dev(&ad788x_devices[ad788x_tmp->type].zdev); + /* zdev here is the generic device */ + zdev = spi_get_drvdata(spi); + ad788x = zdev->private_data; + zio_unregister_device(zdev); + kfree(ad788x); + zio_free_device(zdev); return 0; } @@ -313,17 +332,29 @@ static struct spi_driver ad788x_driver = { .owner = THIS_MODULE, }, .id_table = ad788x_id, - .probe = ad788x_probe, - .remove = __devexit_p(ad788x_remove), + .probe = ad788x_spi_probe, + .remove = __devexit_p(ad788x_spi_remove), }; static int __init ad788x_init(void) { + int err, i; + + for (i = 0; i < ARRAY_SIZE(ad788x_tmpl); ++i) { + if (ad788x_trigger) + ad788x_tmpl[i].preferred_trigger = ad788x_trigger; + if (ad788x_buffer) + ad788x_tmpl[i].preferred_buffer = ad788x_buffer; + } + err = zio_register_driver(&ad788x_zdrv); + if (err) + return err; return spi_register_driver(&ad788x_driver); } static void __exit ad788x_exit(void) { driver_unregister(&ad788x_driver.driver); + zio_unregister_driver(&ad788x_zdrv); } module_init(ad788x_init); diff --git a/drivers/zio-gpio.c b/drivers/zio-gpio.c index 49fe7f9bc6f951d589fa334e9a558dba4efb0771..6b9811a2c852834d2c0fc4cc88c043090d8ab127 100644 --- a/drivers/zio-gpio.c +++ b/drivers/zio-gpio.c @@ -101,7 +101,7 @@ static struct zio_cset zgp_cset[] = { .flags = ZIO_DIR_INPUT | ZCSET_TYPE_ANALOG, }, }; -static struct zio_device zgp_dev = { +static struct zio_device zgp_tmpl = { .owner = THIS_MODULE, .cset = zgp_cset, .n_cset = ARRAY_SIZE(zgp_cset), @@ -110,6 +110,19 @@ static struct zio_device zgp_dev = { }, }; +static struct zio_device *zgp_dev; +static const struct zio_device_id zzero_table[] = { + {"gpio", &zgp_tmpl}, + {}, +}; + +static struct zio_driver zpg_zdrv = { + .driver = { + .name = "gpio", + .owner = THIS_MODULE, + }, + .id_table = zzero_table, +}; static int __init zgp_init(void) { @@ -143,14 +156,24 @@ static int __init zgp_init(void) } if (zgp_trigger) - zgp_dev.preferred_trigger = zgp_trigger; + zgp_tmpl.preferred_trigger = zgp_trigger; if (zgp_buffer) - zgp_dev.preferred_buffer = zgp_buffer; - err = zio_register_dev(&zgp_dev, "gpio"); + zgp_tmpl.preferred_buffer = zgp_buffer; + + err = zio_register_driver(&zpg_zdrv); + if (err) + goto out_input; + zgp_dev = zio_allocate_device(); + if (IS_ERR(zgp_dev)) { + err = PTR_ERR(zgp_dev); + goto out_alloc; + } + zgp_dev->owner = THIS_MODULE; + err = zio_register_device(zgp_dev, "gpio", 0); if (err) { pr_err(KBUILD_MODNAME ": can't register zio driver " "(error %i)\n", err); - goto out_input; + goto out_reg; } for (i = 0; i < zgp_nout; i++) @@ -159,6 +182,10 @@ static int __init zgp_init(void) gpio_direction_input(zgp_in[i]); return 0; +out_reg: + zio_free_device(zgp_dev); +out_alloc: + zio_unregister_driver(&zpg_zdrv); out_input: /* i is one more than the last registered gpio */ for (i--; i >= 0; i--) @@ -174,7 +201,10 @@ out: static void __exit zgp_exit(void) { int i; - zio_unregister_dev(&zgp_dev); + + zio_unregister_device(zgp_dev); + zio_free_device(zgp_dev); + zio_unregister_driver(&zpg_zdrv); for (i = 0; i < zgp_nout; i++) gpio_free(zgp_out[i]); for (i = 0; i < zgp_nin; i++) diff --git a/drivers/zio-zero.c b/drivers/zio-zero.c index c10cb443d8f299bb316b2abcf5893399360d8288..49037efd71749013f7c75b284b34d86cd6130a5f 100644 --- a/drivers/zio-zero.c +++ b/drivers/zio-zero.c @@ -73,7 +73,7 @@ static struct zio_cset zzero_cset[] = { }, }; -static struct zio_device zzero_dev = { +static struct zio_device zzero_tmpl = { .owner = THIS_MODULE, .cset = zzero_cset, .n_cset = ARRAY_SIZE(zzero_cset), @@ -82,18 +82,54 @@ static struct zio_device zzero_dev = { }, }; +static struct zio_device *zzero_dev; +static const struct zio_device_id zzero_table[] = { + {"zzero", &zzero_tmpl}, + {}, +}; + +static struct zio_driver zzero_zdrv = { + .driver = { + .name = "zzero", + .owner = THIS_MODULE, + }, + .id_table = zzero_table, +}; + static int __init zzero_init(void) { + int err; + if (zzero_trigger) - zzero_dev.preferred_trigger = zzero_trigger; + zzero_tmpl.preferred_trigger = zzero_trigger; if (zzero_buffer) - zzero_dev.preferred_buffer = zzero_buffer; - return zio_register_dev(&zzero_dev, "zzero"); + zzero_tmpl.preferred_buffer = zzero_buffer; + + err = zio_register_driver(&zzero_zdrv); + if (err) + return err; + zzero_dev = zio_allocate_device(); + if (IS_ERR(zzero_dev)) { + err = PTR_ERR(zzero_dev); + goto out_all; + } + zzero_dev->owner = THIS_MODULE; + err = zio_register_device(zzero_dev, "zzero", 0); + if (err) + goto out_dev; + return 0; +out_dev: + zio_free_device(zzero_dev); +out_all: + zio_unregister_driver(&zzero_zdrv); + return err; } static void __exit zzero_exit(void) { - zio_unregister_dev(&zzero_dev); + zio_unregister_device(zzero_dev); + zio_free_device(zzero_dev); + zio_unregister_driver(&zzero_zdrv); } module_init(zzero_init); diff --git a/include/linux/zio.h b/include/linux/zio.h index 827683cdc9e845291e0bd344ef51b89a3c14a60f..a125a371205f26bff514a181df0e781f7e31dfdc 100644 --- a/include/linux/zio.h +++ b/include/linux/zio.h @@ -111,6 +111,26 @@ enum zobj_flags { ZIO_DIR_OUTPUT = 0x2, }; +/* + * zio_device_id -- struct use to match driver with device + */ +struct zio_device_id { + char name[ZIO_OBJ_NAME_LEN]; + struct zio_device *template; +}; +/* + * zio_driver -- the struct driver for zio + */ +struct zio_driver { + const struct zio_device_id *id_table; + int (*probe)(struct zio_device *dev); + int (*remove)(struct zio_device *dev); + struct device_driver driver; +}; +#define to_zio_drv(_drv) container_of(_drv, struct zio_driver, driver) +extern struct bus_type zio_bus_type; +int zio_register_driver(struct zio_driver *zdrv); +void zio_unregister_driver(struct zio_driver *zdrv); /* * zio_device -- the top-level hardware description */ @@ -129,10 +149,13 @@ struct zio_device { /* We can state what its preferred buffer and trigger are (NULL ok) */ char *preferred_buffer; char *preferred_trigger; + void *private_data; }; - -int __must_check zio_register_dev(struct zio_device *zdev, const char *name); -void zio_unregister_dev(struct zio_device *zio_dev); +struct zio_device *zio_allocate_device(void); +void zio_free_device(struct zio_device *dev); +int __must_check zio_register_device(struct zio_device *zdev, const char *name, + uint32_t dev_id); +void zio_unregister_device(struct zio_device *zdev); /* * zio_cset -- channel set: a group of channels with the same features @@ -175,9 +198,8 @@ enum zcset_flags { ZCSET_TYPE_DIGITAL = 0x00, ZCSET_TYPE_ANALOG = 0x10, ZCSET_TYPE_TIME = 0x20, - ZCSET_CHAN_ALLOC = 0x80, /* 1 if channels are allocated by zio*/ - ZCSET_CHAN_ALLOC_ON = 0x80, - ZCSET_CHAN_ALLOC_OFF = 0x00, + ZCSET_CHAN_TEMPLATE = 0x80, /* 1 if channels from template */ + }; /* diff --git a/zio-cdev.c b/zio-cdev.c index 02e8ed5b5bfe23c76c2107144629efa8fabcb2b3..fbfdd2448cac8cf69ace781fd9958920a354c891 100644 --- a/zio-cdev.c +++ b/zio-cdev.c @@ -218,7 +218,7 @@ int zio_create_chan_devices(struct zio_channel *chan) pr_debug("%s:%d dev_t=0x%x\n", __func__, __LINE__, devt_c); chan->ctrl_dev = device_create(&zio_class, NULL, devt_c, &chan->flags, "%s-%i-%i-ctrl", - chan->cset->zdev->head.name, + dev_name(&chan->cset->zdev->head.dev), chan->cset->index, chan->index); if (IS_ERR(&chan->ctrl_dev)) { @@ -230,7 +230,7 @@ int zio_create_chan_devices(struct zio_channel *chan) pr_debug("%s:%d dev_t=0x%x\n", __func__, __LINE__, devt_d); chan->data_dev = device_create(&zio_class, NULL, devt_d, &chan->flags, "%s-%i-%i-data", - chan->cset->zdev->head.name, + dev_name(&chan->cset->zdev->head.dev), chan->cset->index, chan->index); if (IS_ERR(&chan->data_dev)) { diff --git a/zio-sys.c b/zio-sys.c index 08277a09f2c6cfb482e8c08357ded748b91a56d5..2ee1d160f571629a8808457d07202095dc57ae2f 100644 --- a/zio-sys.c +++ b/zio-sys.c @@ -42,14 +42,19 @@ const char zio_zbuf_attr_names[ZATTR_STD_NUM_ZBUF][ZIO_NAME_LEN] = { }; EXPORT_SYMBOL(zio_zbuf_attr_names); -/* buffer instance prototype */ +/* device instance prototypes */ +static int cset_register(struct zio_cset *cset, struct zio_cset *cset_t); +static void cset_unregister(struct zio_cset *cset); +static int __zdev_register(struct zio_device *parent, + const struct zio_device_id *id); +/* buffer instance prototypes */ static struct zio_bi *__bi_create_and_init(struct zio_buffer_type *zbuf, struct zio_channel *chan); static void __bi_destroy(struct zio_buffer_type *zbuf, struct zio_bi *bi); static int __bi_register(struct zio_buffer_type *zbuf, struct zio_channel *chan, struct zio_bi *bi, const char *name); static void __bi_unregister(struct zio_buffer_type *zbuf, struct zio_bi *bi); -/* trigger instance prototype */ +/* trigger instance prototypes */ static struct zio_ti *__ti_create_and_init(struct zio_trigger_type *trig, struct zio_cset *cset); static void __ti_destroy(struct zio_trigger_type *trig, struct zio_ti *ti); @@ -58,6 +63,10 @@ static int __ti_register(struct zio_trigger_type *trig, struct zio_cset *cset, static void __ti_unregister(struct zio_trigger_type *trig, struct zio_ti *ti); /* Attributes initlialization */ static void __zattr_trig_init_ctrl(struct zio_ti *ti, struct zio_control *ctrl); +/* sysfs attribute prototypes */ +static int zattr_set_create(struct zio_obj_head *head, + const struct zio_sysfs_operations *s_op); +static void zattr_set_remove(struct zio_obj_head *head); /* * Top-level ZIO objects has a unique name. @@ -83,6 +92,7 @@ static inline struct zio_object_list_item *__zio_object_get( { struct zio_object_list_item *list_item; + pr_debug("%s:%d\n", __func__, __LINE__); /* search for default trigger */ list_item = __find_by_name(zobj_list, name); if (!list_item) @@ -256,89 +266,40 @@ void zio_fire_trigger(struct zio_ti *ti) } EXPORT_SYMBOL(zio_fire_trigger); -static int __has_auto_index(char *s) -{ - int i = 0; - for (i = 0; i < ZIO_NAME_LEN-1; i++) { - if (s[i] != '%') - continue; - i++; - if (s[i] == 'd') - return 1; - } - return 0; -} -static int __next_strlen(char *str) -{ - int increment = 0, i; - - for (i = strlen(str)-1; i > 0; i--) { - /* if is an ascii number */ - if (str[i] >= '0' && str[i] <= '9') { - if (str[i] == '9') - continue; - else - break; - } else { - increment++; - break; - } - } - return strlen(str) + increment; -} - /* - * The zio device name must be unique. If it is not unique, a busy error is - * returned. + * zobj_unique_name + * + * Return the number of object registered with the same name within the same + * list + * + * @zobj_list: list to use + * @name: name to check */ -static int zobj_unique_name(struct zio_object_list *zobj_list, char *name) +static int zobj_unique_name(struct zio_object_list *zobj_list, const char *name) { struct zio_object_list_item *cur; - struct zio_obj_head *tmp; - unsigned int counter = 0, again, len; - char name_to_check[ZIO_NAME_LEN]; - int auto_index = __has_auto_index(name); - - pr_debug("%s\n", __func__); + unsigned int conflict = 0; - if (!name) + if (!name) { + pr_err("ZIO: you must spicify a name\n"); return -EINVAL; - - len = strlen(name); - if (!len) + } + if (!strlen(name)) { + pr_err("ZIO: name cannot be an empty string\n"); return -EINVAL; + } + if (strlen(name) > ZIO_OBJ_NAME_LEN) + pr_warning("ZIO: name too long, cut to %d characters\n", + ZIO_OBJ_NAME_LEN); - strncpy(name_to_check, name, ZIO_NAME_LEN); - do { - again = 0; - if (auto_index) { /* TODO when zio become bus, it is useless */ - sprintf(name_to_check, name, counter++); - len = strlen(name_to_check); - } + pr_debug("%s\n", __func__); + list_for_each_entry(cur, &zobj_list->list, list) { + if (strcmp(cur->obj_head->name, name)) + continue; /* no conflict */ + conflict++; + } - list_for_each_entry(cur, &zobj_list->list, list) { - tmp = cur->obj_head; - if (strcmp(tmp->name, name_to_check)) - continue; /* no conflict */ - /* conflict found */ - - /* if not auto-assigned, then error */ - if (!auto_index) { - pr_err("ZIO: name \"%s\" is already taken\n", - name); - return -EBUSY; - } - /* build sequential name */ - if (__next_strlen(name_to_check) > ZIO_NAME_LEN) { - pr_err("ZIO: invalid name \"%s\"\n", name); - return -EINVAL; - } - again = 1; - break; - } - } while (again); - strncpy(name, name_to_check, ZIO_NAME_LEN); - return 0; + return conflict; } static struct zio_attribute *__zattr_clone(const struct zio_attribute *src, @@ -347,7 +308,7 @@ static struct zio_attribute *__zattr_clone(const struct zio_attribute *src, struct zio_attribute *dest = NULL; unsigned int size; - if (!src) + if (!src || !n) return NULL; size = n * sizeof(struct zio_attribute); dest = kmalloc(size, GFP_KERNEL); @@ -994,9 +955,18 @@ static const struct attribute_group *def_bi_groups_ptr[] = { /* Device types */ void zio_device_release(struct device *dev) { + pr_debug("RELEASE %s\n", dev_name(dev)); return; } - +void __zio_generic_device_release(struct device *dev) +{ + pr_debug("RELEASE %s\n", dev_name(dev)); + return; +} +static struct device_type zdev_generic_type = { + .name = "zio generic device type", + .release = __zio_generic_device_release, +}; struct device_type zobj_device_type = { .name = "zio_obj_type", .release = zio_device_release, @@ -1013,6 +983,7 @@ struct device_type bi_device_type = { .groups = def_bi_groups_ptr, }; + /* * Bus */ @@ -1044,62 +1015,159 @@ static ssize_t zio_show_triggers(struct bus_type *bus, char *buf) return len; } - -/* Attributes to change buffer and trigger instance*/ -static DEVICE_ATTR(current_trigger, 0666, zobj_show_cur_trig, - zobj_store_cur_trig); -static DEVICE_ATTR(current_buffer, 0666, zobj_show_cur_zbuf, - zobj_store_cur_zbuf); - -/* Bus definition */ static struct bus_attribute def_bus_attrs[] = { __ATTR(version, 0444, zio_show_version, NULL), __ATTR(available_buffers, 0444, zio_show_buffers, NULL), __ATTR(available_triggers, 0444, zio_show_triggers, NULL), __ATTR_NULL, }; -static struct device_attribute def_device_attrs[] = { - __ATTR(name, 0444, zobj_show_name, NULL), - __ATTR(enable, 0666, zobj_show_enable, zobj_store_enable), - __ATTR_NULL, -}; -static struct attribute *def_device_attrs_ptr[] = { - &def_device_attrs[0].attr, - &def_device_attrs[1].attr, - NULL, -}; -static const struct attribute_group def_device_groups[] = { - { - .attrs = def_device_attrs_ptr, - }, -}; -static const struct attribute_group *def_device_groups_ptr[] = { - &def_device_groups[0], - NULL, -}; -static int zio_match(struct device *dev, struct device_driver *drv) + +static const struct zio_device_id *zio_match_id(const struct zio_device_id *id, + const struct zio_obj_head *head) +{ + while (id->name[0]) { + pr_debug("%s comparing %s == %s \n", __func__, + id->name, head->name); + if (!strcmp(head->name, id->name)) + return id; + ++id; + } + pr_debug("%s:%d fail\n", __func__, __LINE__); + return NULL; +} +const struct zio_device_id *zio_get_device_id(const struct zio_device *zdev) { - pr_debug("%s %s\n", __func__, dev->init_name); + const struct zio_driver *zdrv = to_zio_drv(zdev->head.dev.driver); + + return zio_match_id(zdrv->id_table, &zdev->head); +} +EXPORT_SYMBOL(zio_get_device_id); +static int zio_match_device(struct device *dev, struct device_driver *drv) +{ + const struct zio_driver *zdrv = to_zio_drv(drv); + const struct zio_device_id *id; + + pr_debug("%s:%d\n", __func__, __LINE__); + if (!zdrv->id_table) + return 0; + id = zio_match_id(zdrv->id_table, to_zio_head(dev)); + if(!id) + return 0; + pr_debug("%s:%d\n", __func__, __LINE__); + /* device and driver match */ + if (dev->type == &zdev_generic_type) { + /* Register the real zio device */ + pr_debug("%s:%d\n", __func__, __LINE__); + __zdev_register(to_zio_dev(dev), id); + return 0; + } else if (dev->type == &zobj_device_type) { + pr_debug("%s:%d\n", __func__, __LINE__); + return 1; /* real device always match*/ + } return 0; } struct bus_type zio_bus_type = { .name = "zio", .bus_attrs = def_bus_attrs, - //.dev_attrs = def_device_attrs, - .match = zio_match, + .match = zio_match_device, }; -/* Device types */ -void zio_device_release(struct device *dev) +/* + * zio_drv_probe + */ +static int zio_drv_probe(struct device *dev) { - return; + struct zio_driver *zdrv = to_zio_drv(dev->driver); + struct zio_device *zdev = to_zio_dev(dev); + + pr_debug("%s:%d %p %p\n", __func__, __LINE__, zdrv, zdrv->probe); + if (zdrv->probe) + return zdrv->probe(zdev); + pr_debug("%s:%d\n", __func__, __LINE__); + return 0; } +static int zio_drv_remove(struct device *dev) +{ + struct zio_driver *zdrv = to_zio_drv(dev->driver); + struct zio_device *zdev = to_zio_dev(dev); -struct device_type zobj_device_type = { - .name = "zio object device type", - .release = zio_device_release, - .groups = def_device_groups_ptr, -}; + if (zdrv->remove) + return zdrv->remove(zdev); + return 0; +} + +/* + * _zdev_template_check_and_init + * + * zio_register_driver() invokes this function to perform a preliminar test and + * initialization on templates registered within the driver. + * + * NOTE: this not performa a complete test and initialization, during + * driver->probe ZIO can rise new error and performa other initlization stuff + * + * FIXME try to move all the validations here + */ +static int _zdev_template_check_and_init(struct zio_device *zdev, + const char *name) +{ + struct zio_cset *cset; + int i; + + pr_debug("%s:%d\n", __func__, __LINE__); + if (!zdev->owner) { + /* FIXME I can use driver->owner */ + pr_err("ZIO: device template %s has no owner\n", name); + return -EINVAL; + } + if (!zdev->cset || !zdev->n_cset) { + pr_err("ZIO: no cset in device template %s", name); + return -EINVAL; + } + + for (i = 0; i < zdev->n_cset; ++i) { + cset = &zdev->cset[i]; + if (!cset->n_chan) { + pr_err("ZIO: no channels in %s cset%i\n", name, + cset->index); + return -EINVAL; + } + if (!cset->ssize) { + pr_err("ZIO: ssize can not be 0 in %s cset%i\n", name, + cset->index); + return -EINVAL; + } + } + return 0; +} + +int zio_register_driver(struct zio_driver *zdrv) +{ + int i, err; + + pr_debug("%s:%d\n", __func__, __LINE__); + if (!zdrv->id_table) { + pr_err("ZIO: id_table is mandatory for a zio driver\n"); + return -EINVAL; + } + for (i = 0; zdrv->id_table[i].name[0]; ++i) { + err = _zdev_template_check_and_init(zdrv->id_table[i].template, + zdrv->id_table[i].name); + if (err) + return err; + } + + zdrv->driver.bus = &zio_bus_type; + zdrv->driver.probe = zio_drv_probe; + zdrv->driver.remove = zio_drv_remove; + + return driver_register(&zdrv->driver); +} +EXPORT_SYMBOL(zio_register_driver); +void zio_unregister_driver(struct zio_driver *zdrv) +{ + driver_unregister(&zdrv->driver); +} +EXPORT_SYMBOL(zio_unregister_driver); static int __check_dev_zattr(struct zio_attribute_set *parent, @@ -1222,7 +1290,6 @@ ext: groups[g] = __allocate_group(zattr_set->n_ext_attr); if (IS_ERR(groups[g])) return PTR_ERR(groups[g]); - pr_debug("%s %p", __func__, groups[g]); for (i = 0, a_count = 0; i < zattr_set->n_ext_attr; ++i) { attr = &zattr_set->ext_zattr[i].attr.attr; err = __check_attr(attr, s_op); @@ -1457,11 +1524,19 @@ static uint16_t __get_nbits(struct zio_channel *chan) return 0; } /* - * chan_register registers one channel. It is important to register - * or unregister all the channels of a cset at the same time to prevent - * overlaps in the minors. + * chan_register + * + * @chan: channel to register + * @chan_t: channel template + * + * if the channel template exists, this function copies it and registr the copy + * as child of a cset. It is important to register or unregister all the + * channels of a cset at the same time to prevent overlaps in the minors. + * + * NOTE: The channel template doesn't need a validation because ZIO already + * done it during driver registration */ -static int chan_register(struct zio_channel *chan) +static int chan_register(struct zio_channel *chan, struct zio_channel *chan_t) { struct zio_control *ctrl; struct zio_bi *bi; @@ -1470,89 +1545,90 @@ static int chan_register(struct zio_channel *chan) pr_debug("%s:%d\n", __func__, __LINE__); if (!chan) return -EINVAL; + chan->head.zobj_type = ZCHAN; + + /* Copy from template, initialize and verify zio attributes */ + if (chan_t) { /* ZCSET_CHAN_TEMPLATE is set */ + memcpy(chan, chan_t,sizeof(struct zio_channel)); + if (chan_t->zattr_set.std_zattr) + chan_t->zattr_set.n_std_attr = ZATTR_STD_NUM_ZDEV; + err = __zattr_set_copy(&chan->zattr_set, &chan_t->zattr_set); + if (err) + goto out_zattr_copy; + } + err = zattr_set_create(&chan->head, chan->cset->zdev->s_op); + if (err) + goto out_zattr_create; + /* Check attribute hierarchy */ + err = __check_dev_zattr(&chan->cset->zattr_set, &chan->zattr_set); + if (err) + goto out_zattr_check; + err = __check_dev_zattr(&chan->cset->zdev->zattr_set, &chan->zattr_set); + if (err) + goto out_zattr_check; /* Allocate, initialize and assign a current control for channel */ ctrl = zio_alloc_control(GFP_KERNEL); - if (!ctrl) - return -ENOMEM; - ctrl->cset_i = chan->cset->index; - ctrl->chan_i = chan->index; - strncpy(ctrl->devname, chan->cset->zdev->head.name, ZIO_NAME_LEN); + if (!ctrl) { + err = -ENOMEM; + goto out_zattr_check; + } ctrl->nbits = __get_nbits(chan); if (!ctrl->nbits) { err = -EINVAL; /* message already printed */ - goto out; + goto out_ctrl_bits; } + ctrl->cset_i = chan->cset->index; + ctrl->chan_i = chan->index; + strncpy(ctrl->devname, chan->cset->zdev->head.name, ZIO_NAME_LEN); ctrl->ssize = chan->cset->ssize; /* Trigger instance is already assigned so */ ctrl->nsamples = chan->cset->ti->zattr_set.std_zattr[ZATTR_TRIG_NSAMPLES].value; chan->current_ctrl = ctrl; - /* Initialize head */ + /* Initialize and register channel device */ if (strlen(chan->head.name) == 0) snprintf(chan->head.name, ZIO_NAME_LEN, "chan%i", chan->index); - chan->head.dev.init_name = chan->head.name; + dev_set_name(&chan->head.dev, chan->head.name); chan->head.dev.type = &zobj_device_type; chan->head.dev.parent = &chan->cset->head.dev; - chan->head.zobj_type = ZCHAN; - - /* Create sysfs channel attributes */ - if (chan->zattr_set.std_zattr) - chan->zattr_set.n_std_attr = ZATTR_STD_NUM_ZDEV; - err = zattr_set_create(&chan->head, chan->cset->zdev->s_op); - if (err) - goto out; - /* Register channel */ err = device_register(&chan->head.dev); if (err) - goto out_reg; - /* Check attribute hierarchy */ - err = __check_dev_zattr(&chan->cset->zattr_set, &chan->zattr_set); - if (err) - goto out_remove_sys; - pr_debug("%s:%d\n", __func__, __LINE__); - err = __check_dev_zattr(&chan->cset->zdev->zattr_set, &chan->zattr_set); - if (err) - goto out_remove_sys; + goto out_ctrl_bits; /* Create buffer */ bi = __bi_create_and_init(chan->cset->zbuf, chan); if (IS_ERR(bi)) { err = PTR_ERR(bi); - goto out_remove_sys; + goto out_buf_create; } err = __bi_register(chan->cset->zbuf, chan, bi, "buffer"); if (err) - goto out_bi_destroy; + goto out_buf_reg; /* Assign the buffer instance to this channel */ chan->bi = bi; /* Create channel char devices*/ err = zio_create_chan_devices(chan); if (err) - goto out_create; - /* - * If no name was assigned, ZIO assigns it. channel name is - * set to the kobject name. kobject name has no length limit, - * so the channel name is the first ZIO_NAME_LEN characters of - * kobject name. A duplicate channel name is not a problem - * anyways. - */ - if (!strlen(chan->head.name)) - strncpy(chan->head.name, dev_name(&chan->head.dev), - ZIO_NAME_LEN); + goto out_cdev_create; + return 0; -out_create: +out_cdev_create: __bi_unregister(chan->cset->zbuf, bi); -out_bi_destroy: +out_buf_reg: __bi_destroy(chan->cset->zbuf, bi); -out_remove_sys: +out_buf_create: device_unregister(&chan->head.dev); -out_reg: - zattr_set_remove(&chan->head); -out: +out_ctrl_bits: zio_free_control(ctrl); +out_zattr_check: + zattr_set_remove(&chan->head); +out_zattr_create: + if (chan_t) + __zattr_set_free(&chan->zattr_set); +out_zattr_copy: return err; } @@ -1566,81 +1642,35 @@ static void chan_unregister(struct zio_channel *chan) __bi_unregister(chan->cset->zbuf, chan->bi); __bi_destroy(chan->cset->zbuf, chan->bi); device_unregister(&chan->head.dev); - zattr_set_remove(&chan->head); zio_free_control(chan->current_ctrl); + zattr_set_remove(&chan->head); + if (chan->cset->flags & ZCSET_CHAN_TEMPLATE) + __zattr_set_free(&chan->zattr_set); } /* - * @cset_alloc_chan: low-level drivers can avoid allocating their channels, - * they say how many are there and ZIO allocates them. - * @cset_free_chan: if ZIO allocated channels, then it frees them; otherwise - * it does nothing. + * cset_registration + * + * @cset: cset to register + * @cset_t: cset template + * + * the function copies a cset from a cset template and then it register it + * as child of a zio device. + * + * NOTE: The cset template doesn't need a validation because ZIO already done + * it during driver registration */ -static struct zio_channel *cset_alloc_chan(struct zio_cset *cset) +static int cset_register(struct zio_cset *cset, struct zio_cset *cset_t) { - int i; - - pr_debug("%s:%d\n", __func__, __LINE__); - /*if no static channels, then ZIO must alloc them */ - if (cset->chan) - return cset->chan; - - /* initialize memory to zero to have correct flags and attrs */ - cset->chan = kzalloc(sizeof(struct zio_channel) * cset->n_chan, - GFP_KERNEL); - if (!cset->chan) - return ERR_PTR(-ENOMEM); - cset->flags |= ZCSET_CHAN_ALLOC; - - if (!cset->chan_template) - return cset->chan; - - cset->chan_template->zattr_set.n_std_attr = ZATTR_STD_NUM_ZDEV; - /* apply template on channels */ - for (i = 0; i < cset->n_chan; ++i) { - memcpy(cset->chan + i, cset->chan_template, - sizeof(struct zio_channel)); - __zattr_set_copy(&cset->chan[i].zattr_set, - &cset->chan_template->zattr_set); - } - - return cset->chan; -} -static inline void cset_free_chan(struct zio_cset *cset) -{ - int i; - - pr_debug("%s:%d\n", __func__, __LINE__); - /* Only allocated channels need to be freed */ - if (!(cset->flags & ZCSET_CHAN_ALLOC)) - return; - if(cset->chan_template) - for (i = 0; i < cset->n_chan; ++i) - __zattr_set_free(&cset->chan[i].zattr_set); - kfree(cset->chan); -} - -static int cset_register(struct zio_cset *cset) -{ - int i, j, err = 0; + int i, j, err = 0, size; struct zio_buffer_type *zbuf = NULL; struct zio_trigger_type *trig = NULL; + struct zio_channel *chan_tmp; struct zio_ti *ti = NULL; char *name; - pr_debug("%s\n", __func__); - if (!cset) - return -EINVAL; - - if (!cset->n_chan) { - pr_err("ZIO: no channels in cset%i\n", cset->index); - return -EINVAL; - } - - if (!cset->ssize) { - pr_err("ZIO: ssize can not be 0 in cset%i\n", cset->index); - return -EINVAL; - } + pr_debug("%s:%d\n", __func__, __LINE__); + cset->head.zobj_type = ZCSET; /* Get an available minor base */ err = __zio_minorbase_get(cset); @@ -1648,35 +1678,30 @@ static int cset_register(struct zio_cset *cset) pr_err("ZIO: no minors available\n"); return -EBUSY; } - /* Initialize head */ + + /* Copy from template, initialize and verify zio attributes */ + if (cset_t->zattr_set.std_zattr) + cset_t->zattr_set.n_std_attr = ZATTR_STD_NUM_ZDEV; + err = __zattr_set_copy(&cset->zattr_set, &cset_t->zattr_set); + if (err) + goto out_zattr_copy; + err = zattr_set_create(&cset->head, cset->zdev->s_op); + if (err) + goto out_zattr_create; + err = __check_dev_zattr(&cset->zdev->zattr_set, &cset->zattr_set); + if (err) + goto out_zattr_check; + + /* Initialize and register zio device */ if (strlen(cset->head.name) == 0) snprintf(cset->head.name, ZIO_NAME_LEN, "cset%i", cset->index); dev_set_name(&cset->head.dev, cset->head.name); spin_lock_init(&cset->lock); cset->head.dev.type = &cset_device_type; cset->head.dev.parent = &cset->zdev->head.dev; - cset->head.zobj_type = ZCSET; - /* Create sysfs cset attributes */ - if (cset->zattr_set.std_zattr) - cset->zattr_set.n_std_attr = ZATTR_STD_NUM_ZDEV; - err = zattr_set_create(&cset->head, cset->zdev->s_op); - if (err) - goto out; - /* Register cset */ err = device_register(&cset->head.dev); if (err) - goto out_dev_reg; - /* Check attribute hierarchy */ - err = __check_dev_zattr(&cset->zdev->zattr_set, &cset->zattr_set); - if (err) - goto out_remove_sys; - pr_debug("%s:%d\n", __func__, __LINE__); - cset->chan = cset_alloc_chan(cset); - if (IS_ERR(cset->chan)) { - err = PTR_ERR(cset->chan); - goto out_remove_sys; - } - spin_lock_init(&cset->lock); + goto out_zattr_check; /* * The cset must have a buffer type. If none is associated * to the cset, ZIO selects the preferred or default one. @@ -1695,18 +1720,6 @@ static int cset_register(struct zio_cset *cset) } cset->zbuf = zbuf; } - - /* - * If no name was assigned, ZIO assigns it. cset name is - * set to the kobject name. kobject name has no length limit, - * so the cset name is the first ZIO_NAME_LEN characters of - * kobject name. A duplicate cset name is not a problem - * anyways. - */ - if (!strlen(cset->head.name)) - strncpy(cset->head.name, dev_name(&cset->head.dev), - ZIO_NAME_LEN); - /* * The cset must have a trigger type. If none is associated * to the cset, ZIO selects the default or preferred one. @@ -1737,13 +1750,25 @@ static int cset_register(struct zio_cset *cset) cset->trig = trig; cset->ti = ti; } + /* Allocate a new vector of channel for the new zio cset instance */ + size = sizeof(struct zio_channel) * cset->n_chan; + cset->chan = kzalloc(size, GFP_KERNEL); + if (!cset->chan) + goto out_n_chan; + if (cset->chan_template || cset_t->chan) + cset->flags |= ZCSET_CHAN_TEMPLATE; /* Register all child channels */ for (i = 0; i < cset->n_chan; i++) { cset->chan[i].index = i; cset->chan[i].cset = cset; cset->chan[i].flags |= cset->flags & ZIO_DIR; - err = chan_register(&cset->chan[i]); + chan_tmp = NULL; + if (cset->chan_template) + chan_tmp = cset->chan_template; + else if (cset_t->chan) + chan_tmp = &cset->chan[i]; + err = chan_register(&cset->chan[i], chan_tmp); if (err) goto out_reg; } @@ -1753,7 +1778,6 @@ static int cset_register(struct zio_cset *cset) if (err) goto out_reg; } - spin_lock(&zstat->lock); list_add(&cset->list_cset, &zstat->list_cset); spin_unlock(&zstat->lock); @@ -1763,6 +1787,8 @@ static int cset_register(struct zio_cset *cset) out_reg: for (j = i-1; j >= 0; j--) chan_unregister(&cset->chan[j]); + kfree(cset->chan); +out_n_chan: __ti_unregister(trig, ti); out_tr: __ti_destroy(trig, ti); @@ -1772,12 +1798,12 @@ out_trig: zio_buffer_put(cset->zbuf); cset->zbuf = NULL; out_buf: - cset_free_chan(cset); -out_remove_sys: device_unregister(&cset->head.dev); -out_dev_reg: +out_zattr_check: zattr_set_remove(&cset->head); -out: +out_zattr_create: + __zattr_set_free(&cset->zattr_set); +out_zattr_copy: __zio_minorbase_put(cset); return err; } @@ -1789,28 +1815,30 @@ static void cset_unregister(struct zio_cset *cset) pr_debug("%s:%d\n", __func__, __LINE__); if (!cset) return; - /* Private exit function */ - if (cset->exit) - cset->exit(cset); - /* Remove from csets list*/ spin_lock(&zstat->lock); list_del(&cset->list_cset); spin_unlock(&zstat->lock); + /* Private exit function */ + if (cset->exit) + cset->exit(cset); + /* Unregister all child channels */ + for (i = 0; i < cset->n_chan; i++) + chan_unregister(&cset->chan[i]); + kfree(cset->chan); /* destroy instance and decrement trigger usage */ __ti_unregister(cset->trig, cset->ti); __ti_destroy(cset->trig, cset->ti); zio_trigger_put(cset->trig); cset->trig = NULL; - /* Unregister all child channels */ - for (i = 0; i < cset->n_chan; i++) - chan_unregister(&cset->chan[i]); + /* decrement buffer usage */ zio_buffer_put(cset->zbuf); cset->zbuf = NULL; - cset_free_chan(cset); + device_unregister(&cset->head.dev); zattr_set_remove(&cset->head); + __zattr_set_free(&cset->zattr_set); /* Release a group of minors */ __zio_minorbase_put(cset); } @@ -1821,28 +1849,19 @@ static void cset_unregister(struct zio_cset *cset) */ static int zobj_register(struct zio_object_list *zlist, struct zio_obj_head *head, - struct module *owner, - const char *name) + struct module *owner) { - int err; struct zio_object_list_item *item; - if (strlen(name) > ZIO_OBJ_NAME_LEN) - pr_warning("ZIO: name too long, cut to %d characters\n", - ZIO_OBJ_NAME_LEN); - strncpy(head->name, name, ZIO_OBJ_NAME_LEN); - - /* Name must be unique */ - err = zobj_unique_name(zlist, head->name); - if (err) - goto out; - + if (!owner) { + pr_err("ZIO: missing owner for %s", head->name); + return -EINVAL; + } /* Add to object list */ item = kmalloc(sizeof(struct zio_object_list_item), GFP_KERNEL); - if (!item) { - err = -ENOMEM; - goto out; - } + if (!item) + return -ENOMEM; + item->obj_head = head; item->owner = owner; strncpy(item->name, head->name, ZIO_OBJ_NAME_LEN); @@ -1851,9 +1870,6 @@ static int zobj_register(struct zio_object_list *zlist, list_add(&item->list, &zlist->list); spin_unlock(&zstat->lock); return 0; - -out: - return err; } static void zobj_unregister(struct zio_object_list *zlist, struct zio_obj_head *head) @@ -1875,94 +1891,216 @@ static void zobj_unregister(struct zio_object_list *zlist, } } -/* Register a zio device */ -int zio_register_dev(struct zio_device *zdev, const char *name) +/* + * __zdev_register + * ZIO uses this function to create a new instance of a zio device. The new + * instance is child of a generic zio_device registered before to make the + * bus work correctly. + */ +static int __zdev_register(struct zio_device *parent, + const struct zio_device_id *id) { - int err = 0, i, j; + struct zio_device *zdev, *tmpl; + const char *pname; + int err, size, i; - if (!zdev->owner) { - pr_err("%s: new device has no owner\n", __func__); - return -EINVAL; - } + zdev = kzalloc(sizeof(struct zio_device), GFP_KERNEL); + if (!zdev) + return -ENOMEM; + + tmpl = id->template; - zdev->head.zobj_type = ZDEV; - if (zdev->zattr_set.std_zattr) - zdev->zattr_set.n_std_attr = ZATTR_STD_NUM_ZDEV; spin_lock_init(&zdev->lock); + zdev->private_data = parent->private_data; + zdev->head.zobj_type = ZDEV; + zdev->head.dev.parent = &parent->head.dev; + zdev->head.dev.type = &zobj_device_type; + zdev->head.dev.bus = &zio_bus_type; + /* Name was verified during zio_register_device */ + strncpy(zdev->head.name, parent->head.name, ZIO_OBJ_NAME_LEN); + pname = dev_name(&parent->head.dev) + 6; + dev_set_name(&zdev->head.dev, "zio-%s", pname); + + zdev->owner = parent->owner; /* FIXME which owner? */ + zdev->flags = tmpl->flags; + zdev->s_op = tmpl->s_op; + zdev->preferred_buffer = tmpl->preferred_buffer; + zdev->preferred_trigger = tmpl->preferred_trigger; + zdev->n_cset = tmpl->n_cset; + + + if (tmpl->zattr_set.std_zattr) + tmpl->zattr_set.n_std_attr = ZATTR_STD_NUM_ZDEV; /* Create standard and extended sysfs attribute for device */ + err = __zattr_set_copy(&zdev->zattr_set, &tmpl->zattr_set); + if (err) + goto out_copy; err = zattr_set_create(&zdev->head, zdev->s_op); if (err) - goto out; - /* Register the device */ - err = zobj_register(&zstat->all_devices, &zdev->head, zdev->owner, name); + goto out_create; + + /* Register zio device */ + err = zobj_register(&zstat->all_devices, &zdev->head, zdev->owner); if (err) goto out_reg; - - dev_set_name(&zdev->head.dev, zdev->head.name); - zdev->head.dev.type = &zobj_device_type; - zdev->head.dev.bus = &zio_bus_type; err = device_register(&zdev->head.dev); if (err) goto out_dev; - /* Register all child channel sets */ - for (i = 0; i < zdev->n_cset; i++) { + + + size = sizeof(struct zio_cset) * zdev->n_cset; + zdev->cset = kzalloc(size, GFP_KERNEL); + if (!zdev->cset) { + err = -ENOMEM; + goto out_alloc_cset; + } + memcpy(zdev->cset, tmpl->cset, size); + /* Register all csets */ + for (i = 0; i < zdev->n_cset; ++i) { zdev->cset[i].index = i; zdev->cset[i].zdev = zdev; - err = cset_register(&zdev->cset[i]); + err = cset_register(&zdev->cset[i], &tmpl->cset[i]); if (err) goto out_cset; } - pr_debug("%s:%d\n", __func__, __LINE__); /* Fix extended attribute index */ err = __zattr_dev_init_ctrl(zdev); if (err) goto out_cset; - return 0; + return 0; out_cset: - for (j = i-1; j >= 0; j--) - cset_unregister(zdev->cset + j); + while (--i >= 0) + cset_unregister(&zdev->cset[i]); + kfree(zdev->cset); +out_alloc_cset: + device_unregister(&zdev->head.dev); out_dev: zobj_unregister(&zstat->all_devices, &zdev->head); out_reg: zattr_set_remove(&zdev->head); -out: +out_create: + __zattr_set_free(&zdev->zattr_set); +out_copy: + kfree(zdev); return err; } -EXPORT_SYMBOL(zio_register_dev); - -void zio_unregister_dev(struct zio_device *zdev) +static void __zdev_unregister(struct zio_device *zdev) { int i; - pr_debug("%s:%d\n", __func__, __LINE__); - if (!zdev) - return; - - /* Unregister all child channel sets */ - for (i = 0; i < zdev->n_cset; i++) + for (i = 0; i < zdev->n_cset; ++i) cset_unregister(&zdev->cset[i]); + kfree(zdev->cset); device_unregister(&zdev->head.dev); zobj_unregister(&zstat->all_devices, &zdev->head); zattr_set_remove(&zdev->head); + __zattr_set_free(&zdev->zattr_set); + kfree(zdev); } -EXPORT_SYMBOL(zio_unregister_dev); + +struct zio_device *zio_allocate_device(void) +{ + struct zio_device *zdev; + + /* Allocate a new zio device to use as instance of zdev_t */ + zdev = kzalloc(sizeof(struct zio_device), GFP_KERNEL); + if (!zdev) + return ERR_PTR(-ENOMEM); + /* Set this device as generic zio device */ + zdev->head.dev.type = &zdev_generic_type; + zdev->head.dev.bus = &zio_bus_type; + + return zdev; +} +EXPORT_SYMBOL(zio_allocate_device); +void zio_free_device(struct zio_device *zdev) +{ + kfree(zdev); +} +EXPORT_SYMBOL(zio_free_device); +/* + * zio_register_device + * + * Register an empty zio_device, when it match with a driver it will be + * filled with driver information. Registration sets the correct name to + * the device and it adds the device to the device list; then it registers + * the device. + * + * @zdev: an empty zio_device allocated with zio_allocate_device + * @name: name of the device to register + * @dev_id: device identifier, if 0 ZIO use an autoindex + */ +int zio_register_device(struct zio_device *zdev, const char *name, + uint32_t dev_id) +{ + int n_conflict; + + pr_debug("%s:%d\n", __func__, __LINE__); + /* Verify if it is a valid name */ + n_conflict = zobj_unique_name(&zstat->all_devices, name); + if (n_conflict < 0) + return n_conflict; + strncpy(zdev->head.name, name, ZIO_OBJ_NAME_LEN); + if (dev_id == 0) + dev_set_name(&zdev->head.dev, "hwdev-%s-%04x", + zdev->head.name, n_conflict); + else + dev_set_name(&zdev->head.dev, "hwdev-%s-%04x", + zdev->head.name, dev_id); + + return device_register(&zdev->head.dev); +} +EXPORT_SYMBOL(zio_register_device); + +/* + * __zdev_match_child + * ZIO uses this function only to find the real zio_device, which is child of + * the generic zio_device + */ +static int __zdev_match_child(struct device *dev, void *data) +{ + pr_debug("%s:%d\n", __func__, __LINE__); + if (dev->type == &zobj_device_type) + return 1; + return 0; +} +void zio_unregister_device(struct zio_device *zdev) +{ + struct device *dev; + + /* + * the child of a generic zio_device could be only a real zio_device. + * If it exists, unregister it + */ + dev = device_find_child(&zdev->head.dev, NULL, __zdev_match_child); + if (dev) + __zdev_unregister(to_zio_dev(dev)); + + pr_info("ZIO: device %s removed\n", dev_name(&zdev->head.dev)); + device_unregister(&zdev->head.dev); +} +EXPORT_SYMBOL(zio_unregister_device); /* Register a buffer into the available buffer list */ int zio_register_buf(struct zio_buffer_type *zbuf, const char *name) { int err; pr_debug("%s:%d\n", __func__, __LINE__); - if (!zbuf || !name) + if (!zbuf) return -EINVAL; + /* Verify if it is a valid name */ + err = zobj_unique_name(&zstat->all_buffer_types, name); + if (err) + return err < 0 ? err: -EBUSY; + strncpy(zbuf->head.name, name, ZIO_OBJ_NAME_LEN); err = zio_init_buffer_fops(zbuf); if (err < 0) return err; zbuf->head.zobj_type = ZBUF; - err = zobj_register(&zstat->all_buffer_types, &zbuf->head, - zbuf->owner, name); + err = zobj_register(&zstat->all_buffer_types, &zbuf->head, zbuf->owner); if (err) { zio_fini_buffer_fops(zbuf); return err; @@ -1990,16 +2128,19 @@ int zio_register_trig(struct zio_trigger_type *trig, const char *name) { int err; - if (!trig || !name) + if (!trig) return -EINVAL; - if (!trig->zattr_set.std_zattr) goto err_nsamp; if (!trig->zattr_set.std_zattr[ZATTR_TRIG_NSAMPLES].attr.attr.mode) goto err_nsamp; + /* Verify if it is a valid name */ + err = zobj_unique_name(&zstat->all_buffer_types, name); + if (err) + return err < 0 ? err: -EBUSY; + strncpy(trig->head.name, name, ZIO_OBJ_NAME_LEN); trig->head.zobj_type = ZTRIG; - err = zobj_register(&zstat->all_trigger_types, &trig->head, - trig->owner, name); + err = zobj_register(&zstat->all_trigger_types, &trig->head, trig->owner); if (err) return err; if (trig->zattr_set.std_zattr)