Commit b78750c1 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

staging: comedi: dt9812: convert to use comedi (*auto_attach)

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: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8db1eba1
...@@ -45,7 +45,6 @@ for my needs. ...@@ -45,7 +45,6 @@ for my needs.
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/usb.h> #include <linux/usb.h>
...@@ -258,55 +257,26 @@ struct dt9812_usb_cmd { ...@@ -258,55 +257,26 @@ struct dt9812_usb_cmd {
#endif #endif
}; };
#define DT9812_NUM_SLOTS 16 struct dt9812_private {
struct semaphore sem;
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 { struct {
__u8 addr; __u8 addr;
size_t size; size_t size;
} cmd_wr, cmd_rd; } cmd_wr, cmd_rd;
struct kref kref; u32 serial;
}; u16 vendor;
u16 product;
struct dt9812_private { u16 device;
struct semaphore sem;
struct slot_dt9812 *slot;
u16 ao_shadow[2]; u16 ao_shadow[2];
u8 do_shadow; u8 do_shadow;
}; };
struct slot_dt9812 { static int dt9812_read_info(struct comedi_device *dev,
struct usb_dt9812 *usb; int offset, void *buf, size_t buf_size)
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)
{ {
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; struct dt9812_usb_cmd cmd;
int count, ret; int count, ret;
...@@ -316,19 +286,22 @@ static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf, ...@@ -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); cmd.u.flash_data_info.numbytes = cpu_to_le16(buf_size);
/* DT9812 only responds to 32 byte writes!! */ /* 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); &cmd, 32, &count, HZ * 1);
if (ret) if (ret)
return 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); buf, buf_size, &count, HZ * 1);
} }
static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, static int dt9812_read_multiple_registers(struct comedi_device *dev,
u8 *address, u8 *value) 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; struct dt9812_usb_cmd cmd;
int i, count, ret; int i, count, ret;
...@@ -338,20 +311,22 @@ static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, ...@@ -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]; cmd.u.read_multi_info.address[i] = address[i];
/* DT9812 only responds to 32 byte writes!! */ /* 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); &cmd, 32, &count, HZ * 1);
if (ret) if (ret)
return 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); 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, int reg_count, u8 *address,
u8 *value) 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; struct dt9812_usb_cmd cmd;
int i, count; int i, count;
...@@ -363,14 +338,17 @@ static int dt9812_write_multiple_registers(struct usb_dt9812 *dev, ...@@ -363,14 +338,17 @@ static int dt9812_write_multiple_registers(struct usb_dt9812 *dev,
} }
/* DT9812 only responds to 32 byte writes!! */ /* 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); &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 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; struct dt9812_usb_cmd cmd;
int i, count; int i, count;
...@@ -380,30 +358,26 @@ static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_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]; cmd.u.rmw_multi_info.rmw[i] = rmw[i];
/* DT9812 only responds to 32 byte writes!! */ /* 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); &cmd, 32, &count, HZ * 1);
} }
static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) static int dt9812_digital_in(struct comedi_device *dev, u8 *bits)
{ {
struct dt9812_private *devpriv = dev->private; struct dt9812_private *devpriv = dev->private;
struct slot_dt9812 *slot = devpriv->slot; u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 };
int ret = -ENODEV; u8 value[2];
int ret;
down(&devpriv->sem); down(&devpriv->sem);
if (slot->usb) { ret = dt9812_read_multiple_registers(dev, 2, reg, value);
u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 }; if (ret == 0) {
u8 value[2]; /*
* bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital
ret = dt9812_read_multiple_registers(slot->usb, 2, reg, value); * input port bit 3 in F020_SFR_P1 is bit 7 in the
if (ret == 0) { * digital input port
/* */
* bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4);
* 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); up(&devpriv->sem);
...@@ -413,17 +387,13 @@ static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) ...@@ -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) static int dt9812_digital_out(struct comedi_device *dev, u8 bits)
{ {
struct dt9812_private *devpriv = dev->private; struct dt9812_private *devpriv = dev->private;
struct slot_dt9812 *slot = devpriv->slot; u8 reg[1] = { F020_SFR_P2 };
int ret = -ENODEV; u8 value[1] = { bits };
int ret;
down(&devpriv->sem); down(&devpriv->sem);
if (slot->usb) { ret = dt9812_write_multiple_registers(dev, 1, reg, value);
u8 reg[1] = { F020_SFR_P2 }; devpriv->do_shadow = bits;
u8 value[1] = { bits };
ret = dt9812_write_multiple_registers(slot->usb, 1, reg, value);
devpriv->do_shadow = bits;
}
up(&devpriv->sem); up(&devpriv->sem);
return ret; return ret;
...@@ -444,10 +414,8 @@ static void dt9812_configure_mux(struct comedi_device *dev, ...@@ -444,10 +414,8 @@ static void dt9812_configure_mux(struct comedi_device *dev,
struct dt9812_rmw_byte *rmw, int channel) struct dt9812_rmw_byte *rmw, int channel)
{ {
struct dt9812_private *devpriv = dev->private; 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 */ /* In the DT9812/10V MUX is selected by P1.5-7 */
rmw->address = F020_SFR_P1; rmw->address = F020_SFR_P1;
rmw->and_mask = 0xe0; rmw->and_mask = 0xe0;
...@@ -465,11 +433,9 @@ static void dt9812_configure_gain(struct comedi_device *dev, ...@@ -465,11 +433,9 @@ static void dt9812_configure_gain(struct comedi_device *dev,
enum dt9812_gain gain) enum dt9812_gain gain)
{ {
struct dt9812_private *devpriv = dev->private; 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 */ /* 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; gain <<= 1;
rmw->address = F020_SFR_ADC0CF; rmw->address = F020_SFR_ADC0CF;
...@@ -516,7 +482,6 @@ static int dt9812_analog_in(struct comedi_device *dev, ...@@ -516,7 +482,6 @@ static int dt9812_analog_in(struct comedi_device *dev,
int channel, u16 *value, enum dt9812_gain gain) int channel, u16 *value, enum dt9812_gain gain)
{ {
struct dt9812_private *devpriv = dev->private; struct dt9812_private *devpriv = dev->private;
struct slot_dt9812 *slot = devpriv->slot;
struct dt9812_rmw_byte rmw[3]; struct dt9812_rmw_byte rmw[3];
u8 reg[3] = { u8 reg[3] = {
F020_SFR_ADC0CN, F020_SFR_ADC0CN,
...@@ -524,11 +489,9 @@ static int dt9812_analog_in(struct comedi_device *dev, ...@@ -524,11 +489,9 @@ static int dt9812_analog_in(struct comedi_device *dev,
F020_SFR_ADC0L F020_SFR_ADC0L
}; };
u8 val[3]; u8 val[3];
int ret = -ENODEV; int ret;
down(&devpriv->sem); down(&devpriv->sem);
if (!slot->usb)
goto exit;
/* 1 select the gain */ /* 1 select the gain */
dt9812_configure_gain(dev, &rmw[0], gain); dt9812_configure_gain(dev, &rmw[0], gain);
...@@ -541,12 +504,12 @@ static int dt9812_analog_in(struct comedi_device *dev, ...@@ -541,12 +504,12 @@ static int dt9812_analog_in(struct comedi_device *dev,
rmw[2].and_mask = 0xff; rmw[2].and_mask = 0xff;
rmw[2].or_value = F020_MASK_ADC0CN_AD0EN | F020_MASK_ADC0CN_AD0BUSY; 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) if (ret)
goto exit; goto exit;
/* read the status and ADC */ /* 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) if (ret)
goto exit; goto exit;
...@@ -561,7 +524,7 @@ static int dt9812_analog_in(struct comedi_device *dev, ...@@ -561,7 +524,7 @@ static int dt9812_analog_in(struct comedi_device *dev,
*/ */
if ((val[0] & (F020_MASK_ADC0CN_AD0INT | F020_MASK_ADC0CN_AD0BUSY)) == if ((val[0] & (F020_MASK_ADC0CN_AD0INT | F020_MASK_ADC0CN_AD0BUSY)) ==
F020_MASK_ADC0CN_AD0INT) { F020_MASK_ADC0CN_AD0INT) {
switch (slot->usb->device) { switch (devpriv->device) {
case DT9812_DEVID_DT9812_10: case DT9812_DEVID_DT9812_10:
/* /*
* For DT9812-10V the personality module set the * For DT9812-10V the personality module set the
...@@ -597,53 +560,51 @@ static int dt9812_analog_out_shadow(struct comedi_device *dev, ...@@ -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) static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value)
{ {
struct dt9812_private *devpriv = dev->private; struct dt9812_private *devpriv = dev->private;
struct slot_dt9812 *slot = devpriv->slot; struct dt9812_rmw_byte rmw[3];
int ret = -ENODEV; int ret;
down(&devpriv->sem); down(&devpriv->sem);
if (slot->usb) {
struct dt9812_rmw_byte rmw[3];
switch (channel) { switch (channel) {
case 0: case 0:
/* 1. Set DAC mode */ /* 1. Set DAC mode */
rmw[0].address = F020_SFR_DAC0CN; rmw[0].address = F020_SFR_DAC0CN;
rmw[0].and_mask = 0xff; rmw[0].and_mask = 0xff;
rmw[0].or_value = F020_MASK_DACxCN_DACxEN; rmw[0].or_value = F020_MASK_DACxCN_DACxEN;
/* 2 load low byte of DAC value first */ /* 2 load low byte of DAC value first */
rmw[1].address = F020_SFR_DAC0L; rmw[1].address = F020_SFR_DAC0L;
rmw[1].and_mask = 0xff; rmw[1].and_mask = 0xff;
rmw[1].or_value = value & 0xff; rmw[1].or_value = value & 0xff;
/* 3 load high byte of DAC value next to latch the /* 3 load high byte of DAC value next to latch the
12-bit value */ 12-bit value */
rmw[2].address = F020_SFR_DAC0H; rmw[2].address = F020_SFR_DAC0H;
rmw[2].and_mask = 0xff; rmw[2].and_mask = 0xff;
rmw[2].or_value = (value >> 8) & 0xf; rmw[2].or_value = (value >> 8) & 0xf;
break; break;
case 1: case 1:
/* 1. Set DAC mode */ /* 1. Set DAC mode */
rmw[0].address = F020_SFR_DAC1CN; rmw[0].address = F020_SFR_DAC1CN;
rmw[0].and_mask = 0xff; rmw[0].and_mask = 0xff;
rmw[0].or_value = F020_MASK_DACxCN_DACxEN; rmw[0].or_value = F020_MASK_DACxCN_DACxEN;
/* 2 load low byte of DAC value first */ /* 2 load low byte of DAC value first */
rmw[1].address = F020_SFR_DAC1L; rmw[1].address = F020_SFR_DAC1L;
rmw[1].and_mask = 0xff; rmw[1].and_mask = 0xff;
rmw[1].or_value = value & 0xff; rmw[1].or_value = value & 0xff;
/* 3 load high byte of DAC value next to latch the /* 3 load high byte of DAC value next to latch the
12-bit value */ 12-bit value */
rmw[2].address = F020_SFR_DAC1H; rmw[2].address = F020_SFR_DAC1H;
rmw[2].and_mask = 0xff; rmw[2].and_mask = 0xff;
rmw[2].or_value = (value >> 8) & 0xf; rmw[2].or_value = (value >> 8) & 0xf;
break; break;
}
ret = dt9812_rmw_multiple_registers(slot->usb, 3, rmw);
devpriv->ao_shadow[channel] = value;
} }
ret = dt9812_rmw_multiple_registers(dev, 3, rmw);
devpriv->ao_shadow[channel] = value;
up(&devpriv->sem); up(&devpriv->sem);
return ret; return ret;
...@@ -727,10 +688,11 @@ static int dt9812_ao_winsn(struct comedi_device *dev, ...@@ -727,10 +688,11 @@ static int dt9812_ao_winsn(struct comedi_device *dev,
return n; return n;
} }
static int dt9812_find_endpoints(struct usb_interface *intf, static int dt9812_find_endpoints(struct comedi_device *dev)
struct usb_dt9812 *devpriv)
{ {
struct usb_interface *intf = comedi_to_usb_interface(dev);
struct usb_host_interface *host = intf->cur_altsetting; struct usb_host_interface *host = intf->cur_altsetting;
struct dt9812_private *devpriv = dev->private;
struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep;
int i; int i;
...@@ -774,24 +736,26 @@ static int dt9812_find_endpoints(struct usb_interface *intf, ...@@ -774,24 +736,26 @@ static int dt9812_find_endpoints(struct usb_interface *intf,
return 0; return 0;
} }
static int dt9812_reset_device(struct usb_interface *intf, static int dt9812_reset_device(struct comedi_device *dev)
struct usb_dt9812 *devpriv)
{ {
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 ret;
int i; int i;
u32 tmp32; u32 tmp32;
u16 tmp16; u16 tmp16;
u8 tmp8; u8 tmp8;
ret = dt9812_read_info(devpriv, 0, &tmp8, sizeof(tmp8)); ret = dt9812_read_info(dev, 0, &tmp8, sizeof(tmp8));
if (ret) { if (ret) {
/* /*
* Seems like a configuration reset is necessary if driver is * Seems like a configuration reset is necessary if driver is
* reloaded while device is attached * reloaded while device is attached
*/ */
usb_reset_configuration(devpriv->udev); usb_reset_configuration(usb);
for (i = 0; i < 10; i++) { 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) if (ret == 0)
break; break;
} }
...@@ -801,28 +765,28 @@ static int dt9812_reset_device(struct usb_interface *intf, ...@@ -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) { if (ret) {
dev_err(&intf->dev, "failed to read vendor id\n"); dev_err(&intf->dev, "failed to read vendor id\n");
return ret; return ret;
} }
devpriv->vendor = le16_to_cpu(tmp16); 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) { if (ret) {
dev_err(&intf->dev, "failed to read product id\n"); dev_err(&intf->dev, "failed to read product id\n");
return ret; return ret;
} }
devpriv->product = le16_to_cpu(tmp16); 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) { if (ret) {
dev_err(&intf->dev, "failed to read device id\n"); dev_err(&intf->dev, "failed to read device id\n");
return ret; return ret;
} }
devpriv->device = le16_to_cpu(tmp16); 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) { if (ret) {
dev_err(&intf->dev, "failed to read serial number\n"); dev_err(&intf->dev, "failed to read serial number\n");
return ret; return ret;
...@@ -837,11 +801,11 @@ static int dt9812_reset_device(struct usb_interface *intf, ...@@ -837,11 +801,11 @@ static int dt9812_reset_device(struct usb_interface *intf,
return 0; 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; struct dt9812_private *devpriv;
int i;
struct comedi_subdevice *s; struct comedi_subdevice *s;
bool is_unipolar; bool is_unipolar;
int ret; int ret;
...@@ -850,186 +814,110 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) ...@@ -850,186 +814,110 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (!devpriv) if (!devpriv)
return -ENOMEM; return -ENOMEM;
dev->private = devpriv; dev->private = devpriv;
sema_init(&devpriv->sem, 1);
down(&dt9812_mutex); sema_init(&devpriv->sem, 1);
usb_set_intfdata(intf, devpriv);
/* ret = dt9812_find_endpoints(dev);
* Find the first unused slot for the comedi device if (ret)
* that has a usb device connected. return ret;
*/
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;
}
slot->devpriv = devpriv; ret = dt9812_reset_device(dev);
devpriv->slot = slot; if (ret)
is_unipolar = (slot->usb->device == DT9812_DEVID_DT9812_2PT5); return ret;
up(&dt9812_mutex); is_unipolar = (devpriv->device == DT9812_DEVID_DT9812_2PT5);
ret = comedi_alloc_subdevices(dev, 4); ret = comedi_alloc_subdevices(dev, 4);
if (ret) if (ret)
return ret; return ret;
/* digital input subdevice */ /* Digital Input subdevice */
s = &dev->subdevices[0]; s = &dev->subdevices[0];
s->type = COMEDI_SUBD_DI; s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE; s->subdev_flags = SDF_READABLE;
s->n_chan = 8; s->n_chan = 8;
s->maxdata = 1; s->maxdata = 1;
s->range_table = &range_digital; s->range_table = &range_digital;
s->insn_read = &dt9812_di_rinsn; s->insn_read = dt9812_di_rinsn;
/* digital output subdevice */ /* Digital Output subdevice */
s = &dev->subdevices[1]; s = &dev->subdevices[1];
s->type = COMEDI_SUBD_DO; s->type = COMEDI_SUBD_DO;
s->subdev_flags = SDF_WRITEABLE; s->subdev_flags = SDF_WRITEABLE;
s->n_chan = 8; s->n_chan = 8;
s->maxdata = 1; s->maxdata = 1;
s->range_table = &range_digital; s->range_table = &range_digital;
s->insn_write = &dt9812_do_winsn; s->insn_write = dt9812_do_winsn;
devpriv->do_shadow = 0; devpriv->do_shadow = 0;
/* analog input subdevice */ /* Analog Input subdevice */
s = &dev->subdevices[2]; s = &dev->subdevices[2];
s->type = COMEDI_SUBD_AI; s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_GROUND; s->subdev_flags = SDF_READABLE | SDF_GROUND;
s->n_chan = 8; s->n_chan = 8;
s->maxdata = 4095; s->maxdata = 0x0fff;
s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10;
s->insn_read = &dt9812_ai_rinsn; s->insn_read = dt9812_ai_rinsn;
/* analog output subdevice */ /* Analog Output subdevice */
s = &dev->subdevices[3]; s = &dev->subdevices[3];
s->type = COMEDI_SUBD_AO; s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITEABLE; s->subdev_flags = SDF_WRITEABLE;
s->n_chan = 0; s->n_chan = 2;
s->maxdata = 4095; s->maxdata = 0x0fff;
s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10;
s->insn_write = &dt9812_ao_winsn; s->insn_write = dt9812_ao_winsn;
s->insn_read = &dt9812_ao_rinsn; s->insn_read = dt9812_ao_rinsn;
devpriv->ao_shadow[0] = is_unipolar ? 0x0000 : 0x0800; devpriv->ao_shadow[0] = is_unipolar ? 0x0000 : 0x0800;
devpriv->ao_shadow[1] = is_unipolar ? 0x0000 : 0x0800; devpriv->ao_shadow[1] = is_unipolar ? 0x0000 : 0x0800;
dev_info(dev->class_dev, "successfully attached to dt9812.\n");
return 0; return 0;
} }
static void dt9812_detach(struct comedi_device *dev) static void dt9812_detach(struct comedi_device *dev)
{ {
struct usb_interface *intf = comedi_to_usb_interface(dev);
struct dt9812_private *devpriv = dev->private; struct dt9812_private *devpriv = dev->private;
if (devpriv && devpriv->slot) if (!devpriv)
devpriv->slot = NULL; return;
}
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;
/* save our data pointer in this interface device */ down(&devpriv->sem);
usb_set_intfdata(intf, dev);
return 0; usb_set_intfdata(intf, NULL);
error: up(&devpriv->sem);
if (dev)
kref_put(&dev->kref, dt9812_delete);
return retval;
} }
static void dt9812_disconnect(struct usb_interface *intf) static struct comedi_driver dt9812_driver = {
{ .driver_name = "dt9812",
struct usb_dt9812 *dev; .module = THIS_MODULE,
int minor = intf->minor; .auto_attach = dt9812_auto_attach,
.detach = dt9812_detach,
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);
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) }, { USB_DEVICE(0x0867, 0x9812) },
{ } { }
}; };
MODULE_DEVICE_TABLE(usb, dt9812_table); MODULE_DEVICE_TABLE(usb, dt9812_usb_table);
static struct usb_driver dt9812_usb_driver = { static struct usb_driver dt9812_usb_driver = {
.name = "dt9812", .name = "dt9812",
.id_table = dt9812_table, .id_table = dt9812_usb_table,
.probe = dt9812_probe, .probe = dt9812_usb_probe,
.disconnect = dt9812_disconnect, .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@control.lth.se>"); MODULE_AUTHOR("Anders Blomdell <anders.blomdell@control.lth.se>");
MODULE_DESCRIPTION("Comedi DT9812 driver"); MODULE_DESCRIPTION("Comedi DT9812 driver");
......
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