Staging: Update VME vme_user module
authorMartyn Welch <martyn.welch@gefanuc.com>
Tue, 11 Aug 2009 13:37:15 +0000 (14:37 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 15 Sep 2009 19:02:10 +0000 (12:02 -0700)
* Add ifdef wrapper to vme_user.h
 * Correct Initialisation routine
 * Add remove routine to correct probe routine
 * Remove old test routines

Signed-off-by: Martyn Welch <martyn.welch@gefanuc.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/vme/devices/vme_user.c
drivers/staging/vme/devices/vme_user.h

index 10294ab1c404abbd3b87135e4fb9accf88e3cd30..78912883d1533d38e6c085b651cd09c4615e1444 100644 (file)
 #include "../vme.h"
 #include "vme_user.h"
 
+static char driver_name[] = "vme_user";
+
+static int bus[USER_BUS_MAX];
+static int bus_num;
+
 /* Currently Documentation/devices.txt defines the following for VME:
  *
  * 221 char    VME bus
  * defined above and try to support at least some of the interface from
  * http://www.vmelinux.org/ as an alternative drive can be written providing a
  * saner interface later.
+ *
+ * The vmelinux.org driver never supported slave images, the devices reserved
+ * for slaves were repurposed to support all 8 master images on the UniverseII!
+ * We shall support 4 masters and 4 slaves with this driver.
  */
 #define VME_MAJOR      221     /* VME Major Device Number */
 #define VME_DEVS       9       /* Number of dev entries */
@@ -107,7 +116,6 @@ struct cdev *vme_user_cdev;         /* Character device */
 struct class *vme_user_sysfs_class;    /* Sysfs class */
 struct device *vme_user_bridge;                /* Pointer to the bridge device */
 
-static char driver_name[] = "vme_user";
 
 static const int type[VME_DEVS] = {    MASTER_MINOR,   MASTER_MINOR,
                                        MASTER_MINOR,   MASTER_MINOR,
@@ -125,7 +133,8 @@ static loff_t vme_user_llseek(struct file *, loff_t, int);
 static int vme_user_ioctl(struct inode *, struct file *, unsigned int,
        unsigned long);
 
-static int __init vme_user_probe(struct device *dev);
+static int __init vme_user_probe(struct device *, int, int);
+static int __exit vme_user_remove(struct device *, int, int);
 
 static struct file_operations vme_user_fops = {
         .open = vme_user_open,
@@ -151,61 +160,6 @@ static void reset_counters(void)
         statistics.timeouts = 0;
 }
 
-void lmcall(int monitor)
-{
-       printk("Caught Location Monitor %d access\n", monitor);
-}
-
-static void tests(void)
-{
-       struct vme_resource *dma_res;
-       struct vme_dma_list *dma_list;
-       struct vme_dma_attr *pattern_attr, *vme_attr;
-
-       int retval;
-       unsigned int data;
-
-       printk("Running VME DMA test\n");
-       dma_res = vme_request_dma(vme_user_bridge);
-       dma_list = vme_new_dma_list(dma_res);
-       pattern_attr = vme_dma_pattern_attribute(0x0,
-               VME_DMA_PATTERN_WORD |
-                       VME_DMA_PATTERN_INCREMENT);
-       vme_attr = vme_dma_vme_attribute(0x10000, VME_A32,
-               VME_SCT, VME_D32);
-       retval = vme_dma_list_add(dma_list, pattern_attr,
-               vme_attr, 0x10000);
-#if 0
-       vme_dma_free_attribute(vme_attr);
-       vme_attr = vme_dma_vme_attribute(0x20000, VME_A32,
-               VME_SCT, VME_D32);
-       retval = vme_dma_list_add(dma_list, pattern_attr,
-               vme_attr, 0x10000);
-#endif
-       retval = vme_dma_list_exec(dma_list);
-       vme_dma_free_attribute(pattern_attr);
-       vme_dma_free_attribute(vme_attr);
-       vme_dma_list_free(dma_list);
-#if 0
-       printk("Generating a VME interrupt\n");
-       vme_generate_irq(dma_res, 0x3, 0xaa);
-       printk("Interrupt returned\n");
-#endif
-       vme_dma_free(dma_res);
-
-       /* Attempt RMW */
-       data = vme_master_rmw(image[0].resource, 0x80000000, 0x00000000,
-               0x80000000, 0);
-       printk("RMW returned 0x%8.8x\n", data);
-
-
-       /* Location Monitor */
-       printk("vme_lm_set:%d\n", vme_lm_set(vme_user_bridge, 0x60000, VME_A32, VME_SCT | VME_USER | VME_DATA));
-       printk("vme_lm_attach:%d\n", vme_lm_attach(vme_user_bridge, 0, lmcall));
-
-       printk("Board in VME slot:%d\n", vme_slot_get(vme_user_bridge));
-}
-
 static int vme_user_open(struct inode *inode, struct file *file)
 {
        int err;
@@ -451,57 +405,118 @@ static loff_t vme_user_llseek(struct file *file, loff_t off, int whence)
        return -EINVAL;
 }
 
+/*
+ * The ioctls provided by the old VME access method (the one at vmelinux.org)
+ * are most certainly wrong as the effectively push the registers layout
+ * through to user space. Given that the VME core can handle multiple bridges,
+ * with different register layouts this is most certainly not the way to go.
+ *
+ * We aren't using the structures defined in the Motorola driver either - these
+ * are also quite low level, however we should use the definitions that have
+ * already been defined.
+ */
 static int vme_user_ioctl(struct inode *inode, struct file *file,
        unsigned int cmd, unsigned long arg)
 {
+       struct vme_master master;
+       struct vme_slave slave;
+       unsigned long copied;
        unsigned int minor = MINOR(inode->i_rdev);
-#if 0
-       int ret_val;
-#endif
-       unsigned long copyRet;
-       vme_slave_t slave;
+       int retval;
+       dma_addr_t pci_addr;
 
        statistics.ioctls++;
+
        switch (type[minor]) {
        case CONTROL_MINOR:
                break;
        case MASTER_MINOR:
-               break;
-       case SLAVE_MINOR:
                switch (cmd) {
-               case VME_SET_SLAVE:
+               case VME_GET_MASTER:
+                       memset(&master, 0, sizeof(struct vme_master));
+
+                       /* XXX  We do not want to push aspace, cycle and width
+                        *      to userspace as they are
+                        */
+                       retval = vme_master_get(image[minor].resource,
+                               &(master.enable), &(master.vme_addr),
+                               &(master.size), &(master.aspace),
+                               &(master.cycle), &(master.dwidth));
+
+                       copied = copy_to_user((char *)arg, &master,
+                               sizeof(struct vme_master));
+                       if (copied != 0) {
+                               printk(KERN_WARNING "Partial copy to "
+                                       "userspace\n");
+                               return -EFAULT;
+                       }
 
-                       copyRet = copy_from_user(&slave, (char *)arg,
-                               sizeof(slave));
-                       if (copyRet != 0) {
+                       return retval;
+                       break;
+
+               case VME_SET_MASTER:
+
+                       copied = copy_from_user(&master, (char *)arg,
+                               sizeof(master));
+                       if (copied != 0) {
                                printk(KERN_WARNING "Partial copy from "
                                        "userspace\n");
                                return -EFAULT;
                        }
 
-                       return vme_slave_set(image[minor].resource,
-                               slave.enable, slave.vme_addr, slave.size,
-                               image[minor].pci_buf, slave.aspace,
-                               slave.cycle);
+                       /* XXX  We do not want to push aspace, cycle and width
+                        *      to userspace as they are
+                        */
+                       return vme_master_set(image[minor].resource,
+                               master.enable, master.vme_addr, master.size,
+                               master.aspace, master.cycle, master.dwidth);
 
                        break;
-#if 0
+               }
+               break;
+       case SLAVE_MINOR:
+               switch (cmd) {
                case VME_GET_SLAVE:
-                       vme_slave_t slave;
+                       memset(&slave, 0, sizeof(struct vme_slave));
+
+                       /* XXX  We do not want to push aspace, cycle and width
+                        *      to userspace as they are
+                        */
+                       retval = vme_slave_get(image[minor].resource,
+                               &(slave.enable), &(slave.vme_addr),
+                               &(slave.size), &pci_addr, &(slave.aspace),
+                               &(slave.cycle));
+
+                       copied = copy_to_user((char *)arg, &slave,
+                               sizeof(struct vme_slave));
+                       if (copied != 0) {
+                               printk(KERN_WARNING "Partial copy to "
+                                       "userspace\n");
+                               return -EFAULT;
+                       }
+
+                       return retval;
+                       break;
 
-                       ret_val = vme_slave_get(minor, &iRegs);
+               case VME_SET_SLAVE:
 
-                       copyRet = copy_to_user((char *)arg, &slave,
+                       copied = copy_from_user(&slave, (char *)arg,
                                sizeof(slave));
-                       if (copyRet != 0) {
-                               printk(KERN_WARNING "Partial copy to "
+                       if (copied != 0) {
+                               printk(KERN_WARNING "Partial copy from "
                                        "userspace\n");
                                return -EFAULT;
                        }
 
-                       return ret_val;
+                       /* XXX  We do not want to push aspace, cycle and width
+                        *      to userspace as they are
+                        */
+                       return vme_slave_set(image[minor].resource,
+                               slave.enable, slave.vme_addr, slave.size,
+                               image[minor].pci_buf, slave.aspace,
+                               slave.cycle);
+
                        break;
-#endif
                }
                break;
        }
@@ -538,36 +553,87 @@ static void buf_unalloc (int num)
 static struct vme_driver vme_user_driver = {
         .name = driver_name,
         .probe = vme_user_probe,
+       .remove = vme_user_remove,
 };
 
 
-/*
- * 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
- * here so that we don't have to do it later.
- */
-static int __init vme_bridge_init(void)
+static int __init vme_user_init(void)
 {
-       int retval;
+       int retval = 0;
+       int i;
+       struct vme_device_id *ids;
+
        printk(KERN_INFO "VME User Space Access Driver\n");
-       printk("vme_user_driver:%p\n", &vme_user_driver);
+
+       if (bus_num == 0) {
+               printk(KERN_ERR "%s: No cards, skipping registration\n",
+                       driver_name);
+               goto err_nocard;
+       }
+
+       /* Let's start by supporting one bus, we can support more than one
+        * in future revisions if that ever becomes necessary.
+        */
+       if (bus_num > USER_BUS_MAX) {
+               printk(KERN_ERR "%s: Driver only able to handle %d PIO2 "
+                       "Cards\n", driver_name, USER_BUS_MAX);
+               bus_num = USER_BUS_MAX;
+       }
+
+
+       /* Dynamically create the bind table based on module parameters */
+       ids = kmalloc(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);
+               goto err_id;
+       }
+
+       memset(ids, 0, (sizeof(struct vme_device_id) * (bus_num + 1)));
+
+       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);
-       printk("vme_register_driver returned %d\n", retval);
+       if (retval != 0)
+               goto err_reg;
+
+       return retval;
+
+       vme_unregister_driver(&vme_user_driver);
+err_reg:
+       kfree(ids);
+err_id:
+err_nocard:
        return retval;
 }
 
 /*
- * This structure gets passed a device, this should be the device created at
- * registration.
+ * 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
+ * here so that we don't have to do it later.
  */
-static int __init vme_user_probe(struct device *dev)
+static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
 {
        int i, err;
        char name[8];
 
-       printk("Running vme_user_probe()\n");
-
-       /* Pointer to the bridge device */
+       /* Save pointer to the bridge device */
+       if (vme_user_bridge != NULL) {
+               printk(KERN_ERR "%s: Driver can only be loaded for 1 device\n",
+                       driver_name);
+               err = -EINVAL;
+               goto err_dev;
+       }
        vme_user_bridge = dev;
 
        /* Initialise descriptors */
@@ -610,7 +676,7 @@ static int __init vme_user_probe(struct device *dev)
                if (image[i].resource == NULL) {
                        printk(KERN_WARNING "Unable to allocate slave "
                                "resource\n");
-                       goto err_buf;
+                       goto err_slave;
                }
                image[i].size_buf = PCI_BUF_SIZE;
                image[i].kern_buf = vme_alloc_consistent(image[i].resource,
@@ -621,7 +687,7 @@ static int __init vme_user_probe(struct device *dev)
                        image[i].pci_buf = 0;
                        vme_slave_free(image[i].resource);
                        err = -ENOMEM;
-                       goto err_buf;
+                       goto err_slave;
                }
        }
 
@@ -636,38 +702,7 @@ static int __init vme_user_probe(struct device *dev)
                if (image[i].resource == NULL) {
                        printk(KERN_WARNING "Unable to allocate master "
                                "resource\n");
-                       goto err_buf;
-               }
-               image[i].size_buf = PAGE_SIZE;
-               image[i].kern_buf = vme_alloc_consistent(image[i].resource,
-                       image[i].size_buf, &(image[i].pci_buf));
-               if (image[i].kern_buf == NULL) {
-                       printk(KERN_WARNING "Unable to allocate memory for "
-                               "buffer\n");
-                       image[i].pci_buf = 0;
-                       vme_master_free(image[i].resource);
-                       err = -ENOMEM;
-                       goto err_buf;
-               }
-       }
-
-       /* Setup some debug windows */
-       for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
-               err = vme_slave_set(image[i].resource, 1, 0x4000*(i-4),
-                       0x4000, image[i].pci_buf, VME_A16,
-                       VME_SCT | VME_SUPER | VME_USER | VME_PROG | VME_DATA);
-               if (err != 0) {
-                       printk(KERN_WARNING "Failed to configure window\n");
-                       goto err_buf;
-               }
-       }
-       for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) {
-               err = vme_master_set(image[i].resource, 1,
-                       (0x10000 + (0x10000*i)), 0x10000,
-                       VME_A32, VME_SCT | VME_USER | VME_DATA, VME_D32);
-               if (err != 0) {
-                       printk(KERN_WARNING "Failed to configure window\n");
-                       goto err_buf;
+                       goto err_master;
                }
        }
 
@@ -709,11 +744,6 @@ static int __init vme_user_probe(struct device *dev)
                }
        }
 
-       /* XXX Run tests */
-       /*
-       tests();
-       */
-
        return 0;
 
        /* Ensure counter set correcty to destroy all sysfs devices */
@@ -725,12 +755,21 @@ err_sysfs:
        }
        class_destroy(vme_user_sysfs_class);
 
-       /* Ensure counter set correcty to unalloc all slave buffers */
+       /* Ensure counter set correcty to unalloc all master windows */
+       i = MASTER_MAX + 1;
+err_master:
+       while (i > MASTER_MINOR) {
+               i--;
+               vme_master_free(image[i].resource);
+       }
+
+       /*
+        * Ensure counter set correcty to unalloc all slave windows and buffers
+        */
        i = SLAVE_MAX + 1;
-err_buf:
-       while (i > SLAVE_MINOR){
+err_slave:
+       while (i > SLAVE_MINOR) {
                i--;
-               vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0);
                vme_slave_free(image[i].resource);
                buf_unalloc(i);
        }
@@ -739,10 +778,11 @@ err_class:
 err_char:
        unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS);
 err_region:
+err_dev:
        return err;
 }
 
-static void __exit vme_bridge_exit(void)
+static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot)
 {
        int i;
 
@@ -753,6 +793,8 @@ static void __exit vme_bridge_exit(void)
        class_destroy(vme_user_sysfs_class);
 
        for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
+               vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0);
+               vme_slave_free(image[i].resource);
                buf_unalloc(i);
        }
 
@@ -761,11 +803,24 @@ static void __exit vme_bridge_exit(void)
 
        /* Unregiser the major and minor device numbers */
        unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS);
+
+       return 0;
 }
 
+static void __exit vme_user_exit(void)
+{
+       vme_unregister_driver(&vme_user_driver);
+
+       kfree(vme_user_driver.bind_table);
+}
+
+
+MODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the driver is connected");
+module_param_array(bus, int, &bus_num, 0);
+
 MODULE_DESCRIPTION("VME User Space Access Driver");
 MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com");
 MODULE_LICENSE("GPL");
 
-module_init(vme_bridge_init);
-module_exit(vme_bridge_exit);
+module_init(vme_user_init);
+module_exit(vme_user_exit);
index f352aec35b84108fa972e24f650200513ff551eb..ede77d7e766b54bc02a9bc0a84344b46019f3556 100644 (file)
@@ -1,9 +1,13 @@
+#ifndef _VME_USER_H_
+#define _VME_USER_H_
+
+#define USER_BUS_MAX                  1
 
 /*
  * VMEbus Master Window Configuration Structure
  */
-typedef struct {
-       char enable;                    /* State of Window */
+struct vme_master {
+       int enable;                     /* State of Window */
        unsigned long long vme_addr;    /* Starting Address on the VMEbus */
        unsigned long long size;        /* Window Size */
        vme_address_t aspace;           /* Address Space */
@@ -14,7 +18,7 @@ typedef struct {
        int prefetchSize;               /* Prefetch Read Size (Cache Lines) */
        char wrPostEnable;              /* Write Post State */
 #endif
-} vme_master_t;
+};
 
 
 /*
@@ -26,8 +30,8 @@ typedef struct {
 
 
 /* VMEbus Slave Window Configuration Structure */
-typedef struct {
-       char enable;                    /* State of Window */
+struct vme_slave {
+       int enable;                     /* State of Window */
        unsigned long long vme_addr;    /* Starting Address on the VMEbus */
        unsigned long long size;        /* Window Size */
        vme_address_t aspace;           /* Address Space */
@@ -37,7 +41,12 @@ typedef struct {
        char rmwLock;                   /* Lock PCI during RMW Cycles */
        char data64BitCapable;          /* non-VMEbus capable of 64-bit Data */
 #endif
-} vme_slave_t;
+};
+
+#define VME_GET_SLAVE _IOR(VME_IOC_MAGIC, 1, struct vme_slave)
+#define VME_SET_SLAVE _IOW(VME_IOC_MAGIC, 2, struct vme_slave)
+#define VME_GET_MASTER _IOR(VME_IOC_MAGIC, 3, struct vme_master)
+#define VME_SET_MASTER _IOW(VME_IOC_MAGIC, 4, struct vme_master)
 
-#define VME_SET_SLAVE _IOW(VME_IOC_MAGIC, 10, vme_slave_t)
+#endif /* _VME_USER_H_ */