Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1823fcbf authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman
Browse files

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



The usb_driver (*probe) already calls comedi_usb_auto_config(), which
will call the comedi_driver (*auto_attach). Move the bulk of the (*probe)
to the (*auto_attach).

This allows the comedi_device private data to be kzalloc'ed and the static
array used to pass the private data from the usb_driver to the comedi_driver
can be removed along with the static semaphore that protected it.

We can also drop a couple variables from the private data since they no
longer are used or needed.

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 9319d4ab
Loading
Loading
Loading
Loading
+40 −113
Original line number Diff line number Diff line
@@ -145,9 +145,6 @@ Status: testing
/* 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

@@ -172,10 +169,6 @@ static const struct comedi_lrange range_usbdux_ai_range = { 1, {
};

struct usbduxsigma_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 */
@@ -199,8 +192,6 @@ struct usbduxsigma_private {
	int8_t *insnBuffer;
	/* output buffer for single DA outputs */
	int16_t *outBuffer;
	/* interface number */
	int ifnum;
	/* interface structure in 2.6 */
	struct usb_interface *interface;
	/* comedi device for the interrupt context */
@@ -233,17 +224,6 @@ struct usbduxsigma_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 usbduxsigma_private usbduxsub[NUMUSBDUX];

static DEFINE_SEMAPHORE(start_stop_sem);

static void usbdux_ai_stop(struct usbduxsigma_private *devpriv, int do_unlink)
{
	if (do_unlink) {
@@ -1737,8 +1717,6 @@ static void tidy_up(struct usbduxsigma_private *usbduxsub_tmp)
	if (usbduxsub_tmp->interface)
		usb_set_intfdata(usbduxsub_tmp->interface, NULL);

	usbduxsub_tmp->probed = 0;

	if (usbduxsub_tmp->urbIn) {
		/* force unlink all urbs */
		usbdux_ai_stop(usbduxsub_tmp, 1);
@@ -1789,9 +1767,9 @@ static void tidy_up(struct usbduxsigma_private *usbduxsub_tmp)
	usbduxsub_tmp->dux_commands = NULL;
}

static int usbduxsigma_attach_common(struct comedi_device *dev,
				     struct usbduxsigma_private *uds)
static int usbduxsigma_attach_common(struct comedi_device *dev)
{
	struct usbduxsigma_private *uds = dev->private;
	int ret;
	struct comedi_subdevice *s;
	int n_subdevs;
@@ -1811,8 +1789,6 @@ static int usbduxsigma_attach_common(struct comedi_device *dev,
		up(&uds->sem);
		return ret;
	}
	/* private structure is also simply the usb-structure */
	dev->private = uds;
	/* the first subdevice is the A/D converter */
	s = &dev->subdevices[SUBDEV_AD];
	/* the URBs get the comedi subdevice */
@@ -1890,8 +1866,6 @@ static int usbduxsigma_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 */
	uds->attached = 1;
	up(&uds->sem);
	offset = usbdux_getstatusinfo(dev, 0);
	if (offset < 0)
@@ -1991,34 +1965,51 @@ static int usbduxsigma_alloc_usb_buffers(struct usbduxsigma_private *devpriv)
static int usbduxsigma_auto_attach(struct comedi_device *dev,
				   unsigned long context_unused)
{
	struct usb_interface *uinterf = comedi_to_usb_interface(dev);
	struct usbduxsigma_private *uds = usb_get_intfdata(uinterf);
	struct usb_device *usb = uds->usbdev;
	struct usb_interface *intf = comedi_to_usb_interface(dev);
	struct usb_device *usb = comedi_to_usb_dev(dev);
	struct usbduxsigma_private *devpriv;
	int ret;

	dev->private = uds;	/* This is temporary... */
	ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
				   usbduxsigma_firmware_upload, 0);
	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
	if (!devpriv)
		return -ENOMEM;
	dev->private = devpriv;

	sema_init(&devpriv->sem, 1);
	devpriv->usbdev = usb;
	devpriv->interface = intf;
	usb_set_intfdata(intf, devpriv);

	ret = usb_set_interface(usb,
				intf->altsetting->desc.bInterfaceNumber, 3);
	if (ret < 0) {
		dev->private = NULL;
		return ret;
		dev_err(dev->class_dev,
			"could not set alternate setting 3 in high speed\n");
		return -ENODEV;
	}

	dev->private = NULL;
	/* test if it is high speed (USB 2.0) */
	devpriv->high_speed = (usb->speed == USB_SPEED_HIGH);
	if (devpriv->high_speed) {
		devpriv->numOfInBuffers = NUMOFINBUFFERSHIGH;
		devpriv->numOfOutBuffers = NUMOFOUTBUFFERSHIGH;
	} else {
		devpriv->numOfInBuffers = NUMOFINBUFFERSFULL;
		devpriv->numOfOutBuffers = NUMOFOUTBUFFERSFULL;
	}

	down(&start_stop_sem);
	if (!uds) {
		dev_err(dev->class_dev,
			"usbduxsigma: error: auto_attach failed, not connected\n");
		ret = -ENODEV;
	} else if (uds->attached) {
		dev_err(dev->class_dev,
		       "usbduxsigma: error: auto_attach failed, already attached\n");
		ret = -ENODEV;
	} else
		ret = usbduxsigma_attach_common(dev, uds);
	up(&start_stop_sem);
	ret = usbduxsigma_alloc_usb_buffers(devpriv);
	if (ret) {
		tidy_up(devpriv);
		return ret;
	}

	ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
				   usbduxsigma_firmware_upload, 0);
	if (ret)
		return ret;

	return usbduxsigma_attach_common(dev);
}

static void usbduxsigma_detach(struct comedi_device *dev)
@@ -2032,14 +2023,10 @@ static void usbduxsigma_detach(struct comedi_device *dev)
	usbdux_ai_stop(devpriv, devpriv->ai_cmd_running);
	usbdux_ao_stop(devpriv, devpriv->ao_cmd_running);

	down(&start_stop_sem);
	down(&devpriv->sem);
	dev->private = NULL;
	devpriv->attached = 0;
	devpriv->comedidev = NULL;
	tidy_up(devpriv);
	up(&devpriv->sem);
	up(&start_stop_sem);
}

static struct comedi_driver usbduxsigma_driver = {
@@ -2052,66 +2039,6 @@ static struct comedi_driver usbduxsigma_driver = {
static int usbduxsigma_usb_probe(struct usb_interface *intf,
				 const struct usb_device_id *id)
{
	struct usb_device *usb = interface_to_usbdev(intf);
	struct device *dev = &intf->dev;
	struct usbduxsigma_private *devpriv = NULL;
	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 usbduxsigma-devices connected.\n");
		up(&start_stop_sem);
		return -EMFILE;
	}

	sema_init(&devpriv->sem, 1);
	devpriv->usbdev = usb;
	devpriv->interface = intf;
	devpriv->ifnum = intf->altsetting->desc.bInterfaceNumber;
	usb_set_intfdata(intf, devpriv);

	ret = usb_set_interface(usb, devpriv->ifnum, 3);
	if (ret < 0) {
		dev_err(dev,
			"could not set alternate setting 3 in high speed\n");
		tidy_up(devpriv);
		up(&start_stop_sem);
		return -ENODEV;
	}

	/* test if it is high speed (USB 2.0) */
	devpriv->high_speed = (usb->speed == USB_SPEED_HIGH);
	if (devpriv->high_speed) {
		devpriv->numOfInBuffers = NUMOFINBUFFERSHIGH;
		devpriv->numOfOutBuffers = NUMOFOUTBUFFERSHIGH;
	} else {
		devpriv->numOfInBuffers = NUMOFINBUFFERSFULL;
		devpriv->numOfOutBuffers = NUMOFOUTBUFFERSFULL;
	}

	ret = usbduxsigma_alloc_usb_buffers(devpriv);
	if (ret) {
		tidy_up(devpriv);
		up(&start_stop_sem);
		return ret;
	}

	devpriv->ai_cmd_running = 0;
	devpriv->ao_cmd_running = 0;
	devpriv->pwm_cmd_running = 0;

	/* we've reached the bottom of the function */
	devpriv->probed = 1;
	up(&start_stop_sem);

	return comedi_usb_auto_config(intf, &usbduxsigma_driver, 0);;
}