diff options
-rw-r--r-- | drivers/staging/vme/devices/vme_user.c | 45 | ||||
-rw-r--r-- | drivers/staging/vme/vme.c | 202 | ||||
-rw-r--r-- | drivers/staging/vme/vme.h | 23 | ||||
-rw-r--r-- | drivers/staging/vme/vme_api.txt | 60 | ||||
-rw-r--r-- | drivers/staging/vme/vme_bridge.h | 5 |
5 files changed, 169 insertions, 166 deletions
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index bb33dc2..c658ce9 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -135,6 +135,7 @@ static ssize_t vme_user_write(struct file *, const char __user *, size_t, static loff_t vme_user_llseek(struct file *, loff_t, int); static long vme_user_unlocked_ioctl(struct file *, unsigned int, unsigned long); +static int vme_user_match(struct vme_dev *); static int __devinit vme_user_probe(struct vme_dev *); static int __devexit vme_user_remove(struct vme_dev *); @@ -620,6 +621,7 @@ static void buf_unalloc(int num) static struct vme_driver vme_user_driver = { .name = driver_name, + .match = vme_user_match, .probe = vme_user_probe, .remove = __devexit_p(vme_user_remove), }; @@ -628,8 +630,6 @@ static struct vme_driver vme_user_driver = { static int __init vme_user_init(void) { int retval = 0; - int i; - struct vme_device_id *ids; printk(KERN_INFO "VME User Space Access Driver\n"); @@ -649,41 +649,30 @@ static int __init vme_user_init(void) bus_num = USER_BUS_MAX; } - - /* Dynamically create the bind table based on module parameters */ - ids = kzalloc(sizeof(struct vme_device_id) * (bus_num + 1), GFP_KERNEL); - if (ids == NULL) { - printk(KERN_ERR "%s: Unable to allocate ID table\n", - driver_name); - retval = -ENOMEM; - goto err_id; - } - - for (i = 0; i < bus_num; i++) { - ids[i].bus = bus[i]; - /* - * We register the driver against the slot occupied by *this* - * card, since it's really a low level way of controlling - * the VME bridge - */ - ids[i].slot = VME_SLOT_CURRENT; - } - - vme_user_driver.bind_table = ids; - - retval = vme_register_driver(&vme_user_driver); + /* + * Here we just register the maximum number of devices we can and + * leave vme_user_match() to allow only 1 to go through to probe(). + * This way, if we later want to allow multiple user access devices, + * we just change the code in vme_user_match(). + */ + retval = vme_register_driver(&vme_user_driver, VME_MAX_SLOTS); if (retval != 0) goto err_reg; return retval; err_reg: - kfree(ids); -err_id: err_nocard: return retval; } +static int vme_user_match(struct vme_dev *vdev) +{ + if (vdev->id.num >= USER_BUS_MAX) + return 0; + return 1; +} + /* * In this simple access driver, the old behaviour is being preserved as much * as practical. We will therefore reserve the buffers and request the images @@ -896,8 +885,6 @@ static int __devexit vme_user_remove(struct vme_dev *dev) static void __exit vme_user_exit(void) { vme_unregister_driver(&vme_user_driver); - - kfree(vme_user_driver.bind_table); } diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c index 4bef789..2abb9eb 100644 --- a/drivers/staging/vme/vme.c +++ b/drivers/staging/vme/vme.c @@ -1317,6 +1317,7 @@ static int vme_add_bus(struct vme_bridge *bridge) if ((vme_bus_numbers & (1 << i)) == 0) { vme_bus_numbers |= (1 << i); bridge->num = i; + INIT_LIST_HEAD(&bridge->devices); list_add_tail(&bridge->bus_list, &vme_bus_list); ret = 0; break; @@ -1329,8 +1330,16 @@ static int vme_add_bus(struct vme_bridge *bridge) static void vme_remove_bus(struct vme_bridge *bridge) { + struct vme_dev *vdev; + struct vme_dev *tmp; + mutex_lock(&vme_buses_lock); vme_bus_numbers &= ~(1 << bridge->num); + list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) { + list_del(&vdev->drv_list); + list_del(&vdev->bridge_list); + device_unregister(&vdev->dev); + } list_del(&bridge->bus_list); mutex_unlock(&vme_buses_lock); } @@ -1342,153 +1351,153 @@ static void vme_dev_release(struct device *dev) int vme_register_bridge(struct vme_bridge *bridge) { - struct vme_dev *vdev; - int retval; - int i; + return vme_add_bus(bridge); +} +EXPORT_SYMBOL(vme_register_bridge); - retval = vme_add_bus(bridge); - if (retval) - return retval; +void vme_unregister_bridge(struct vme_bridge *bridge) +{ + vme_remove_bus(bridge); +} +EXPORT_SYMBOL(vme_unregister_bridge); - /* This creates 32 vme "slot" devices. This equates to a slot for each - * ID available in a system conforming to the ANSI/VITA 1-1994 - * specification. - */ - for (i = 0; i < VME_SLOTS_MAX; i++) { - bridge->dev[i] = kzalloc(sizeof(struct vme_dev), GFP_KERNEL); - if (!bridge->dev[i]) { - retval = -ENOMEM; +/* - Driver Registration --------------------------------------------------- */ + +static int __vme_register_driver_bus(struct vme_driver *drv, + struct vme_bridge *bridge, unsigned int ndevs) +{ + int err; + unsigned int i; + struct vme_dev *vdev; + struct vme_dev *tmp; + + for (i = 0; i < ndevs; i++) { + vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL); + if (!vdev) { + err = -ENOMEM; goto err_devalloc; } - vdev = bridge->dev[i]; - memset(vdev, 0, sizeof(struct vme_dev)); - + vdev->id.num = i; vdev->id.bus = bridge->num; vdev->id.slot = i + 1; vdev->bridge = bridge; + vdev->dev.platform_data = drv; + vdev->dev.release = vme_dev_release; vdev->dev.parent = bridge->parent; vdev->dev.bus = &vme_bus_type; - vdev->dev.release = vme_dev_release; - /* - * We save a pointer to the bridge in platform_data so that we - * can get to it later. We keep driver_data for use by the - * driver that binds against the slot - */ - vdev->dev.platform_data = bridge; - dev_set_name(&vdev->dev, "vme-%x.%x", bridge->num, i + 1); + dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, vdev->id.bus, + vdev->id.num); - retval = device_register(&vdev->dev); - if (retval) + err = device_register(&vdev->dev); + if (err) goto err_reg; - } - return retval; + if (vdev->dev.platform_data) { + list_add_tail(&vdev->drv_list, &drv->devices); + list_add_tail(&vdev->bridge_list, &bridge->devices); + } else + device_unregister(&vdev->dev); + } + return 0; err_reg: kfree(vdev); err_devalloc: - while (--i >= 0) { - vdev = bridge->dev[i]; + list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) { + list_del(&vdev->drv_list); + list_del(&vdev->bridge_list); device_unregister(&vdev->dev); } - vme_remove_bus(bridge); - return retval; + return err; } -EXPORT_SYMBOL(vme_register_bridge); -void vme_unregister_bridge(struct vme_bridge *bridge) +static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs) { - int i; - struct vme_dev *vdev; - + struct vme_bridge *bridge; + int err = 0; - for (i = 0; i < VME_SLOTS_MAX; i++) { - vdev = bridge->dev[i]; - device_unregister(&vdev->dev); + mutex_lock(&vme_buses_lock); + list_for_each_entry(bridge, &vme_bus_list, bus_list) { + /* + * This cannot cause trouble as we already have vme_buses_lock + * and if the bridge is removed, it will have to go through + * vme_unregister_bridge() to do it (which calls remove() on + * the bridge which in turn tries to acquire vme_buses_lock and + * will have to wait). The probe() called after device + * registration in __vme_register_driver below will also fail + * as the bridge is being removed (since the probe() calls + * vme_bridge_get()). + */ + err = __vme_register_driver_bus(drv, bridge, ndevs); + if (err) + break; } - vme_remove_bus(bridge); + mutex_unlock(&vme_buses_lock); + return err; } -EXPORT_SYMBOL(vme_unregister_bridge); - - -/* - Driver Registration --------------------------------------------------- */ -int vme_register_driver(struct vme_driver *drv) +int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) { + int err; + drv->driver.name = drv->name; drv->driver.bus = &vme_bus_type; + INIT_LIST_HEAD(&drv->devices); + + err = driver_register(&drv->driver); + if (err) + return err; - return driver_register(&drv->driver); + err = __vme_register_driver(drv, ndevs); + if (err) + driver_unregister(&drv->driver); + + return err; } EXPORT_SYMBOL(vme_register_driver); void vme_unregister_driver(struct vme_driver *drv) { + struct vme_dev *dev, *dev_tmp; + + mutex_lock(&vme_buses_lock); + list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) { + list_del(&dev->drv_list); + list_del(&dev->bridge_list); + device_unregister(&dev->dev); + } + mutex_unlock(&vme_buses_lock); + driver_unregister(&drv->driver); } EXPORT_SYMBOL(vme_unregister_driver); /* - Bus Registration ------------------------------------------------------ */ -static struct vme_driver *dev_to_vme_driver(struct device *dev) -{ - if (dev->driver == NULL) - printk(KERN_ERR "Bugger dev->driver is NULL\n"); - - return container_of(dev->driver, struct vme_driver, driver); -} - static int vme_bus_match(struct device *dev, struct device_driver *drv) { - struct vme_dev *vdev; - struct vme_bridge *bridge; - struct vme_driver *driver; - int i, num; - - vdev = dev_to_vme_dev(dev); - bridge = vdev->bridge; - driver = container_of(drv, struct vme_driver, driver); + struct vme_driver *vme_drv; - num = vdev->id.slot; - if (num <= 0 || num >= VME_SLOTS_MAX) - goto err_dev; - - if (driver->bind_table == NULL) { - dev_err(dev, "Bind table NULL\n"); - goto err_table; - } + vme_drv = container_of(drv, struct vme_driver, driver); - i = 0; - while ((driver->bind_table[i].bus != 0) || - (driver->bind_table[i].slot != 0)) { + if (dev->platform_data == vme_drv) { + struct vme_dev *vdev = dev_to_vme_dev(dev); - if (bridge->num == driver->bind_table[i].bus) { - if (num == driver->bind_table[i].slot) - return 1; + if (vme_drv->match && vme_drv->match(vdev)) + return 1; - if (driver->bind_table[i].slot == VME_SLOT_ALL) - return 1; - - if ((driver->bind_table[i].slot == VME_SLOT_CURRENT) && - (num == vme_slot_get(vdev))) - return 1; - } - i++; + dev->platform_data = NULL; } - -err_dev: -err_table: return 0; } static int vme_bus_probe(struct device *dev) { - struct vme_driver *driver; - struct vme_dev *vdev; int retval = -ENODEV; + struct vme_driver *driver; + struct vme_dev *vdev = dev_to_vme_dev(dev); - driver = dev_to_vme_driver(dev); - vdev = dev_to_vme_dev(dev); + driver = dev->platform_data; if (driver->probe != NULL) retval = driver->probe(vdev); @@ -1498,12 +1507,11 @@ static int vme_bus_probe(struct device *dev) static int vme_bus_remove(struct device *dev) { - struct vme_driver *driver; - struct vme_dev *vdev; int retval = -ENODEV; + struct vme_driver *driver; + struct vme_dev *vdev = dev_to_vme_dev(dev); - driver = dev_to_vme_driver(dev); - vdev = dev_to_vme_dev(dev); + driver = dev->platform_data; if (driver->remove != NULL) retval = driver->remove(vdev); diff --git a/drivers/staging/vme/vme.h b/drivers/staging/vme/vme.h index d442cce..95224d7 100644 --- a/drivers/staging/vme/vme.h +++ b/drivers/staging/vme/vme.h @@ -88,15 +88,21 @@ struct vme_resource { extern struct bus_type vme_bus_type; +/* VME_MAX_BRIDGES comes from the type of vme_bus_numbers */ +#define VME_MAX_BRIDGES (sizeof(unsigned int)*8) +#define VME_MAX_SLOTS 32 + #define VME_SLOT_CURRENT -1 #define VME_SLOT_ALL -2 /** * VME device identifier structure + * @num: The device ID (ranges from 0 to N-1 for N devices) * @bus: The bus ID of the bus the device is on * @slot: The slot this device is plugged into */ struct vme_device_id { + int num; int bus; int slot; }; @@ -106,21 +112,26 @@ struct vme_device_id { * @id: The ID of the device (currently the bus and slot number) * @bridge: Pointer to the bridge device this device is on * @dev: Internal device structure + * @drv_list: List of devices (per driver) + * @bridge_list: List of devices (per bridge) */ struct vme_dev { struct vme_device_id id; struct vme_bridge *bridge; struct device dev; + struct list_head drv_list; + struct list_head bridge_list; }; struct vme_driver { struct list_head node; const char *name; - const struct vme_device_id *bind_table; - int (*probe) (struct vme_dev *); - int (*remove) (struct vme_dev *); - void (*shutdown) (void); - struct device_driver driver; + int (*match)(struct vme_dev *); + int (*probe)(struct vme_dev *); + int (*remove)(struct vme_dev *); + void (*shutdown)(void); + struct device_driver driver; + struct list_head devices; }; void *vme_alloc_consistent(struct vme_resource *, size_t, dma_addr_t *); @@ -179,7 +190,7 @@ void vme_lm_free(struct vme_resource *); int vme_slot_get(struct vme_dev *); -int vme_register_driver(struct vme_driver *); +int vme_register_driver(struct vme_driver *, unsigned int); void vme_unregister_driver(struct vme_driver *); diff --git a/drivers/staging/vme/vme_api.txt b/drivers/staging/vme/vme_api.txt index 03f4813..53abf7e 100644 --- a/drivers/staging/vme/vme_api.txt +++ b/drivers/staging/vme/vme_api.txt @@ -18,24 +18,37 @@ registration function. The structure is as follows: struct vme_driver { struct list_head node; - char *name; - const struct vme_device_id *bind_table; - int (*probe) (struct vme_dev *); - int (*remove) (struct vme_dev *); - void (*shutdown) (void); - struct device_driver driver; + const char *name; + int (*match)(struct vme_dev *); + int (*probe)(struct vme_dev *); + int (*remove)(struct vme_dev *); + void (*shutdown)(void); + struct device_driver driver; + struct list_head devices; + unsigned int ndev; }; -At the minimum, the '.name', '.probe' and '.bind_table' elements of this -structure should be correctly set. The '.name' element is a pointer to a string -holding the device driver's name. The '.probe' element should contain a pointer -to the probe routine. +At the minimum, the '.name', '.match' and '.probe' elements of this structure +should be correctly set. The '.name' element is a pointer to a string holding +the device driver's name. -The arguments of the probe routine are as follows: +The '.match' function allows controlling the number of devices that need to +be registered. The match function should return 1 if a device should be +probed and 0 otherwise. This example match function (from vme_user.c) limits +the number of devices probed to one: - probe(struct vme_dev *dev); + #define USER_BUS_MAX 1 + ... + static int vme_user_match(struct vme_dev *vdev) + { + if (vdev->id.num >= USER_BUS_MAX) + return 0; + return 1; + } -The device structure looks like the following: +The '.probe' element should contain a pointer to the probe routine. The +probe routine is passed a 'struct vme_dev' pointer as an argument. The +'struct vme_dev' structure looks like the following: struct vme_dev { struct vme_device_id id; @@ -49,25 +62,12 @@ contains information useful for the probe function: struct vme_device_id { int bus; int slot; + int num; }; -'bus' is the number of the bus the device being probed is on. 'slot' refers -to the specific slot on the VME bus. - -The '.bind_table' is a pointer to an array of type 'vme_device_id': - - struct vme_device_id { - int bus; - int slot; - }; - -Each structure in this array should provide a bus and slot number where the core -should probe, using the driver's probe routine, for a device on the specified -VME bus. - -The VME subsystem supports a single VME driver per 'slot'. There are considered -to be 32 slots per bus, one for each slot-ID as defined in the ANSI/VITA 1-1994 -specification and are analogious to the physical slots on the VME backplane. +Here, 'bus' is the number of the bus the device being probed is on. 'slot' +refers to the specific slot on the VME bus. The 'num' field refers to the +sequential device ID for this specific driver. A function is also provided to unregister the driver from the VME core and is usually called from the device driver's exit routine: diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/staging/vme/vme_bridge.h index 6dd2f4c..c2deda2 100644 --- a/drivers/staging/vme/vme_bridge.h +++ b/drivers/staging/vme/vme_bridge.h @@ -2,7 +2,6 @@ #define _VME_BRIDGE_H_ #define VME_CRCSR_BUF_SIZE (508*1024) -#define VME_SLOTS_MAX 32 /* * Resource structures */ @@ -108,15 +107,13 @@ struct vme_bridge { struct list_head lm_resources; struct list_head vme_errors; /* List for errors generated on VME */ + struct list_head devices; /* List of devices on this bridge */ /* Bridge Info - XXX Move to private structure? */ struct device *parent; /* Parent device (eg. pdev->dev for PCI) */ void *driver_priv; /* Private pointer for the bridge driver */ struct list_head bus_list; /* list of VME buses */ - struct vme_dev *dev[VME_SLOTS_MAX]; /* Device registered - * on VME bus */ - /* Interrupt callbacks */ struct vme_irq irq[7]; /* Locking for VME irq callback configuration */ |