Converting this driver to use the comedi (*auto_attach) mechanism allows pushing the usb (*probe) into the comedi (*auto_attach) and the usb (disconnect) into the comedi (*detach). This removes the disconnect between the usb driver and the comedi driver. Now when the comedi driver is attached it will always have a usb device associated with it. This removes the 16 usb device limitation and allows bringing all the private data into a single struct that can be kzalloc'ed when the comedi driver is (*auto_attached). It also allows removing the the sanity checks that make sure a usb device is connected to the comedi device in the helper functions. For aesthetic reasons, add some whitespace to the subdevice init. Also, fix the analog out subdevice. There are 2 analog output channels available on the usb device. Signed-off-by: H Hartley Sweeten <hsweeten@xxxxxxxxxxxxxxxxxxx> Cc: Ian Abbott <abbotti@xxxxxxxxx> Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/staging/comedi/drivers/dt9812.c | 458 ++++++++++++-------------------- 1 file changed, 173 insertions(+), 285 deletions(-) diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index 57bdb06..0efff28 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -45,7 +45,6 @@ for my needs. #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/kref.h> #include <linux/uaccess.h> #include <linux/usb.h> @@ -258,55 +257,26 @@ struct dt9812_usb_cmd { #endif }; -#define DT9812_NUM_SLOTS 16 - -static DEFINE_SEMAPHORE(dt9812_mutex); - -struct usb_dt9812 { - struct slot_dt9812 *slot; - struct usb_device *udev; - u16 vendor; - u16 product; - u16 device; - u32 serial; +struct dt9812_private { + struct semaphore sem; struct { __u8 addr; size_t size; } cmd_wr, cmd_rd; - struct kref kref; -}; - -struct dt9812_private { - struct semaphore sem; - struct slot_dt9812 *slot; + u32 serial; + u16 vendor; + u16 product; + u16 device; u16 ao_shadow[2]; u8 do_shadow; }; -struct slot_dt9812 { - struct usb_dt9812 *usb; - struct dt9812_private *devpriv; -}; - -static struct slot_dt9812 dt9812[DT9812_NUM_SLOTS]; - -static inline struct usb_dt9812 *to_dt9812_dev(struct kref *d) -{ - return container_of(d, struct usb_dt9812, kref); -} - -static void dt9812_delete(struct kref *kref) -{ - struct usb_dt9812 *dev = to_dt9812_dev(kref); - - usb_put_dev(dev->udev); - kfree(dev); -} - -static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf, - size_t buf_size) +static int dt9812_read_info(struct comedi_device *dev, + int offset, void *buf, size_t buf_size) { - struct usb_device *usb = dev->udev; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = interface_to_usbdev(intf); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; int count, ret; @@ -316,19 +286,22 @@ static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf, cmd.u.flash_data_info.numbytes = cpu_to_le16(buf_size); /* DT9812 only responds to 32 byte writes!! */ - ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, dev->cmd_wr.addr), + ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), &cmd, 32, &count, HZ * 1); if (ret) return ret; - return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, dev->cmd_rd.addr), + return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr), buf, buf_size, &count, HZ * 1); } -static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, - u8 *address, u8 *value) +static int dt9812_read_multiple_registers(struct comedi_device *dev, + int reg_count, u8 *address, + u8 *value) { - struct usb_device *usb = dev->udev; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = interface_to_usbdev(intf); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; int i, count, ret; @@ -338,20 +311,22 @@ static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, cmd.u.read_multi_info.address[i] = address[i]; /* DT9812 only responds to 32 byte writes!! */ - ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, dev->cmd_wr.addr), + ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), &cmd, 32, &count, HZ * 1); if (ret) return ret; - return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, dev->cmd_rd.addr), + return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr), value, reg_count, &count, HZ * 1); } -static int dt9812_write_multiple_registers(struct usb_dt9812 *dev, +static int dt9812_write_multiple_registers(struct comedi_device *dev, int reg_count, u8 *address, u8 *value) { - struct usb_device *usb = dev->udev; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = interface_to_usbdev(intf); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; int i, count; @@ -363,14 +338,17 @@ static int dt9812_write_multiple_registers(struct usb_dt9812 *dev, } /* DT9812 only responds to 32 byte writes!! */ - return usb_bulk_msg(usb, usb_sndbulkpipe(usb, dev->cmd_wr.addr), + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), &cmd, 32, &count, HZ * 1); } -static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_count, +static int dt9812_rmw_multiple_registers(struct comedi_device *dev, + int reg_count, struct dt9812_rmw_byte *rmw) { - struct usb_device *usb = dev->udev; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = interface_to_usbdev(intf); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; int i, count; @@ -380,30 +358,26 @@ static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_count, cmd.u.rmw_multi_info.rmw[i] = rmw[i]; /* DT9812 only responds to 32 byte writes!! */ - return usb_bulk_msg(usb, usb_sndbulkpipe(usb, dev->cmd_wr.addr), + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), &cmd, 32, &count, HZ * 1); } static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) { struct dt9812_private *devpriv = dev->private; - struct slot_dt9812 *slot = devpriv->slot; - int ret = -ENODEV; + u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 }; + u8 value[2]; + int ret; down(&devpriv->sem); - if (slot->usb) { - u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 }; - u8 value[2]; - - ret = dt9812_read_multiple_registers(slot->usb, 2, reg, value); - if (ret == 0) { - /* - * bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital - * input port bit 3 in F020_SFR_P1 is bit 7 in the - * digital input port - */ - *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4); - } + ret = dt9812_read_multiple_registers(dev, 2, reg, value); + if (ret == 0) { + /* + * bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital + * input port bit 3 in F020_SFR_P1 is bit 7 in the + * digital input port + */ + *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4); } up(&devpriv->sem); @@ -413,17 +387,13 @@ static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) static int dt9812_digital_out(struct comedi_device *dev, u8 bits) { struct dt9812_private *devpriv = dev->private; - struct slot_dt9812 *slot = devpriv->slot; - int ret = -ENODEV; + u8 reg[1] = { F020_SFR_P2 }; + u8 value[1] = { bits }; + int ret; down(&devpriv->sem); - if (slot->usb) { - u8 reg[1] = { F020_SFR_P2 }; - u8 value[1] = { bits }; - - ret = dt9812_write_multiple_registers(slot->usb, 1, reg, value); - devpriv->do_shadow = bits; - } + ret = dt9812_write_multiple_registers(dev, 1, reg, value); + devpriv->do_shadow = bits; up(&devpriv->sem); return ret; @@ -444,10 +414,8 @@ static void dt9812_configure_mux(struct comedi_device *dev, struct dt9812_rmw_byte *rmw, int channel) { struct dt9812_private *devpriv = dev->private; - struct slot_dt9812 *slot = devpriv->slot; - struct usb_dt9812 *usb = slot->usb; - if (usb->device == DT9812_DEVID_DT9812_10) { + if (devpriv->device == DT9812_DEVID_DT9812_10) { /* In the DT9812/10V MUX is selected by P1.5-7 */ rmw->address = F020_SFR_P1; rmw->and_mask = 0xe0; @@ -465,11 +433,9 @@ static void dt9812_configure_gain(struct comedi_device *dev, enum dt9812_gain gain) { struct dt9812_private *devpriv = dev->private; - struct slot_dt9812 *slot = devpriv->slot; - struct usb_dt9812 *usb = slot->usb; /* In the DT9812/10V, there is an external gain of 0.5 */ - if (usb->device == DT9812_DEVID_DT9812_10) + if (devpriv->device == DT9812_DEVID_DT9812_10) gain <<= 1; rmw->address = F020_SFR_ADC0CF; @@ -516,7 +482,6 @@ static int dt9812_analog_in(struct comedi_device *dev, int channel, u16 *value, enum dt9812_gain gain) { struct dt9812_private *devpriv = dev->private; - struct slot_dt9812 *slot = devpriv->slot; struct dt9812_rmw_byte rmw[3]; u8 reg[3] = { F020_SFR_ADC0CN, @@ -524,11 +489,9 @@ static int dt9812_analog_in(struct comedi_device *dev, F020_SFR_ADC0L }; u8 val[3]; - int ret = -ENODEV; + int ret; down(&devpriv->sem); - if (!slot->usb) - goto exit; /* 1 select the gain */ dt9812_configure_gain(dev, &rmw[0], gain); @@ -541,12 +504,12 @@ static int dt9812_analog_in(struct comedi_device *dev, rmw[2].and_mask = 0xff; rmw[2].or_value = F020_MASK_ADC0CN_AD0EN | F020_MASK_ADC0CN_AD0BUSY; - ret = dt9812_rmw_multiple_registers(slot->usb, 3, rmw); + ret = dt9812_rmw_multiple_registers(dev, 3, rmw); if (ret) goto exit; /* read the status and ADC */ - ret = dt9812_read_multiple_registers(slot->usb, 3, reg, val); + ret = dt9812_read_multiple_registers(dev, 3, reg, val); if (ret) goto exit; @@ -561,7 +524,7 @@ static int dt9812_analog_in(struct comedi_device *dev, */ if ((val[0] & (F020_MASK_ADC0CN_AD0INT | F020_MASK_ADC0CN_AD0BUSY)) == F020_MASK_ADC0CN_AD0INT) { - switch (slot->usb->device) { + switch (devpriv->device) { case DT9812_DEVID_DT9812_10: /* * For DT9812-10V the personality module set the @@ -597,53 +560,51 @@ static int dt9812_analog_out_shadow(struct comedi_device *dev, static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) { struct dt9812_private *devpriv = dev->private; - struct slot_dt9812 *slot = devpriv->slot; - int ret = -ENODEV; + struct dt9812_rmw_byte rmw[3]; + int ret; down(&devpriv->sem); - if (slot->usb) { - struct dt9812_rmw_byte rmw[3]; - switch (channel) { - case 0: - /* 1. Set DAC mode */ - rmw[0].address = F020_SFR_DAC0CN; - rmw[0].and_mask = 0xff; - rmw[0].or_value = F020_MASK_DACxCN_DACxEN; - - /* 2 load low byte of DAC value first */ - rmw[1].address = F020_SFR_DAC0L; - rmw[1].and_mask = 0xff; - rmw[1].or_value = value & 0xff; - - /* 3 load high byte of DAC value next to latch the - 12-bit value */ - rmw[2].address = F020_SFR_DAC0H; - rmw[2].and_mask = 0xff; - rmw[2].or_value = (value >> 8) & 0xf; - break; + switch (channel) { + case 0: + /* 1. Set DAC mode */ + rmw[0].address = F020_SFR_DAC0CN; + rmw[0].and_mask = 0xff; + rmw[0].or_value = F020_MASK_DACxCN_DACxEN; + + /* 2 load low byte of DAC value first */ + rmw[1].address = F020_SFR_DAC0L; + rmw[1].and_mask = 0xff; + rmw[1].or_value = value & 0xff; + + /* 3 load high byte of DAC value next to latch the + 12-bit value */ + rmw[2].address = F020_SFR_DAC0H; + rmw[2].and_mask = 0xff; + rmw[2].or_value = (value >> 8) & 0xf; + break; - case 1: - /* 1. Set DAC mode */ - rmw[0].address = F020_SFR_DAC1CN; - rmw[0].and_mask = 0xff; - rmw[0].or_value = F020_MASK_DACxCN_DACxEN; - - /* 2 load low byte of DAC value first */ - rmw[1].address = F020_SFR_DAC1L; - rmw[1].and_mask = 0xff; - rmw[1].or_value = value & 0xff; - - /* 3 load high byte of DAC value next to latch the - 12-bit value */ - rmw[2].address = F020_SFR_DAC1H; - rmw[2].and_mask = 0xff; - rmw[2].or_value = (value >> 8) & 0xf; - break; - } - ret = dt9812_rmw_multiple_registers(slot->usb, 3, rmw); - devpriv->ao_shadow[channel] = value; + case 1: + /* 1. Set DAC mode */ + rmw[0].address = F020_SFR_DAC1CN; + rmw[0].and_mask = 0xff; + rmw[0].or_value = F020_MASK_DACxCN_DACxEN; + + /* 2 load low byte of DAC value first */ + rmw[1].address = F020_SFR_DAC1L; + rmw[1].and_mask = 0xff; + rmw[1].or_value = value & 0xff; + + /* 3 load high byte of DAC value next to latch the + 12-bit value */ + rmw[2].address = F020_SFR_DAC1H; + rmw[2].and_mask = 0xff; + rmw[2].or_value = (value >> 8) & 0xf; + break; } + ret = dt9812_rmw_multiple_registers(dev, 3, rmw); + devpriv->ao_shadow[channel] = value; + up(&devpriv->sem); return ret; @@ -727,10 +688,11 @@ static int dt9812_ao_winsn(struct comedi_device *dev, return n; } -static int dt9812_find_endpoints(struct usb_interface *intf, - struct usb_dt9812 *devpriv) +static int dt9812_find_endpoints(struct comedi_device *dev) { + struct usb_interface *intf = comedi_to_usb_interface(dev); struct usb_host_interface *host = intf->cur_altsetting; + struct dt9812_private *devpriv = dev->private; struct usb_endpoint_descriptor *ep; int i; @@ -774,24 +736,26 @@ static int dt9812_find_endpoints(struct usb_interface *intf, return 0; } -static int dt9812_reset_device(struct usb_interface *intf, - struct usb_dt9812 *devpriv) +static int dt9812_reset_device(struct comedi_device *dev) { + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = interface_to_usbdev(intf); + struct dt9812_private *devpriv = dev->private; int ret; int i; u32 tmp32; u16 tmp16; u8 tmp8; - ret = dt9812_read_info(devpriv, 0, &tmp8, sizeof(tmp8)); + ret = dt9812_read_info(dev, 0, &tmp8, sizeof(tmp8)); if (ret) { /* * Seems like a configuration reset is necessary if driver is * reloaded while device is attached */ - usb_reset_configuration(devpriv->udev); + usb_reset_configuration(usb); for (i = 0; i < 10; i++) { - ret = dt9812_read_info(devpriv, 1, &tmp8, sizeof(tmp8)); + ret = dt9812_read_info(dev, 1, &tmp8, sizeof(tmp8)); if (ret == 0) break; } @@ -801,28 +765,28 @@ static int dt9812_reset_device(struct usb_interface *intf, } } - ret = dt9812_read_info(devpriv, 1, &tmp16, sizeof(tmp16)); + ret = dt9812_read_info(dev, 1, &tmp16, sizeof(tmp16)); if (ret) { dev_err(&intf->dev, "failed to read vendor id\n"); return ret; } devpriv->vendor = le16_to_cpu(tmp16); - ret = dt9812_read_info(devpriv, 3, &tmp16, sizeof(tmp16)); + ret = dt9812_read_info(dev, 3, &tmp16, sizeof(tmp16)); if (ret) { dev_err(&intf->dev, "failed to read product id\n"); return ret; } devpriv->product = le16_to_cpu(tmp16); - ret = dt9812_read_info(devpriv, 5, &tmp16, sizeof(tmp16)); + ret = dt9812_read_info(dev, 5, &tmp16, sizeof(tmp16)); if (ret) { dev_err(&intf->dev, "failed to read device id\n"); return ret; } devpriv->device = le16_to_cpu(tmp16); - ret = dt9812_read_info(devpriv, 7, &tmp32, sizeof(tmp32)); + ret = dt9812_read_info(dev, 7, &tmp32, sizeof(tmp32)); if (ret) { dev_err(&intf->dev, "failed to read serial number\n"); return ret; @@ -837,11 +801,11 @@ static int dt9812_reset_device(struct usb_interface *intf, return 0; } -static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int dt9812_auto_attach(struct comedi_device *dev, + unsigned long context) { - struct slot_dt9812 *slot = NULL; + struct usb_interface *intf = comedi_to_usb_interface(dev); struct dt9812_private *devpriv; - int i; struct comedi_subdevice *s; bool is_unipolar; int ret; @@ -850,186 +814,110 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (!devpriv) return -ENOMEM; dev->private = devpriv; - sema_init(&devpriv->sem, 1); - down(&dt9812_mutex); + sema_init(&devpriv->sem, 1); + usb_set_intfdata(intf, devpriv); - /* - * Find the first unused slot for the comedi device - * that has a usb device connected. - */ - for (i = 0; i < DT9812_NUM_SLOTS; i++) { - if (dt9812[i].usb && !dt9812[i].devpriv) { - slot = &dt9812[i]; - break; - } - } - if (!slot) { - up(&dt9812_mutex); - return -ENODEV; - } + ret = dt9812_find_endpoints(dev); + if (ret) + return ret; - slot->devpriv = devpriv; - devpriv->slot = slot; - is_unipolar = (slot->usb->device == DT9812_DEVID_DT9812_2PT5); + ret = dt9812_reset_device(dev); + if (ret) + return ret; - up(&dt9812_mutex); + is_unipolar = (devpriv->device == DT9812_DEVID_DT9812_2PT5); ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - /* digital input subdevice */ + /* Digital Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_read = &dt9812_di_rinsn; - - /* digital output subdevice */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_read = dt9812_di_rinsn; + + /* Digital Output subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_write = &dt9812_do_winsn; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_write = dt9812_do_winsn; devpriv->do_shadow = 0; - /* analog input subdevice */ + /* Analog Input subdevice */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 8; - s->maxdata = 4095; - s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; - s->insn_read = &dt9812_ai_rinsn; - - /* analog output subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8; + s->maxdata = 0x0fff; + s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; + s->insn_read = dt9812_ai_rinsn; + + /* Analog Output subdevice */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 0; - s->maxdata = 4095; - s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; - s->insn_write = &dt9812_ao_winsn; - s->insn_read = &dt9812_ao_rinsn; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; + s->insn_write = dt9812_ao_winsn; + s->insn_read = dt9812_ao_rinsn; devpriv->ao_shadow[0] = is_unipolar ? 0x0000 : 0x0800; devpriv->ao_shadow[1] = is_unipolar ? 0x0000 : 0x0800; - dev_info(dev->class_dev, "successfully attached to dt9812.\n"); - return 0; } static void dt9812_detach(struct comedi_device *dev) { + struct usb_interface *intf = comedi_to_usb_interface(dev); struct dt9812_private *devpriv = dev->private; - if (devpriv && devpriv->slot) - devpriv->slot = NULL; -} - -static struct comedi_driver dt9812_comedi_driver = { - .module = THIS_MODULE, - .driver_name = "dt9812", - .attach = dt9812_attach, - .detach = dt9812_detach, -}; - -static int dt9812_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct slot_dt9812 *slot = NULL; - struct usb_dt9812 *dev = NULL; - int retval = -ENOMEM; - int i; - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) - goto error; - - kref_init(&dev->kref); - - down(&dt9812_mutex); - - /* Find an empty slot for the usb device */ - for (i = 0; i < DT9812_NUM_SLOTS; i++) { - if (!dt9812[i].usb) { - slot = &dt9812[i]; - break; - } - } - if (!slot) { - up(&dt9812_mutex); - retval = -ENODEV; - goto error; - } - - slot->usb = dev; - dev->slot = slot; - - up(&dt9812_mutex); - - dev->udev = usb_get_dev(interface_to_usbdev(intf)); - - retval = dt9812_find_endpoints(intf, dev); - if (retval) - goto error; - - retval = dt9812_reset_device(intf, dev); - if (retval) - goto error; + if (!devpriv) + return; - /* save our data pointer in this interface device */ - usb_set_intfdata(intf, dev); + down(&devpriv->sem); - return 0; + usb_set_intfdata(intf, NULL); -error: - if (dev) - kref_put(&dev->kref, dt9812_delete); - return retval; + up(&devpriv->sem); } -static void dt9812_disconnect(struct usb_interface *intf) -{ - struct usb_dt9812 *dev; - int minor = intf->minor; - - down(&dt9812_mutex); - dev = usb_get_intfdata(intf); - if (dev->slot) { - dev->slot->usb = NULL; - dev->slot = NULL; - } - usb_set_intfdata(intf, NULL); - up(&dt9812_mutex); - - /* queue final destruction */ - kref_put(&dev->kref, dt9812_delete); +static struct comedi_driver dt9812_driver = { + .driver_name = "dt9812", + .module = THIS_MODULE, + .auto_attach = dt9812_auto_attach, + .detach = dt9812_detach, +}; - dev_info(&intf->dev, "USB Dt9812 #%d now disconnected\n", minor); +static int dt9812_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return comedi_usb_auto_config(intf, &dt9812_driver, id->driver_info); } -static const struct usb_device_id dt9812_table[] = { +static const struct usb_device_id dt9812_usb_table[] = { { USB_DEVICE(0x0867, 0x9812) }, { } }; -MODULE_DEVICE_TABLE(usb, dt9812_table); +MODULE_DEVICE_TABLE(usb, dt9812_usb_table); static struct usb_driver dt9812_usb_driver = { .name = "dt9812", - .id_table = dt9812_table, - .probe = dt9812_probe, - .disconnect = dt9812_disconnect, + .id_table = dt9812_usb_table, + .probe = dt9812_usb_probe, + .disconnect = comedi_usb_auto_unconfig, }; -module_comedi_usb_driver(dt9812_comedi_driver, dt9812_usb_driver); +module_comedi_usb_driver(dt9812_driver, dt9812_usb_driver); MODULE_AUTHOR("Anders Blomdell <anders.blomdell@xxxxxxxxxxxxxx>"); MODULE_DESCRIPTION("Comedi DT9812 driver"); -- 1.8.1.4 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/devel