[RFC PATCH 21/30] staging: comedi: dt9812: convert to use comedi (*auto_attach)

H Hartley Sweeten hsweeten at visionengravers.com
Fri May 3 20:51:05 UTC 2013


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 at visionengravers.com>
Cc: Ian Abbott <abbotti at mev.co.uk>
Cc: Greg Kroah-Hartman <gregkh at linuxfonudation.org>
---
 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 cf8f10f..1075b04 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 rt9812_reset_device(struct usb_interface *intf,
-			       struct usb_dt9812 *devpriv)
+static int rt9812_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 rt9812_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 rt9812_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 = rt9812_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 = rt9812_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 at control.lth.se>");
 MODULE_DESCRIPTION("Comedi DT9812 driver");
-- 
1.8.1.4




More information about the devel mailing list