From: Frank Mori Hess Date: Thu, 16 Oct 2008 20:58:26 +0000 (+0000) Subject: Added support for udev/sysfs to core and ni_pcimio driver. Driver now X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=2eab4cbdf23cedf0b425ae0b8eee7b716e8142bf;p=comedi.git Added support for udev/sysfs to core and ni_pcimio driver. Driver now auto-configures itself on a /dev/comediN device (starting at /dev/comedi16) as if the user had done a "comedi_config /dev/comediN ni_pcimio ," --- diff --git a/comedi/comedi_fops.c b/comedi/comedi_fops.c index c6af6dd3..985cf3f7 100644 --- a/comedi/comedi_fops.c +++ b/comedi/comedi_fops.c @@ -50,7 +50,7 @@ //#include "kvmem.h" -MODULE_AUTHOR("David Schleef "); +MODULE_AUTHOR("http://www.comedi.org"); MODULE_DESCRIPTION("Comedi core module"); MODULE_LICENSE("GPL"); @@ -59,7 +59,8 @@ int comedi_debug; module_param(comedi_debug, int, 0644); #endif -comedi_device *comedi_devices; +static DEFINE_SPINLOCK(comedi_file_info_table_lock); +static struct comedi_device_file_info* comedi_file_info_table[COMEDI_NUM_MINORS]; static int do_devconfig_ioctl(comedi_device * dev, comedi_devconfig * arg); static int do_bufconfig_ioctl(comedi_device * dev, void *arg); @@ -94,7 +95,8 @@ static int comedi_ioctl(struct inode *inode, struct file *file, #endif { const unsigned minor = iminor(file->f_dentry->d_inode); - comedi_device *dev = comedi_get_device_by_minor(minor); + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor); + comedi_device *dev = dev_file_info->device; int rc; mutex_lock(&dev->mutex); @@ -191,7 +193,8 @@ static int do_devconfig_ioctl(comedi_device * dev, comedi_devconfig * arg) if (arg == NULL) { if (is_device_busy(dev)) return -EBUSY; - return comedi_device_detach(dev); + comedi_device_detach(dev); + return 0; } if (copy_from_user(&it, arg, sizeof(comedi_devconfig))) @@ -340,8 +343,9 @@ static int do_devinfo_ioctl(comedi_device * dev, comedi_devinfo * arg, { comedi_devinfo devinfo; const unsigned minor = iminor(file->f_dentry->d_inode); - comedi_subdevice *read_subdev = comedi_get_read_subdevice(dev, minor); - comedi_subdevice *write_subdev = comedi_get_write_subdevice(dev, minor); + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor); + comedi_subdevice *read_subdev = comedi_get_read_subdevice(dev_file_info); + comedi_subdevice *write_subdev = comedi_get_write_subdevice(dev_file_info); memset(&devinfo, 0, sizeof(devinfo)); @@ -409,8 +413,7 @@ static int do_subdinfo_ioctl(comedi_device * dev, comedi_subdinfo * arg, us->maxdata = s->maxdata; if (s->range_table) { us->range_type = - (dev-> - minor << 28) | (i << 24) | (0 << 16) | (s-> + (i << 24) | (0 << 16) | (s-> range_table->length); } else { us->range_type = 0; /* XXX */ @@ -1378,7 +1381,8 @@ static struct vm_operations_struct comedi_vm_ops = { static int comedi_mmap(struct file *file, struct vm_area_struct *vma) { const unsigned minor = iminor(file->f_dentry->d_inode); - comedi_device *dev = comedi_get_device_by_minor(minor); + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor); + comedi_device *dev = dev_file_info->device; comedi_async *async = NULL; unsigned long start = vma->vm_start; unsigned long size; @@ -1394,9 +1398,9 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) goto done; } if (vma->vm_flags & VM_WRITE) { - s = comedi_get_write_subdevice(dev, minor); + s = comedi_get_write_subdevice(dev_file_info); } else { - s = comedi_get_read_subdevice(dev, minor); + s = comedi_get_read_subdevice(dev_file_info); } if (s == NULL) { retval = -EINVAL; @@ -1451,7 +1455,8 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) { unsigned int mask = 0; const unsigned minor = iminor(file->f_dentry->d_inode); - comedi_device *dev = comedi_get_device_by_minor(minor); + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor); + comedi_device *dev = dev_file_info->device; comedi_subdevice *read_subdev; comedi_subdevice *write_subdev; @@ -1463,7 +1468,7 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) } mask = 0; - read_subdev = comedi_get_read_subdevice(dev, minor); + read_subdev = comedi_get_read_subdevice(dev_file_info); if (read_subdev) { poll_wait(file, &read_subdev->async->wait_head, wait); if (!read_subdev->busy @@ -1473,7 +1478,7 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) mask |= POLLIN | POLLRDNORM; } } - write_subdev = comedi_get_write_subdevice(dev, minor); + write_subdev = comedi_get_write_subdevice(dev_file_info); if (write_subdev) { poll_wait(file, &write_subdev->async->wait_head, wait); comedi_buf_write_alloc(write_subdev->async, write_subdev->async->prealloc_bufsz); @@ -1493,21 +1498,21 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) static ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes, loff_t * offset) { - comedi_device *dev; comedi_subdevice *s; comedi_async *async; int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); const unsigned minor = iminor(file->f_dentry->d_inode); + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor); + comedi_device *dev = dev_file_info->device; - dev = comedi_get_device_by_minor(minor); if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); retval = -ENODEV; goto done; } - s = comedi_get_write_subdevice(dev, minor); + s = comedi_get_write_subdevice(dev_file_info); if (s == NULL) { retval = -EIO; goto done; @@ -1602,7 +1607,8 @@ static ssize_t comedi_read(struct file *file, char *buf, size_t nbytes, int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); const unsigned minor = iminor(file->f_dentry->d_inode); - comedi_device *dev = comedi_get_device_by_minor(minor); + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor); + comedi_device *dev = dev_file_info->device; if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); @@ -1610,7 +1616,7 @@ static ssize_t comedi_read(struct file *file, char *buf, size_t nbytes, goto done; } - s = comedi_get_read_subdevice(dev, minor); + s = comedi_get_read_subdevice(dev_file_info); if (s == NULL) { retval = -EIO; goto done; @@ -1729,7 +1735,8 @@ static int comedi_open(struct inode *inode, struct file *file) { char mod[32]; const unsigned minor = iminor(inode); - comedi_device *dev = comedi_get_device_by_minor(minor); + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor); + comedi_device *dev = dev_file_info->device; if (dev == NULL) { DPRINTK("invalid minor number\n"); return -ENODEV; @@ -1800,7 +1807,8 @@ static int comedi_open(struct inode *inode, struct file *file) static int comedi_close(struct inode *inode, struct file *file) { const unsigned minor = iminor(inode); - comedi_device *dev = comedi_get_device_by_minor(minor); + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor); + comedi_device *dev = dev_file_info->device; comedi_subdevice *s = NULL; int i; @@ -1841,7 +1849,8 @@ static int comedi_close(struct inode *inode, struct file *file) static int comedi_fasync(int fd, struct file *file, int on) { const unsigned minor = iminor(file->f_dentry->d_inode); - comedi_device *dev = comedi_get_device_by_minor(minor); + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(minor); + comedi_device *dev = dev_file_info->device; return fasync_helper(fd, file, on, &dev->async_queue); } @@ -1868,13 +1877,24 @@ const struct file_operations comedi_fops = { struct class *comedi_class = NULL; static struct cdev comedi_cdev; +static void comedi_cleanup_legacy_minors(void) +{ + unsigned i; + for (i = 0; i < COMEDI_NUM_LEGACY_MINORS; i++) { + comedi_free_board_minor(i); + } +} + static int __init comedi_init(void) { int i; int retval; printk("comedi: version " COMEDI_RELEASE - " - David Schleef \n"); + " - http://www.comedi.org\n"); + + memset(comedi_file_info_table, 0, sizeof(struct comedi_device_file_info*) * COMEDI_NUM_MINORS); + retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS, "comedi"); if (retval) @@ -1890,33 +1910,27 @@ static int __init comedi_init(void) comedi_class = class_create(THIS_MODULE, "comedi"); if (IS_ERR(comedi_class)) { printk("comedi: failed to create class"); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); cdev_del(&comedi_cdev); - return PTR_ERR(comedi_class); - } - comedi_devices = - kcalloc(COMEDI_NDEVICES, sizeof(comedi_device), GFP_KERNEL); - if (!comedi_devices) { unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); - cdev_del(&comedi_cdev); - class_destroy(comedi_class); - return -ENOMEM; + return PTR_ERR(comedi_class); } /* XXX requires /proc interface */ comedi_proc_init(); - for (i = 0; i < COMEDI_NDEVICES; i++) { - struct device *csdev; - comedi_devices[i].minor = i; - csdev = COMEDI_DEVICE_CREATE(comedi_class, 0, - MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i); - if (!IS_ERR(csdev)) - comedi_devices[i].class_dev = csdev; - spin_lock_init(&comedi_devices[i].spinlock); - mutex_init(&comedi_devices[i].mutex); + // create devices files for legacy/manual use + for (i = 0; i < COMEDI_NUM_LEGACY_MINORS; i++) { + int minor; + minor = comedi_alloc_board_minor(NULL); + if(minor < 0) + { + comedi_cleanup_legacy_minors(); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return minor; + } } comedi_rt_init(); @@ -1930,25 +1944,18 @@ static void __exit comedi_cleanup(void) { int i; - for (i = 0; i < COMEDI_NDEVICES; i++) { - comedi_device *dev; - - dev = comedi_devices + i; - mutex_lock(&dev->mutex); - if (dev->attached) - comedi_device_detach(dev); - mutex_unlock(&dev->mutex); - mutex_destroy(&dev->mutex); - device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, i)); + comedi_cleanup_legacy_minors(); + for(i = 0; i < COMEDI_NUM_MINORS; ++i) + { + BUG_ON(comedi_file_info_table[i]); } + class_destroy(comedi_class); cdev_del(&comedi_cdev); unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); comedi_proc_cleanup(); - kfree(comedi_devices); - comedi_rt_cleanup(); comedi_unregister_ioctl32(); @@ -2064,3 +2071,171 @@ static int is_device_busy(comedi_device * dev) return 0; } + +void comedi_device_init(comedi_device *dev) +{ + memset(dev, 0, sizeof(comedi_device)); + spin_lock_init(&dev->spinlock); + mutex_init(&dev->mutex); + dev->minor = -1; +} + +void comedi_device_cleanup(comedi_device *dev) +{ + if(dev == NULL) return; + mutex_lock(&dev->mutex); + if (dev->attached) + comedi_device_detach(dev); + mutex_unlock(&dev->mutex); + mutex_destroy(&dev->mutex); +} + +int comedi_alloc_board_minor(struct device *hardware_device) +{ + unsigned long flags; + struct comedi_device_file_info *info; + device_create_result_type *csdev; + unsigned i; + + info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); + if(info == NULL) return -ENOMEM; + info->device = kzalloc(sizeof(comedi_device), GFP_KERNEL); + if(info->device == NULL) + { + kfree(info); + return -ENOMEM; + } + comedi_device_init(info->device); + comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + for(i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) + { + if(comedi_file_info_table[i] == NULL) + { + comedi_file_info_table[i] = info; + break; + } + } + comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + if(i == COMEDI_NUM_BOARD_MINORS) + { + comedi_device_cleanup(info->device); + kfree(info->device); + kfree(info); + rt_printk("comedi: error: ran out of minor numbers for board device files.\n"); + return -EBUSY; + } + info->device->minor = i; + csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL, + MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i); + if(!IS_ERR(csdev)) { + info->device->class_dev = csdev; + if(hardware_device) + { + sysfs_create_link(&csdev->kobj, + &hardware_device->kobj, "device"); + } + } + return i; +} + +void comedi_free_board_minor(unsigned minor) +{ + unsigned long flags; + struct comedi_device_file_info *info; + + BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); + comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + info = comedi_file_info_table[minor]; + comedi_file_info_table[minor] = NULL; + comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + + if(info) + { + comedi_device *dev = info->device; + if(dev) + { + if(dev->class_dev) + { + sysfs_remove_link(&dev->class_dev->kobj, "device"); + device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, dev->minor)); + } + comedi_device_cleanup(dev) + kfree(dev); + } + kfree(info); + } +} + +int comedi_alloc_subdevice_minor(comedi_device *dev, comedi_subdevice *s) +{ + unsigned long flags; + struct comedi_device_file_info *info; + device_create_result_type *csdev; + unsigned i; + + info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); + if(info == NULL) return -ENOMEM; + info->device = dev; + info->read_subdevice = s; + info->write_subdevice = s; + comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + for(i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_BOARD_MINORS; ++i) + { + if(comedi_file_info_table[i] == NULL) + { + comedi_file_info_table[i] = info; + break; + } + } + comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + if(i == COMEDI_NUM_MINORS) + { + kfree(info); + rt_printk("comedi: error: ran out of minor numbers for board device files.\n"); + return -EBUSY; + } + s->minor = i; + csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev, + MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i", dev->minor, s - dev->subdevices); + if(!IS_ERR(csdev)) + { + s->class_dev = csdev; + } + return i; +} + +void comedi_free_subdevice_minor(comedi_subdevice *s) +{ + unsigned long flags; + struct comedi_device_file_info *info; + + if(s == NULL) return; + if(s->minor < 0) return; + + BUG_ON(s->minor >= COMEDI_NUM_MINORS); + BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); + + comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + info = comedi_file_info_table[s->minor]; + comedi_file_info_table[s->minor] = NULL; + comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + + if(s->class_dev) + { + device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); + s->class_dev = NULL; + } + kfree(info); +} + +struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) +{ + unsigned long flags; + struct comedi_device_file_info *info; + + BUG_ON(minor >= COMEDI_NUM_MINORS); + comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + info = comedi_file_info_table[minor]; + comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + return info; +} diff --git a/comedi/comedi_ksyms.c b/comedi/comedi_ksyms.c index 1189a896..7c365859 100644 --- a/comedi/comedi_ksyms.c +++ b/comedi/comedi_ksyms.c @@ -31,8 +31,6 @@ /* for drivers */ EXPORT_SYMBOL(comedi_driver_register); EXPORT_SYMBOL(comedi_driver_unregister); -EXPORT_SYMBOL(comedi_allocate_dev); -EXPORT_SYMBOL(comedi_deallocate_dev); //EXPORT_SYMBOL(comedi_bufcheck); //EXPORT_SYMBOL(comedi_done); //EXPORT_SYMBOL(comedi_error_done); @@ -58,10 +56,14 @@ EXPORT_SYMBOL(rt_pend_call); #ifdef CONFIG_COMEDI_DEBUG EXPORT_SYMBOL(comedi_debug); #endif +EXPORT_SYMBOL_GPL(comedi_alloc_board_minor); +EXPORT_SYMBOL_GPL(comedi_free_board_minor); +EXPORT_SYMBOL_GPL(comedi_pci_auto_config); +EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); /* for kcomedilib */ -EXPORT_SYMBOL(comedi_devices); EXPORT_SYMBOL(check_chanlist); +EXPORT_SYMBOL_GPL(comedi_get_device_file_info); EXPORT_SYMBOL(comedi_buf_put); EXPORT_SYMBOL(comedi_buf_get); diff --git a/comedi/drivers.c b/comedi/drivers.c index 16df91e7..ed203125 100644 --- a/comedi/drivers.c +++ b/comedi/drivers.c @@ -27,6 +27,7 @@ #include "comedi_fops.h" #include #include +#include #include #include #include @@ -69,13 +70,7 @@ static void cleanup_device(comedi_device * dev) if (dev->subdevices) { for (i = 0; i < dev->n_subdevices; i++) { s = dev->subdevices + i; - if (s->class_dev) { - unsigned minor = - comedi_construct_minor_for_subdevice - (dev, i); - dev_t devt = MKDEV(COMEDI_MAJOR, minor); - device_destroy(comedi_class, devt); - } + comedi_free_subdevice_minor(s); if (s->async) { comedi_buf_alloc(dev, s, 0); kfree(s->async); @@ -89,7 +84,6 @@ static void cleanup_device(comedi_device * dev) kfree(dev->private); dev->private = NULL; } - module_put(dev->driver->module); dev->driver = 0; dev->board_name = NULL; dev->board_ptr = NULL; @@ -102,7 +96,7 @@ static void cleanup_device(comedi_device * dev) comedi_set_hw_dev(dev, NULL); } -static int __comedi_device_detach(comedi_device * dev) +static void __comedi_device_detach(comedi_device * dev) { dev->attached = 0; if (dev->driver) { @@ -111,14 +105,13 @@ static int __comedi_device_detach(comedi_device * dev) printk("BUG: dev->driver=NULL in comedi_device_detach()\n"); } cleanup_device(dev); - return 0; } -int comedi_device_detach(comedi_device * dev) +void comedi_device_detach(comedi_device * dev) { if (!dev->attached) - return 0; - return __comedi_device_detach(dev); + return; + __comedi_device_detach(dev); } int comedi_device_attach(comedi_device * dev, comedi_devconfig * it) @@ -168,7 +161,7 @@ int comedi_device_attach(comedi_device * dev, comedi_devconfig * it) } return -EIO; - attached: +attached: /* do a little post-config cleanup */ ret = postconfig(dev); if (ret < 0) { @@ -182,6 +175,7 @@ int comedi_device_attach(comedi_device * dev, comedi_devconfig * it) } smp_wmb(); dev->attached = 1; + module_put(dev->driver->module); return 0; } @@ -200,10 +194,13 @@ int comedi_driver_unregister(comedi_driver * driver) int i; /* check for devices using this driver */ - for (i = 0; i < COMEDI_NDEVICES; i++) { + for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(i); comedi_device *dev; - dev = comedi_devices + i; + if(dev_file_info == NULL) continue; + dev = dev_file_info->device; + mutex_lock(&dev->mutex); if (dev->attached && dev->driver == driver) { if (dev->use_count) @@ -227,16 +224,6 @@ int comedi_driver_unregister(comedi_driver * driver) return -EINVAL; } -comedi_device *comedi_allocate_dev(comedi_driver * driver) -{ - return NULL; -} - -void comedi_deallocate_dev(comedi_device * dev) -{ - -} - static int postconfig(comedi_device * dev) { int i; @@ -254,12 +241,8 @@ static int postconfig(comedi_device * dev) s->len_chanlist = 1; if (s->do_cmd) { - unsigned minor; - dev_t devt; - struct device *csdev; - BUG_ON((s->subdev_flags & (SDF_CMD_READ | - SDF_CMD_WRITE)) == 0); + SDF_CMD_WRITE)) == 0); BUG_ON(!s->do_cmdtest); async = kzalloc(sizeof(comedi_async), GFP_KERNEL); @@ -287,13 +270,7 @@ static int postconfig(comedi_device * dev) if (ret < 0) return ret; } - minor = comedi_construct_minor_for_subdevice(dev, i); - devt = MKDEV(COMEDI_MAJOR, minor); - csdev = COMEDI_DEVICE_CREATE(comedi_class, - dev->class_dev, devt, NULL, "comedi%i_sub%i", - dev->minor, i); - if (!IS_ERR(csdev)) - s->class_dev = csdev; + comedi_alloc_subdevice_minor(dev, s); } if (!s->range_table && !s->range_table_list) @@ -811,3 +788,44 @@ void comedi_reset_async_buf(comedi_async * async) async->events = 0; } + +int comedi_pci_auto_config(const char *board_name, struct pci_dev *pcidev) +{ + comedi_devconfig it; + int minor; + struct comedi_device_file_info *dev_file_info; + int retval; + + minor = comedi_alloc_board_minor(&pcidev->dev); + if(minor < 0) return minor; + pci_set_drvdata(pcidev, (void*)minor); + + dev_file_info = comedi_get_device_file_info(minor); + + memset(&it, 0, sizeof(it)); + strncpy(it.board_name, board_name, COMEDI_NAMELEN); + it.board_name[COMEDI_NAMELEN - 1] = '\0'; + // pci bus + it.options[0] = pcidev->bus->number; + // pci slot + it.options[1] = PCI_SLOT(pcidev->devfn); + + mutex_lock(&dev_file_info->device->mutex); + retval = comedi_device_attach(dev_file_info->device, &it); + mutex_unlock(&dev_file_info->device->mutex); + if(retval < 0) + { + comedi_free_board_minor(minor); + } + return retval; +} + +void comedi_pci_auto_unconfig(struct pci_dev *pcidev) +{ + unsigned long minor = (unsigned long)pci_get_drvdata(pcidev); + struct comedi_device_file_info *dev_file_info; + + BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); + + comedi_free_board_minor(minor); +} diff --git a/comedi/drivers/comedi_bond.c b/comedi/drivers/comedi_bond.c index d7bae245..bd7e3d52 100644 --- a/comedi/drivers/comedi_bond.c +++ b/comedi/drivers/comedi_bond.c @@ -389,7 +389,7 @@ static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen) static int doDevConfig(comedi_device * dev, comedi_devconfig * it) { int i; - comedi_t *devs_opened[COMEDI_NDEVICES]; + comedi_t *devs_opened[COMEDI_NUM_BOARD_MINORS]; memset(devs_opened, 0, sizeof(devs_opened)); devpriv->name[0] = 0;; @@ -402,7 +402,7 @@ static int doDevConfig(comedi_device * dev, comedi_devconfig * it) int sdev = -1, nchans, tmp; BondedDevice *bdev = 0; - if (minor < 0 || minor > COMEDI_NDEVICES) { + if (minor < 0 || minor > COMEDI_NUM_BOARD_MINORS) { ERROR("Minor %d is invalid!\n", minor); return 0; } diff --git a/comedi/drivers/ni_pcimio.c b/comedi/drivers/ni_pcimio.c index 3067e1a2..436d436c 100644 --- a/comedi/drivers/ni_pcimio.c +++ b/comedi/drivers/ni_pcimio.c @@ -125,6 +125,8 @@ Bugs: #define MAX_N_CALDACS (16+16+2) +#define DRV_NAME "ni_pcimio" + /* The following two tables must be in the same order */ static DEFINE_PCI_DEVICE_TABLE(ni_pci_table) = { {PCI_VENDOR_ID_NATINST, 0x0162, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -1190,13 +1192,41 @@ static const ni_board ni_boards[] = { static int pcimio_attach(comedi_device * dev, comedi_devconfig * it); static int pcimio_detach(comedi_device * dev); static comedi_driver driver_pcimio = { - driver_name:"ni_pcimio", - module:THIS_MODULE, - attach:pcimio_attach, - detach:pcimio_detach, + driver_name: DRV_NAME, + module:THIS_MODULE, + attach:pcimio_attach, + detach:pcimio_detach, +}; +static int ni_pcimio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent); +static void ni_pcimio_pci_remove(struct pci_dev *dev); + +static struct pci_driver ni_pcimio_pci_driver = +{ + .name = DRV_NAME, + .id_table = ni_pci_table, + .probe = &ni_pcimio_pci_probe, + .remove = __devexit_p(&ni_pcimio_pci_remove) }; -COMEDI_INITCLEANUP(driver_pcimio); +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi driver for National Instruments E-series, M-series, and related boards"); +MODULE_LICENSE("GPL"); +static int __init driver_pcimio_init_module(void) +{ + int retval; + + retval = comedi_driver_register(&driver_pcimio); + if(retval < 0) return retval; + return pci_register_driver(&ni_pcimio_pci_driver); +} +static void __exit driver_pcimio_cleanup_module(void) +{ + pci_unregister_driver(&ni_pcimio_pci_driver); + comedi_driver_unregister(&driver_pcimio); +} +module_init(driver_pcimio_init_module); +module_exit(driver_pcimio_cleanup_module); typedef struct { NI_PRIVATE_COMMON} ni_private; @@ -1650,7 +1680,7 @@ static int pcimio_attach(comedi_device * dev, comedi_devconfig * it) } else { printk(" ( irq = %u )", dev->irq); if ((ret = comedi_request_irq(dev->irq, ni_E_interrupt, - NI_E_IRQ_FLAGS, "ni_pcimio", + NI_E_IRQ_FLAGS, DRV_NAME, dev)) < 0) { printk(" irq not available\n"); dev->irq = 0; @@ -1757,3 +1787,16 @@ static int pcimio_dio_change(comedi_device * dev, comedi_subdevice * s, return 0; } + +// pci_driver functions + +static int __devinit ni_pcimio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(DRV_NAME, dev); +} + +static void __devexit ni_pcimio_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} diff --git a/comedi/kcomedilib/kcomedilib_main.c b/comedi/kcomedilib/kcomedilib_main.c index bcb14f4d..c209c8b6 100644 --- a/comedi/kcomedilib/kcomedilib_main.c +++ b/comedi/kcomedilib/kcomedilib_main.c @@ -44,6 +44,7 @@ MODULE_LICENSE("GPL"); comedi_t *comedi_open(const char *filename) { + struct comedi_device_file_info *dev_file_info; comedi_device *dev; unsigned int minor; @@ -52,12 +53,15 @@ comedi_t *comedi_open(const char *filename) minor = simple_strtoul(filename + 11, NULL, 0); - if (minor >= COMEDI_NDEVICES) + if (minor >= COMEDI_NUM_BOARD_MINORS) return NULL; - dev = comedi_get_device_by_minor(minor); + dev_file_info = comedi_get_device_file_info(minor); + if(dev_file_info == NULL) + return NULL; + dev = dev_file_info->device; - if (!dev->attached) + if(dev == NULL || !dev->attached) return NULL; if (!try_module_get(dev->driver->module)) @@ -68,14 +72,18 @@ comedi_t *comedi_open(const char *filename) comedi_t *comedi_open_old(unsigned int minor) { + struct comedi_device_file_info *dev_file_info; comedi_device *dev; - if (minor >= COMEDI_NDEVICES) + if (minor >= COMEDI_NUM_MINORS) return NULL; - dev = comedi_get_device_by_minor(minor); + dev_file_info = comedi_get_device_file_info(minor); + if(dev_file_info == NULL) + return NULL; + dev = dev_file_info->device; - if (!dev->attached) + if(dev == NULL || !dev->attached) return NULL; return (comedi_t *) dev; diff --git a/comedi/proc.c b/comedi/proc.c index 472367a0..bd276d2c 100644 --- a/comedi/proc.c +++ b/comedi/proc.c @@ -51,10 +51,13 @@ int comedi_read_procmem(char *buf, char **start, off_t offset, int len, "format string: %s\n", "\"%2d: %-20s %-20s %4d\",i,driver_name,board_name,n_subdevices"); - for (i = 0; i < COMEDI_NDEVICES; i++) { + for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { + struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(i); comedi_device *dev; - dev = comedi_devices + i; + if(dev_file_info == NULL) continue; + dev = dev_file_info->device; + if (dev->attached) { devices_q = 1; l += sprintf(buf + l, "%2d: %-20s %-20s %4d\n", diff --git a/comedi/range.c b/comedi/range.c index 09f54594..54ff2bbb 100644 --- a/comedi/range.c +++ b/comedi/range.c @@ -47,27 +47,20 @@ const comedi_lrange range_unknown = { 1, {{0, 1000000, UNIT_none}} }; int do_rangeinfo_ioctl(comedi_device * dev, comedi_rangeinfo * arg) { comedi_rangeinfo it; - int minor, subd, chan; + int subd, chan; const comedi_lrange *lr; comedi_subdevice *s; - comedi_device *query_dev; if (copy_from_user(&it, arg, sizeof(comedi_rangeinfo))) return -EFAULT; - /* FIXME why do we have to support queries to devices that are different - * than the one passed as the dev argument? */ - minor = (it.range_type >> 28) & 0xf; subd = (it.range_type >> 24) & 0xf; chan = (it.range_type >> 16) & 0xff; - if (minor > COMEDI_NDEVICES) + if (!dev->attached) return -EINVAL; - query_dev = comedi_devices + minor; - if (!query_dev->attached) + if (subd >= dev->n_subdevices) return -EINVAL; - if (subd >= query_dev->n_subdevices) - return -EINVAL; - s = query_dev->subdevices + subd; + s = dev->subdevices + subd; if (s->range_table) { lr = s->range_table; } else if (s->range_table_list) { diff --git a/include/linux/comedidev.h b/include/linux/comedidev.h index 26e836f1..0e1bc3f0 100644 --- a/include/linux/comedidev.h +++ b/include/linux/comedidev.h @@ -87,6 +87,11 @@ #define PCI_VENDOR_ID_CONTEC 0x1221 #define PCI_VENDOR_ID_MEILHAUS 0x1402 +#define COMEDI_NUM_MINORS 0x100 +#define COMEDI_NUM_LEGACY_MINORS 0x10 +#define COMEDI_NUM_BOARD_MINORS 0x30 +#define COMEDI_FIRST_SUBDEVICE_MINOR COMEDI_NUM_BOARD_MINORS + typedef struct comedi_device_struct comedi_device; typedef struct comedi_subdevice_struct comedi_subdevice; typedef struct comedi_async_struct comedi_async; @@ -150,7 +155,8 @@ struct comedi_subdevice_struct { unsigned int state; - struct device *class_dev; + device_create_result_type *class_dev; + int minor; }; struct comedi_buf_page { @@ -222,8 +228,8 @@ struct comedi_device_struct { comedi_driver *driver; void *private; - struct device *class_dev; - unsigned minor; + device_create_result_type *class_dev; + int minor; /* hw_dev is passed to dma_alloc_coherent when allocating async buffers for subdevices that have async_dma_dir set to something other than DMA_NONE */ struct device *hw_dev; @@ -252,13 +258,12 @@ struct comedi_device_struct { void (*close) (comedi_device * dev); }; -struct comedi_inode_private { +struct comedi_device_file_info { comedi_device *device; - comedi_subdevice *subdevice; + comedi_subdevice *read_subdevice; + comedi_subdevice *write_subdevice; }; -extern comedi_device *comedi_devices; - #ifdef CONFIG_COMEDI_DEBUG extern int comedi_debug; #else @@ -281,83 +286,28 @@ enum comedi_minor_bits { }; static const unsigned COMEDI_SUBDEVICE_MINOR_SHIFT = 4; static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1; -static const unsigned COMEDI_NUM_MINORS = 0x100; -static inline comedi_device *comedi_get_device_by_minor(unsigned minor) -{ - unsigned device_index; - if (minor >= COMEDI_NUM_MINORS) - return NULL; - device_index = minor & COMEDI_DEVICE_MINOR_MASK; - if (device_index >= COMEDI_NDEVICES) - return NULL; - return comedi_devices + device_index; -} +struct comedi_device_file_info* comedi_get_device_file_info(unsigned minor); -static inline comedi_subdevice *comedi_get_subdevice_by_minor(unsigned minor) +static inline comedi_subdevice* comedi_get_read_subdevice(const struct comedi_device_file_info *info) { - unsigned subdevice_index; - comedi_device *dev; - - if ((minor & COMEDI_SUBDEVICE_MINOR_MASK) == 0) - return NULL; - dev = comedi_get_device_by_minor(minor); - if (dev == NULL) - return NULL; - subdevice_index = - ((minor & COMEDI_SUBDEVICE_MINOR_MASK) >> - COMEDI_SUBDEVICE_MINOR_SHIFT) - COMEDI_SUBDEVICE_MINOR_OFFSET; - if (subdevice_index >= dev->n_subdevices) - return NULL; - return dev->subdevices + subdevice_index; + if(info->read_subdevice) return info->read_subdevice; + if(info->device == NULL) return NULL; + return info->device->read_subdev; } -static inline comedi_subdevice *comedi_get_read_subdevice(comedi_device * dev, - unsigned minor) +static inline comedi_subdevice* comedi_get_write_subdevice(const struct comedi_device_file_info *info) { - comedi_subdevice *read_subdev = comedi_get_subdevice_by_minor(minor); - if (read_subdev == NULL) { - read_subdev = dev->read_subdev; - } - if (read_subdev == NULL || read_subdev->async == NULL - || (read_subdev->subdev_flags & SDF_CMD_READ) == 0) - return NULL; - return read_subdev; + if(info->write_subdevice) return info->write_subdevice; + if(info->device == NULL) return NULL; + return info->device->write_subdev; } -static inline comedi_subdevice *comedi_get_write_subdevice(comedi_device * dev, - unsigned minor) -{ - comedi_subdevice *write_subdev = comedi_get_subdevice_by_minor(minor); - if (write_subdev == NULL) { - write_subdev = dev->write_subdev; - } - if (write_subdev == NULL || write_subdev->async == NULL - || (write_subdev->subdev_flags & SDF_CMD_WRITE) == 0) - return NULL; - return write_subdev; -} - -static inline unsigned comedi_construct_minor_for_subdevice(comedi_device * dev, - unsigned subdevice_index) -{ - unsigned minor = 0; - minor |= dev->minor & COMEDI_DEVICE_MINOR_MASK; - minor |= ((subdevice_index + - COMEDI_SUBDEVICE_MINOR_OFFSET) << - COMEDI_SUBDEVICE_MINOR_SHIFT) & COMEDI_SUBDEVICE_MINOR_MASK; - BUG_ON(minor >= COMEDI_NUM_MINORS); - return minor; -} - -int comedi_device_detach(comedi_device * dev); +void comedi_device_detach(comedi_device * dev); int comedi_device_attach(comedi_device * dev, comedi_devconfig * it); int comedi_driver_register(comedi_driver *); int comedi_driver_unregister(comedi_driver *); -comedi_device *comedi_allocate_dev(comedi_driver *); -void comedi_deallocate_dev(comedi_device *); - void init_polling(void); void cleanup_polling(void); void start_polling(comedi_device *); @@ -444,6 +394,7 @@ static inline int alloc_subdevices(comedi_device * dev, dev->subdevices[i].device = dev; dev->subdevices[i].async_dma_dir = DMA_NONE; spin_lock_init(&dev->subdevices[i].spin_lock); + dev->subdevices[i].minor = -1; } return 0; } @@ -529,6 +480,13 @@ static inline void *comedi_aux_data(int options[], int n) return (void *)address; } +int comedi_alloc_board_minor(struct device *hardware_device); +void comedi_free_board_minor(unsigned minor); +int comedi_alloc_subdevice_minor(comedi_device *dev, comedi_subdevice *s); +void comedi_free_subdevice_minor(comedi_subdevice *s); +int comedi_pci_auto_config(const char *board_name, struct pci_dev *pcidev); +void comedi_pci_auto_unconfig(struct pci_dev *pcidev); + //#ifdef CONFIG_COMEDI_RT #include //#endif diff --git a/include/linux/device.h b/include/linux/device.h index 2b7a17f2..79fc252d 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -87,18 +87,21 @@ static inline void device_destroy(struct class *cs, dev_t devt) (struct class *)class_simple_create(owner, name) #define class_destroy(cs) \ class_simple_destroy((struct class_simple *)(cs)) + +typedef struct class_device device_create_result_type; #define COMEDI_DEVICE_CREATE(cs, parent, devt, drvdata, fmt...) \ - (struct device *)class_simple_device_add((struct class_simple *)(cs), \ + class_simple_device_add((struct class_simple *)(cs), \ devt, NULL, fmt) #define device_destroy(cs, devt) \ class_simple_device_remove(devt) #else - +/* versions earlier than 2.6.15 are currently broken as of 2008-10-16 FMH*/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) +typedef struct class_device device_create_result_type; #define COMEDI_DEVICE_CREATE(cs, parent, devt, drvdata, fmt...) \ - (struct device *)class_device_create(cs, devt, NULL, fmt) + class_device_create(cs, devt, NULL, fmt) #define device_destroy(cs, devt) \ class_device_destroy(cs, devt) @@ -107,9 +110,10 @@ static inline void device_destroy(struct class *cs, dev_t devt) exactly which kernel version it was fixed in. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +typedef struct class_device device_create_result_type; #define COMEDI_DEVICE_CREATE(cs, parent, devt, drvdata, fmt...) \ - (struct device *)class_device_create( \ - cs, (struct class_device *)parent, devt, NULL, fmt) + class_device_create( \ + cs, parent, devt, NULL, fmt) #define device_destroy(cs, devt) \ class_device_destroy(cs, devt) @@ -117,6 +121,7 @@ exactly which kernel version it was fixed in. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +typedef struct device device_create_result_type; #define COMEDI_DEVICE_CREATE(cs, parent, devt, drvdata, fmt...) \ device_create(cs, parent, devt, fmt) @@ -124,6 +129,7 @@ exactly which kernel version it was fixed in. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) +typedef struct device device_create_result_type; #define COMEDI_DEVICE_CREATE(cs, parent, devt, drvdata, fmt...) \ device_create_drvdata(cs, parent, devt, drvdata, fmt)