提交 ef1ee8cf 编写于 作者: H H Hartley Sweeten 提交者: Greg Kroah-Hartman

staging: comedi: usbdux: push usb (*probe) into comedi (*auto_attach)

The usb_driver (*probe) calls comedi_usb_auto_config() after finding a
free slot for the static private data and doind some initial allocation
and setup. The comedi_usb_auto_config() will then call the comedi_driver
(*auto_attach).

Move all the probe/auto_attach into the comedi_driver and just have the
usb_driver call comedi_usb_auto_config(). This allows the comedi_driver
to allocate the private data and removes the need for the static array
and the semaphore that protects it.

Since all the probe/auto_attach is now handled by the comedi_driver, we
can also remove the 'attached' and 'probed' information from the private
data. The subdevice functions will only be hooked up if the usb device
has been probed and the comedi device is attached.
Signed-off-by: NH Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 a7dd65f5
......@@ -185,9 +185,6 @@ sampling rate. If you sample two channels you get 4kHz and so on.
/* must have more buffers due to buggy USB ctr */
#define NUMOFOUTBUFFERSHIGH 10
/* Total number of usbdux devices */
#define NUMUSBDUX 16
/* Analogue in subdevice */
#define SUBDEV_AD 0
......@@ -229,10 +226,6 @@ static const struct comedi_lrange range_usbdux_ao_range = { 2, {
};
struct usbdux_private {
/* attached? */
int attached;
/* is it associated with a subdevice? */
int probed;
/* pointer to the usb-device */
struct usb_device *usbdev;
/* actual number of in-buffers */
......@@ -290,17 +283,6 @@ struct usbdux_private {
struct semaphore sem;
};
/*
* The pointer to the private usb-data of the driver is also the private data
* for the comedi-device. This has to be global as the usb subsystem needs
* global variables. The other reason is that this structure must be there
* _before_ any comedi command is issued. The usb subsystem must be initialised
* before comedi can access it.
*/
static struct usbdux_private usbduxsub[NUMUSBDUX];
static DEFINE_SEMAPHORE(start_stop_sem);
/*
* Stops the data acquision
* It should be safe to call this function from any context
......@@ -369,10 +351,6 @@ static int usbdux_ai_cancel(struct comedi_device *dev,
/* prevent other CPUs from submitting new commands just now */
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
/* unlink only if the urb really has been submitted */
res = usbdux_ai_stop(this_usbduxsub, this_usbduxsub->ai_cmd_running);
up(&this_usbduxsub->sem);
......@@ -569,10 +547,6 @@ static int usbdux_ao_cancel(struct comedi_device *dev,
/* prevent other CPUs from submitting a command just now */
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
/* unlink only if it is really running */
res = usbdux_ao_stop(this_usbduxsub, this_usbduxsub->ao_cmd_running);
up(&this_usbduxsub->sem);
......@@ -856,9 +830,6 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev,
int err = 0, i;
unsigned int tmp_timer;
if (!(this_usbduxsub->probed))
return -ENODEV;
/* Step 1 : check if triggers are trivially valid */
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
......@@ -1024,10 +995,6 @@ static int usbdux_ai_inttrig(struct comedi_device *dev,
return -EFAULT;
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
dev_dbg(&this_usbduxsub->interface->dev,
"comedi%d: usbdux_ai_inttrig\n", dev->minor);
......@@ -1075,11 +1042,6 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* block other CPUs from starting an ai_cmd */
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
if (this_usbduxsub->ai_cmd_running) {
dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
"ai_cmd not possible. Another ai_cmd is running.\n",
......@@ -1194,10 +1156,6 @@ static int usbdux_ai_insn_read(struct comedi_device *dev,
dev->minor, insn->n, insn->subdev);
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
if (this_usbduxsub->ai_cmd_running) {
dev_err(&this_usbduxsub->interface->dev,
"comedi%d: ai_insn_read not possible. "
......@@ -1250,10 +1208,6 @@ static int usbdux_ao_insn_read(struct comedi_device *dev,
return -EFAULT;
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
for (i = 0; i < insn->n; i++)
data[i] = this_usbduxsub->out_buffer[chan];
......@@ -1276,10 +1230,6 @@ static int usbdux_ao_insn_write(struct comedi_device *dev,
"comedi%d: ao_insn_write\n", dev->minor);
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
if (this_usbduxsub->ao_cmd_running) {
dev_err(&this_usbduxsub->interface->dev,
"comedi%d: ao_insn_write: "
......@@ -1322,10 +1272,6 @@ static int usbdux_ao_inttrig(struct comedi_device *dev,
return -EFAULT;
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
if (trignum != 0) {
dev_err(&this_usbduxsub->interface->dev,
"comedi%d: usbdux_ao_inttrig: invalid trignum\n",
......@@ -1364,9 +1310,6 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev,
if (!this_usbduxsub)
return -EFAULT;
if (!(this_usbduxsub->probed))
return -ENODEV;
/* Step 1 : check if triggers are trivially valid */
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
......@@ -1452,10 +1395,6 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return -EFAULT;
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
dev_dbg(&this_usbduxsub->interface->dev,
"comedi%d: %s\n", dev->minor, __func__);
......@@ -1593,11 +1532,6 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev,
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
/* The insn data is a mask in data[0] and the new data
* in data[1], each channel cooresponding to a bit. */
s->state &= ~data[0];
......@@ -1636,12 +1570,6 @@ static int usbdux_counter_read(struct comedi_device *dev,
return -EFAULT;
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
if (err < 0) {
up(&this_usbduxsub->sem);
......@@ -1670,12 +1598,6 @@ static int usbdux_counter_write(struct comedi_device *dev,
return -EFAULT;
down(&this_usbduxsub->sem);
if (!(this_usbduxsub->probed)) {
up(&this_usbduxsub->sem);
return -ENODEV;
}
this_usbduxsub->dux_commands[1] = insn->chanspec;
*((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data);
......@@ -2050,8 +1972,6 @@ static void tidy_up(struct usbdux_private *usbduxsub_tmp)
if (usbduxsub_tmp->interface)
usb_set_intfdata(usbduxsub_tmp->interface, NULL);
usbduxsub_tmp->probed = 0;
if (usbduxsub_tmp->urb_in) {
if (usbduxsub_tmp->ai_cmd_running) {
usbduxsub_tmp->ai_cmd_running = 0;
......@@ -2110,9 +2030,9 @@ static void tidy_up(struct usbdux_private *usbduxsub_tmp)
usbduxsub_tmp->pwm_cmd_running = 0;
}
static int usbdux_attach_common(struct comedi_device *dev,
struct usbdux_private *udev)
static int usbdux_attach_common(struct comedi_device *dev)
{
struct usbdux_private *udev = dev->private;
int ret;
struct comedi_subdevice *s = NULL;
int n_subdevs;
......@@ -2136,9 +2056,6 @@ static int usbdux_attach_common(struct comedi_device *dev,
return ret;
}
/* private structure is also simply the usb-structure */
dev->private = udev;
/* the first subdevice is the A/D converter */
s = &dev->subdevices[SUBDEV_AD];
/* the URBs get the comedi subdevice */
......@@ -2227,8 +2144,6 @@ static int usbdux_attach_common(struct comedi_device *dev,
s->insn_config = usbdux_pwm_config;
usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
}
/* finally decide that it's attached */
udev->attached = 1;
up(&udev->sem);
......@@ -2352,88 +2267,21 @@ static int usbdux_alloc_usb_buffers(struct usbdux_private *devpriv)
static int usbdux_auto_attach(struct comedi_device *dev,
unsigned long context_unused)
{
struct usb_interface *uinterf = comedi_to_usb_interface(dev);
struct usbdux_private *this_usbduxsub = usb_get_intfdata(uinterf);
struct usb_device *usb = usbduxsub->usbdev;
int ret;
dev->private = this_usbduxsub; /* This is temporary... */
ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
usbdux_firmware_upload, 0);
if (ret < 0) {
dev->private = NULL;
return ret;
}
dev->private = NULL;
down(&start_stop_sem);
if (!this_usbduxsub || !this_usbduxsub->probed) {
dev_err(dev->class_dev,
"usbdux: error: auto_attach failed, not connected\n");
ret = -ENODEV;
} else if (this_usbduxsub->attached) {
dev_err(dev->class_dev,
"error: auto_attach failed, already attached\n");
ret = -ENODEV;
} else
ret = usbdux_attach_common(dev, this_usbduxsub);
up(&start_stop_sem);
return ret;
}
static void usbdux_detach(struct comedi_device *dev)
{
struct usbdux_private *devpriv = dev->private;
down(&start_stop_sem);
if (devpriv) {
down(&devpriv->sem);
tidy_up(devpriv);
dev->private = NULL;
devpriv->attached = 0;
devpriv->comedidev = NULL;
up(&devpriv->sem);
}
up(&start_stop_sem);
}
static struct comedi_driver usbdux_driver = {
.driver_name = "usbdux",
.module = THIS_MODULE,
.auto_attach = usbdux_auto_attach,
.detach = usbdux_detach,
};
static int usbdux_usb_probe(struct usb_interface *uinterf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(uinterf);
struct device *dev = &uinterf->dev;
struct usbdux_private *devpriv = NULL;
struct usb_interface *intf = comedi_to_usb_interface(dev);
struct usb_device *usb = comedi_to_usb_dev(dev);
struct usbdux_private *devpriv;
int ret;
int i;
down(&start_stop_sem);
for (i = 0; i < NUMUSBDUX; i++) {
if (!usbduxsub[i].probed) {
devpriv = &usbduxsub[i];
break;
}
}
if (!devpriv) {
dev_err(dev, "Too many usbdux-devices connected.\n");
up(&start_stop_sem);
return -EMFILE;
}
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
sema_init(&devpriv->sem, 1);
devpriv->usbdev = udev;
devpriv->interface = uinterf;
devpriv->ifnum = uinterf->altsetting->desc.bInterfaceNumber;
usb_set_intfdata(uinterf, devpriv);
devpriv->usbdev = usb;
devpriv->interface = intf;
devpriv->ifnum = intf->altsetting->desc.bInterfaceNumber;
usb_set_intfdata(intf, devpriv);
devpriv->high_speed = (devpriv->usbdev->speed == USB_SPEED_HIGH);
if (devpriv->high_speed) {
......@@ -2443,35 +2291,54 @@ static int usbdux_usb_probe(struct usb_interface *uinterf,
} else {
devpriv->num_in_buffers = NUMOFINBUFFERSFULL;
devpriv->num_out_buffers = NUMOFOUTBUFFERSFULL;
devpriv->size_pwm_buf = 0;
}
ret = usbdux_alloc_usb_buffers(devpriv);
if (ret) {
tidy_up(devpriv);
up(&start_stop_sem);
return ret;
}
/* setting to alternate setting 3: enabling iso ep and bulk ep. */
ret = usb_set_interface(devpriv->usbdev, devpriv->ifnum, 3);
if (ret < 0) {
dev_err(dev,
dev_err(dev->class_dev,
"could not set alternate setting 3 in high speed\n");
tidy_up(devpriv);
up(&start_stop_sem);
return ret;
}
devpriv->ai_cmd_running = 0;
devpriv->ao_cmd_running = 0;
devpriv->pwm_cmd_running = 0;
ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
usbdux_firmware_upload, 0);
if (ret < 0)
return ret;
/* we've reached the bottom of the function */
devpriv->probed = 1;
up(&start_stop_sem);
return usbdux_attach_common(dev);
}
static void usbdux_detach(struct comedi_device *dev)
{
struct usbdux_private *devpriv = dev->private;
return comedi_usb_auto_config(uinterf, &usbdux_driver, 0);
if (devpriv) {
down(&devpriv->sem);
tidy_up(devpriv);
devpriv->comedidev = NULL;
up(&devpriv->sem);
}
}
static struct comedi_driver usbdux_driver = {
.driver_name = "usbdux",
.module = THIS_MODULE,
.auto_attach = usbdux_auto_attach,
.detach = usbdux_detach,
};
static int usbdux_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return comedi_usb_auto_config(intf, &usbdux_driver, 0);
}
static const struct usb_device_id usbdux_usb_table[] = {
......@@ -2479,7 +2346,6 @@ static const struct usb_device_id usbdux_usb_table[] = {
{ USB_DEVICE(0x13d8, 0x0002) },
{ }
};
MODULE_DEVICE_TABLE(usb, usbdux_usb_table);
static struct usb_driver usbdux_usb_driver = {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册