Commit f4011670 authored by Ian Abbott's avatar Ian Abbott Committed by Greg Kroah-Hartman

staging: comedi: add bus-type-specific attach hooks for PCI and USB

The Comedi auto-configuration mechanism used to bind hardware devices to
comedi devices automatically is pretty kludgy.  It fakes a "manual"
configuration of the comedi device as though the COMEDI_DEVCONFIG ioctl
(or the 'comedi_config' utility) were used.  In particular, the
low-level comedi driver's '->attach()' routine is called with a pointer
to the struct comedi_device being attached and a pointer to a 'struct
devconfig' containing a device name string and a few integer options to
help the attach routine locate the device being attached.  In the case
of PCI devices, these integer options are the PCI bus and slot numbers.
In the case of USB devices, there are no integer options and it relies
more on pot luck to attach the correct device.

This patch adds a couple of bus-type-specific attach routine hooks to
the struct comedi_driver, which a low-level driver can optionally fill
in if it supports auto-configuration.

A low-level driver that supports auto-configuration of {PCI,USB} devices
calls the existing comedi_{pci,usb}_auto_config() when it wishes to
auto-configure a freshly probed device (maybe after loading firmware).
This will call the new '->attach_{pci,usb}()' hook if the driver has
defined it, otherwise it will fall back to calling the '->attach()' hook
as before.  The '->attach_{pci,usb}()' hook gets a pointer to the struct
comedi_device and a pointer to the struct {pci_dev,usb_interface} and
can figure out the {PCI,USB} device details for itself.
Signed-off-by: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3902a370
...@@ -180,6 +180,9 @@ struct comedi_async { ...@@ -180,6 +180,9 @@ struct comedi_async {
unsigned int x); unsigned int x);
}; };
struct pci_dev;
struct usb_interface;
struct comedi_driver { struct comedi_driver {
struct comedi_driver *next; struct comedi_driver *next;
...@@ -187,6 +190,8 @@ struct comedi_driver { ...@@ -187,6 +190,8 @@ struct comedi_driver {
struct module *module; struct module *module;
int (*attach) (struct comedi_device *, struct comedi_devconfig *); int (*attach) (struct comedi_device *, struct comedi_devconfig *);
int (*detach) (struct comedi_device *); int (*detach) (struct comedi_device *);
int (*attach_pci) (struct comedi_device *, struct pci_dev *);
int (*attach_usb) (struct comedi_device *, struct usb_interface *);
/* number of elements in board_name and board_id arrays */ /* number of elements in board_name and board_id arrays */
unsigned int num_names; unsigned int num_names;
...@@ -460,7 +465,6 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s); ...@@ -460,7 +465,6 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s);
int comedi_pci_auto_config(struct pci_dev *pcidev, int comedi_pci_auto_config(struct pci_dev *pcidev,
struct comedi_driver *driver); struct comedi_driver *driver);
void comedi_pci_auto_unconfig(struct pci_dev *pcidev); void comedi_pci_auto_unconfig(struct pci_dev *pcidev);
struct usb_interface; /* forward declaration */
int comedi_usb_auto_config(struct usb_interface *intf, int comedi_usb_auto_config(struct usb_interface *intf,
struct comedi_driver *driver); struct comedi_driver *driver);
void comedi_usb_auto_unconfig(struct usb_interface *intf); void comedi_usb_auto_unconfig(struct usb_interface *intf);
......
...@@ -811,6 +811,51 @@ void comedi_reset_async_buf(struct comedi_async *async) ...@@ -811,6 +811,51 @@ void comedi_reset_async_buf(struct comedi_async *async)
async->events = 0; async->events = 0;
} }
static int
comedi_auto_config_helper(struct device *hardware_device,
struct comedi_driver *driver,
int (*attach_wrapper) (struct comedi_device *,
void *), void *context)
{
int minor;
struct comedi_device_file_info *dev_file_info;
struct comedi_device *comedi_dev;
int ret;
if (!comedi_autoconfig)
return 0;
minor = comedi_alloc_board_minor(hardware_device);
if (minor < 0)
return minor;
dev_file_info = comedi_get_device_file_info(minor);
comedi_dev = dev_file_info->device;
mutex_lock(&comedi_dev->mutex);
if (comedi_dev->attached)
ret = -EBUSY;
else if (!try_module_get(driver->module)) {
printk(KERN_INFO "comedi: failed to increment module count\n");
ret = -EIO;
} else {
/* set comedi_dev->driver here for attach wrapper */
comedi_dev->driver = driver;
ret = (*attach_wrapper)(comedi_dev, context);
if (ret < 0) {
module_put(driver->module);
__comedi_device_detach(comedi_dev);
} else {
ret = comedi_device_postconfig(comedi_dev);
}
}
mutex_unlock(&comedi_dev->mutex);
if (ret < 0)
comedi_free_board_minor(minor);
return ret;
}
static int comedi_auto_config(struct device *hardware_device, static int comedi_auto_config(struct device *hardware_device,
const char *board_name, const int *options, const char *board_name, const int *options,
unsigned num_options) unsigned num_options)
...@@ -857,7 +902,8 @@ static void comedi_auto_unconfig(struct device *hardware_device) ...@@ -857,7 +902,8 @@ static void comedi_auto_unconfig(struct device *hardware_device)
comedi_free_board_minor(minor); comedi_free_board_minor(minor);
} }
int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver) static int comedi_old_pci_auto_config(struct pci_dev *pcidev,
struct comedi_driver *driver)
{ {
int options[2]; int options[2];
...@@ -869,6 +915,27 @@ int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver) ...@@ -869,6 +915,27 @@ int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver)
return comedi_auto_config(&pcidev->dev, driver->driver_name, return comedi_auto_config(&pcidev->dev, driver->driver_name,
options, ARRAY_SIZE(options)); options, ARRAY_SIZE(options));
} }
static int comedi_pci_attach_wrapper(struct comedi_device *dev, void *pcidev)
{
return dev->driver->attach_pci(dev, pcidev);
}
static int comedi_new_pci_auto_config(struct pci_dev *pcidev,
struct comedi_driver *driver)
{
return comedi_auto_config_helper(&pcidev->dev, driver,
comedi_pci_attach_wrapper, pcidev);
}
int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver)
{
if (driver->attach_pci)
return comedi_new_pci_auto_config(pcidev, driver);
else
return comedi_old_pci_auto_config(pcidev, driver);
}
EXPORT_SYMBOL_GPL(comedi_pci_auto_config); EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
void comedi_pci_auto_unconfig(struct pci_dev *pcidev) void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
...@@ -877,11 +944,32 @@ void comedi_pci_auto_unconfig(struct pci_dev *pcidev) ...@@ -877,11 +944,32 @@ void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
} }
EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig);
static int comedi_old_usb_auto_config(struct usb_interface *intf,
struct comedi_driver *driver)
{
return comedi_auto_config(&intf->dev, driver->driver_name, NULL, 0);
}
static int comedi_usb_attach_wrapper(struct comedi_device *dev, void *intf)
{
return dev->driver->attach_usb(dev, intf);
}
static int comedi_new_usb_auto_config(struct usb_interface *intf,
struct comedi_driver *driver)
{
return comedi_auto_config_helper(&intf->dev, driver,
comedi_usb_attach_wrapper, intf);
}
int comedi_usb_auto_config(struct usb_interface *intf, int comedi_usb_auto_config(struct usb_interface *intf,
struct comedi_driver *driver) struct comedi_driver *driver)
{ {
BUG_ON(intf == NULL); BUG_ON(intf == NULL);
return comedi_auto_config(&intf->dev, driver->driver_name, NULL, 0); if (driver->attach_usb)
return comedi_new_usb_auto_config(intf, driver);
else
return comedi_old_usb_auto_config(intf, driver);
} }
EXPORT_SYMBOL_GPL(comedi_usb_auto_config); EXPORT_SYMBOL_GPL(comedi_usb_auto_config);
......
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