static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot) { int i; /* Remove sysfs Entries */ for(i=0; i<VME_DEVS; i++) { device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i)); } class_destroy(vme_user_sysfs_class); for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) kfree(image[i].kern_buf); 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); } /* Unregister device driver */ cdev_del(vme_user_cdev); /* Unregiser the major and minor device numbers */ unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS); return 0; }
/* * 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); int retval; dma_addr_t pci_addr; statistics.ioctls++; switch (type[minor]) { case CONTROL_MINOR: break; case MASTER_MINOR: switch (cmd) { 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; } 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; } /* 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; } break; case SLAVE_MINOR: switch (cmd) { case VME_GET_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; case VME_SET_SLAVE: copied = copy_from_user(&slave, (char *)arg, sizeof(slave)); if (copied != 0) { printk(KERN_WARNING "Partial copy from " "userspace\n"); return -EFAULT; } /* 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; } break; } return -EINVAL; }