1f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 2f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * VMEbus User access driver 3f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 466bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn Welch * Author: Martyn Welch <martyn.welch@ge.com> 566bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn Welch * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. 6f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 7f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Based on work by: 8f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Tom Armistead and Ajit Prem 9f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Copyright 2004 Motorola Inc. 10f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 11f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 12f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * This program is free software; you can redistribute it and/or modify it 13f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * under the terms of the GNU General Public License as published by the 14f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Free Software Foundation; either version 2 of the License, or (at your 15f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * option) any later version. 16f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 17f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 18f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/cdev.h> 19f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/delay.h> 20f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/device.h> 21f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/dma-mapping.h> 22f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/errno.h> 23f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/init.h> 24f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/ioctl.h> 25f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/kernel.h> 26f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/mm.h> 27f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/module.h> 28f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/pagemap.h> 29f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/pci.h> 30f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/semaphore.h> 315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 32f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/spinlock.h> 33f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/syscalls.h> 348e2394a981b9258db47f8e223a550d46c6d40cc8Arnd Bergmann#include <linux/mutex.h> 35f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/types.h> 36f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 3745f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos#include <linux/io.h> 3845f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos#include <linux/uaccess.h> 39f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 40f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include "../vme.h" 41f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include "vme_user.h" 42f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 438e2394a981b9258db47f8e223a550d46c6d40cc8Arnd Bergmannstatic DEFINE_MUTEX(vme_user_mutex); 44584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossierstatic const char driver_name[] = "vme_user"; 45238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 460a4b6b0279d903df2d62aaf92edf360fb5312532Manohar Vangastatic int bus[VME_USER_BUS_MAX]; 47c949231838006d7de4ad38be38d9e112826862daEmilio G. Cotastatic unsigned int bus_num; 48238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 49f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* Currently Documentation/devices.txt defines the following for VME: 50f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 51f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 221 char VME bus 5245f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * 0 = /dev/bus/vme/m0 First master image 5345f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * 1 = /dev/bus/vme/m1 Second master image 5445f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * 2 = /dev/bus/vme/m2 Third master image 5545f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * 3 = /dev/bus/vme/m3 Fourth master image 5645f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * 4 = /dev/bus/vme/s0 First slave image 5745f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * 5 = /dev/bus/vme/s1 Second slave image 5845f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * 6 = /dev/bus/vme/s2 Third slave image 5945f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * 7 = /dev/bus/vme/s3 Fourth slave image 6045f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * 8 = /dev/bus/vme/ctl Control 61f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 6245f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * It is expected that all VME bus drivers will use the 6345f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * same interface. For interface documentation see 6445f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos * http://www.vmelinux.org/. 65f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 66f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * However the VME driver at http://www.vmelinux.org/ is rather old and doesn't 67f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * even support the tsi148 chipset (which has 8 master and 8 slave windows). 68f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * We'll run with this or now as far as possible, however it probably makes 69f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * sense to get rid of the old mappings and just do everything dynamically. 70f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 71f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * So for now, we'll restrict the driver to providing 4 masters and 4 slaves as 72f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * defined above and try to support at least some of the interface from 73f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * http://www.vmelinux.org/ as an alternative drive can be written providing a 74f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * saner interface later. 75238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * 76238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * The vmelinux.org driver never supported slave images, the devices reserved 77238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * for slaves were repurposed to support all 8 master images on the UniverseII! 78238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * We shall support 4 masters and 4 slaves with this driver. 79f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 80f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define VME_MAJOR 221 /* VME Major Device Number */ 81f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define VME_DEVS 9 /* Number of dev entries */ 82f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 83f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define MASTER_MINOR 0 84f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define MASTER_MAX 3 85f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define SLAVE_MINOR 4 86f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define SLAVE_MAX 7 87f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define CONTROL_MINOR 8 88f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 89f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define PCI_BUF_SIZE 0x20000 /* Size of one slave image buffer */ 90f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 91f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 92f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Structure to handle image related parameters. 93f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 94584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossierstruct image_desc { 950a81a0f768e5bb0c32db6e44440c5b7c1b4658e7Emilio G. Cota void *kern_buf; /* Buffer address in kernel space */ 96f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch dma_addr_t pci_buf; /* Buffer address in PCI address space */ 97f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long long size_buf; /* Buffer size */ 98f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch struct semaphore sem; /* Semaphore for locking image */ 99f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch struct device *device; /* Sysfs device */ 100f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch struct vme_resource *resource; /* VME resource */ 101f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch int users; /* Number of current users */ 102584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossier}; 103584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossierstatic struct image_desc image[VME_DEVS]; 104f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 105584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossierstruct driver_stats { 106f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long reads; 107f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long writes; 108f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long ioctls; 109f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long irqs; 110f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long berrs; 111f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long dmaErrors; 112f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long timeouts; 113f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long external; 114584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossier}; 115584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossierstatic struct driver_stats statistics; 116f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 117b9cc293486e27f4d29a9813da6ebcb8574071dfaEmilio G. Cotastatic struct cdev *vme_user_cdev; /* Character device */ 118b9cc293486e27f4d29a9813da6ebcb8574071dfaEmilio G. Cotastatic struct class *vme_user_sysfs_class; /* Sysfs class */ 1198f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastatic struct vme_dev *vme_user_bridge; /* Pointer to user device */ 120f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 121f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 122f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR, 123f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch MASTER_MINOR, MASTER_MINOR, 124f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch SLAVE_MINOR, SLAVE_MINOR, 125f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch SLAVE_MINOR, SLAVE_MINOR, 126f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch CONTROL_MINOR 127f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch }; 128f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 129f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 130f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_open(struct inode *, struct file *); 131f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_release(struct inode *, struct file *); 1321a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cotastatic ssize_t vme_user_read(struct file *, char __user *, size_t, loff_t *); 1331a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cotastatic ssize_t vme_user_write(struct file *, const char __user *, size_t, 1341a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cota loff_t *); 135f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic loff_t vme_user_llseek(struct file *, loff_t, int); 136b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmannstatic long vme_user_unlocked_ioctl(struct file *, unsigned int, unsigned long); 137f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 1385d6abf379d73efe390488e8edba972af4e93cb1cManohar Vangastatic int vme_user_match(struct vme_dev *); 1398f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastatic int __devinit vme_user_probe(struct vme_dev *); 1408f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastatic int __devexit vme_user_remove(struct vme_dev *); 141f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 142584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossierstatic const struct file_operations vme_user_fops = { 14345f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos .open = vme_user_open, 14445f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos .release = vme_user_release, 14545f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos .read = vme_user_read, 14645f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos .write = vme_user_write, 14745f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos .llseek = vme_user_llseek, 14845f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos .unlocked_ioctl = vme_user_unlocked_ioctl, 149f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch}; 150f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 151f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 152f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 153f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Reset all the statistic counters 154f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 155f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic void reset_counters(void) 156f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 15745f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos statistics.reads = 0; 15845f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos statistics.writes = 0; 15945f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos statistics.ioctls = 0; 16045f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos statistics.irqs = 0; 16145f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos statistics.berrs = 0; 16245f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos statistics.dmaErrors = 0; 16345f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos statistics.timeouts = 0; 164f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 165f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 166f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_open(struct inode *inode, struct file *file) 167f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 168f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch int err; 169f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(inode->i_rdev); 170f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 171f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch down(&image[minor].sem); 17205614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier /* Allow device to be opened if a resource is needed and allocated. */ 17305614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier if (minor < CONTROL_MINOR && image[minor].resource == NULL) { 174f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_ERR "No resources allocated for device\n"); 175f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = -EINVAL; 176f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_res; 177f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 178f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 179f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Increment user count */ 180f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[minor].users++; 181f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 182f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 183f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 184f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 185f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 186f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_res: 187f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 188f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 189f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return err; 190f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 191f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 192f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_release(struct inode *inode, struct file *file) 193f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 194f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(inode->i_rdev); 195f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 196f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch down(&image[minor].sem); 197f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 198f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Decrement user count */ 199f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[minor].users--; 200f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 201f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 202f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 203f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 204f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 205f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 206f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 207f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * We are going ot alloc a page during init per window for small transfers. 208f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Small transfers will go VME -> buffer -> user space. Larger (more than a 209f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * page) transfers will lock the user space buffer into memory and then 210f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * transfer the data directly into the user space buffers. 211f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 212f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t resource_to_user(int minor, char __user *buf, size_t count, 213f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch loff_t *ppos) 214f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 215f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 216f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t copied = 0; 217f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 218f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (count <= image[minor].size_buf) { 219f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* We copy to kernel buffer */ 220f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = vme_master_read(image[minor].resource, 221f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[minor].kern_buf, count, *ppos); 22245f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos if (copied < 0) 223f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return (int)copied; 224f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 225f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = __copy_to_user(buf, image[minor].kern_buf, 226f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch (unsigned long)copied); 227f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval != 0) { 228f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = (copied - retval); 22945f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos printk(KERN_INFO "User copy failed\n"); 230f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EINVAL; 231f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 232f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 233f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else { 234f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Need to write this */ 23545f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos printk(KERN_INFO "Currently don't support large transfers\n"); 236f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Map in pages from userspace */ 237f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 238f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Call vme_master_read to do the transfer */ 239f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EINVAL; 240f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 241f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 242f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return copied; 243f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 244f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 245f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 246f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * We are going ot alloc a page during init per window for small transfers. 247f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Small transfers will go user space -> buffer -> VME. Larger (more than a 248f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * page) transfers will lock the user space buffer into memory and then 249f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * transfer the data directly from the user space buffers out to VME. 250f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 2511a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cotastatic ssize_t resource_from_user(unsigned int minor, const char __user *buf, 252f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t count, loff_t *ppos) 253f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 254f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 255f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t copied = 0; 256f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 257f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (count <= image[minor].size_buf) { 258f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = __copy_from_user(image[minor].kern_buf, buf, 259f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch (unsigned long)count); 260f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval != 0) 261f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = (copied - retval); 262f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch else 263f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = count; 264f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 265f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = vme_master_write(image[minor].resource, 266f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[minor].kern_buf, copied, *ppos); 267f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else { 268f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Need to write this */ 26945f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos printk(KERN_INFO "Currently don't support large transfers\n"); 270f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Map in pages from userspace */ 271f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 272f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Call vme_master_write to do the transfer */ 273f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EINVAL; 274f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 275f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 276f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return copied; 277f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 278f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 279f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t buffer_to_user(unsigned int minor, char __user *buf, 280f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t count, loff_t *ppos) 281f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 2820a81a0f768e5bb0c32db6e44440c5b7c1b4658e7Emilio G. Cota void *image_ptr; 283f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 284f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 285f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image_ptr = image[minor].kern_buf + *ppos; 286f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 287f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = __copy_to_user(buf, image_ptr, (unsigned long)count); 288f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval != 0) { 289f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = (count - retval); 290f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Partial copy to userspace\n"); 291f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else 292f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = count; 293f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 294f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Return number of bytes successfully read */ 295f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 296f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 297f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 2981a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cotastatic ssize_t buffer_from_user(unsigned int minor, const char __user *buf, 299f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t count, loff_t *ppos) 300f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 3010a81a0f768e5bb0c32db6e44440c5b7c1b4658e7Emilio G. Cota void *image_ptr; 302f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t retval; 303f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 304f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image_ptr = image[minor].kern_buf + *ppos; 305f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 306f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = __copy_from_user(image_ptr, buf, (unsigned long)count); 307f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval != 0) { 308f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = (count - retval); 309f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Partial copy to userspace\n"); 310f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else 311f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = count; 312f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 313f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Return number of bytes successfully read */ 314f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 315f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 316f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 3171a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cotastatic ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, 31845f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos loff_t *ppos) 319f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 320f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); 321f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 322f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t image_size; 323f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t okcount; 324f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 32505614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier if (minor == CONTROL_MINOR) 32605614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier return 0; 32705614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier 328f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch down(&image[minor].sem); 329f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 330f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Do we *really* want this helper - we can use vme_*_get ? */ 331f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image_size = vme_get_size(image[minor].resource); 332f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 333f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure we are starting at a valid location */ 334f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if ((*ppos < 0) || (*ppos > (image_size - 1))) { 335f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 336f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 337f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 338f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 339f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure not reading past end of the image */ 340f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (*ppos + count > image_size) 341f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch okcount = image_size - *ppos; 342f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch else 343f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch okcount = count; 344f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 34545f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos switch (type[minor]) { 346f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case MASTER_MINOR: 347f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = resource_to_user(minor, buf, okcount, ppos); 348f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 349f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case SLAVE_MINOR: 350f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = buffer_to_user(minor, buf, okcount, ppos); 351f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 352f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch default: 353f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = -EINVAL; 354f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 355f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 356f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 357f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 358f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval > 0) 359f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch *ppos += retval; 360f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 361f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 362f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 363f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 3641a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cotastatic ssize_t vme_user_write(struct file *file, const char __user *buf, 3651a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cota size_t count, loff_t *ppos) 366f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 367f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); 368f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 369f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t image_size; 370f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t okcount; 371f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 37205614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier if (minor == CONTROL_MINOR) 37305614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier return 0; 37405614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier 375f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch down(&image[minor].sem); 376f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 377f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image_size = vme_get_size(image[minor].resource); 378f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 379f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure we are starting at a valid location */ 380f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if ((*ppos < 0) || (*ppos > (image_size - 1))) { 381f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 382f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 383f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 384f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 385f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure not reading past end of the image */ 386f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (*ppos + count > image_size) 387f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch okcount = image_size - *ppos; 388f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch else 389f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch okcount = count; 390f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 39145f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos switch (type[minor]) { 392f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case MASTER_MINOR: 393f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = resource_from_user(minor, buf, okcount, ppos); 394f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 395f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case SLAVE_MINOR: 396f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = buffer_from_user(minor, buf, okcount, ppos); 397f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 398f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch default: 399f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = -EINVAL; 400f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 401f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 402f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 403f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 404f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval > 0) 405f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch *ppos += retval; 406f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 407f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 408f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 409f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 410f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic loff_t vme_user_llseek(struct file *file, loff_t off, int whence) 411f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 412877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov loff_t absolute = -1; 413877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); 414877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov size_t image_size; 415877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov 41605614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier if (minor == CONTROL_MINOR) 41705614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier return -EINVAL; 41805614fbfc1f3dedc337ac67e83b6ad130ba9fc9fVincent Bossier 419877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov down(&image[minor].sem); 420877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov image_size = vme_get_size(image[minor].resource); 421877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov 422877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov switch (whence) { 423877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov case SEEK_SET: 424877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov absolute = off; 425877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov break; 426877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov case SEEK_CUR: 427877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov absolute = file->f_pos + off; 428877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov break; 429877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov case SEEK_END: 430877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov absolute = image_size + off; 431877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov break; 432877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov default: 433877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov up(&image[minor].sem); 434877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov return -EINVAL; 435877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov break; 436877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov } 437877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov 438877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov if ((absolute < 0) || (absolute >= image_size)) { 439877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov up(&image[minor].sem); 440877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov return -EINVAL; 441877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov } 442877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov 443877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov file->f_pos = absolute; 444877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov 445877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov up(&image[minor].sem); 446877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov 447877de4b4866f1cc0a25a4d67d3927304556f5d1fArthur Benilov return absolute; 448f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 449f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 450238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch/* 451238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * The ioctls provided by the old VME access method (the one at vmelinux.org) 452238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * are most certainly wrong as the effectively push the registers layout 453238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * through to user space. Given that the VME core can handle multiple bridges, 454238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * with different register layouts this is most certainly not the way to go. 455238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * 456238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * We aren't using the structures defined in the Motorola driver either - these 457238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * are also quite low level, however we should use the definitions that have 458238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * already been defined. 459238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 460f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_ioctl(struct inode *inode, struct file *file, 461f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int cmd, unsigned long arg) 462f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 463238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch struct vme_master master; 464238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch struct vme_slave slave; 465dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier struct vme_irq_id irq_req; 466238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch unsigned long copied; 467f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(inode->i_rdev); 468238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch int retval; 469238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch dma_addr_t pci_addr; 4701a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cota void __user *argp = (void __user *)arg; 471f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 472f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch statistics.ioctls++; 473238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 474f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch switch (type[minor]) { 475f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case CONTROL_MINOR: 476dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier switch (cmd) { 477dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier case VME_IRQ_GEN: 478dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier copied = copy_from_user(&irq_req, (char *)arg, 479dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier sizeof(struct vme_irq_id)); 480dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier if (copied != 0) { 481dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier printk(KERN_WARNING "Partial copy from userspace\n"); 482dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier return -EFAULT; 483dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier } 484dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier 485dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier retval = vme_irq_generate(vme_user_bridge, 486dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier irq_req.level, 487dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier irq_req.statid); 488dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier 489dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier return retval; 490dca22184262de0171bafdf613a8d3992a818b70fVincent Bossier } 491f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 492f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case MASTER_MINOR: 493f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch switch (cmd) { 494238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch case VME_GET_MASTER: 495238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch memset(&master, 0, sizeof(struct vme_master)); 496238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 497238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* XXX We do not want to push aspace, cycle and width 498238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * to userspace as they are 499238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 500238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch retval = vme_master_get(image[minor].resource, 501886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota &master.enable, &master.vme_addr, 502886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota &master.size, &master.aspace, 503886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota &master.cycle, &master.dwidth); 504238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 5051a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cota copied = copy_to_user(argp, &master, 506238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch sizeof(struct vme_master)); 507238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (copied != 0) { 508238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_WARNING "Partial copy to " 509238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch "userspace\n"); 510238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return -EFAULT; 511238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 512f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 513238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return retval; 514238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch break; 515238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 516238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch case VME_SET_MASTER: 517238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 5181a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cota copied = copy_from_user(&master, argp, sizeof(master)); 519238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (copied != 0) { 520f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Partial copy from " 521f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "userspace\n"); 522f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EFAULT; 523f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 524f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 525238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* XXX We do not want to push aspace, cycle and width 526238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * to userspace as they are 527238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 528238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return vme_master_set(image[minor].resource, 529238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch master.enable, master.vme_addr, master.size, 530238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch master.aspace, master.cycle, master.dwidth); 531f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 532f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 533238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 534238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch break; 535238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch case SLAVE_MINOR: 536238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch switch (cmd) { 537f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case VME_GET_SLAVE: 538238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch memset(&slave, 0, sizeof(struct vme_slave)); 539238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 540238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* XXX We do not want to push aspace, cycle and width 541238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * to userspace as they are 542238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 543238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch retval = vme_slave_get(image[minor].resource, 544886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota &slave.enable, &slave.vme_addr, 545886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota &slave.size, &pci_addr, &slave.aspace, 546886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota &slave.cycle); 547238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 5481a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cota copied = copy_to_user(argp, &slave, 549238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch sizeof(struct vme_slave)); 550238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (copied != 0) { 551238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_WARNING "Partial copy to " 552238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch "userspace\n"); 553238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return -EFAULT; 554238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 555238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 556238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return retval; 557238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch break; 558f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 559238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch case VME_SET_SLAVE: 560f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 5611a85f2073d99080ea70962f767edca479c768b6eEmilio G. Cota copied = copy_from_user(&slave, argp, sizeof(slave)); 562238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (copied != 0) { 563238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_WARNING "Partial copy from " 564f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "userspace\n"); 565f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EFAULT; 566f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 567f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 568238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* XXX We do not want to push aspace, cycle and width 569238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * to userspace as they are 570238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 571238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return vme_slave_set(image[minor].resource, 572238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch slave.enable, slave.vme_addr, slave.size, 573238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch image[minor].pci_buf, slave.aspace, 574238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch slave.cycle); 575238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 576f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 577f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 578f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 579f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 580f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 581f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EINVAL; 582f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 583f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 584b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmannstatic long 585b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmannvme_user_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 586b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmann{ 587b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmann int ret; 588b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmann 5898e2394a981b9258db47f8e223a550d46c6d40cc8Arnd Bergmann mutex_lock(&vme_user_mutex); 590b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmann ret = vme_user_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); 5918e2394a981b9258db47f8e223a550d46c6d40cc8Arnd Bergmann mutex_unlock(&vme_user_mutex); 592b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmann 593b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmann return ret; 594b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmann} 595b1f2ac07636aadee5cb077fc7e830908b00fcaaeArnd Bergmann 596f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 597f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 598f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Unallocate a previously allocated buffer 599f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 60045f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomosstatic void buf_unalloc(int num) 601f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 602f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (image[num].kern_buf) { 603f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#ifdef VME_DEBUG 604f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_DEBUG "UniverseII:Releasing buffer at %p\n", 605f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].pci_buf); 606f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#endif 607f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 608f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_free_consistent(image[num].resource, image[num].size_buf, 609f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].kern_buf, image[num].pci_buf); 610f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 611f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].kern_buf = NULL; 612f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].pci_buf = 0; 613f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].size_buf = 0; 614f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 615f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#ifdef VME_DEBUG 616f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else { 617f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_DEBUG "UniverseII: Buffer not allocated\n"); 618f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#endif 619f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 620f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 621f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 622f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic struct vme_driver vme_user_driver = { 62345f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos .name = driver_name, 6245d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga .match = vme_user_match, 62545f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos .probe = vme_user_probe, 6264740a0846069f6d4cbba9e328a9d92e6dd76110dEmilio G. Cota .remove = __devexit_p(vme_user_remove), 627f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch}; 628f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 629f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 630238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic int __init vme_user_init(void) 631f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 632238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch int retval = 0; 633238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 634f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_INFO "VME User Space Access Driver\n"); 635238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 636238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (bus_num == 0) { 637238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_ERR "%s: No cards, skipping registration\n", 638238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch driver_name); 63955db50205adaf14db1bda07d0931b647b794de2fEmilio G. Cota retval = -ENODEV; 640238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_nocard; 641238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 642238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 643238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* Let's start by supporting one bus, we can support more than one 644238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * in future revisions if that ever becomes necessary. 645238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 6460a4b6b0279d903df2d62aaf92edf360fb5312532Manohar Vanga if (bus_num > VME_USER_BUS_MAX) { 64751616e21066d040988a33effa82d4ef37fd60959Martyn Welch printk(KERN_ERR "%s: Driver only able to handle %d buses\n", 6480a4b6b0279d903df2d62aaf92edf360fb5312532Manohar Vanga driver_name, VME_USER_BUS_MAX); 6490a4b6b0279d903df2d62aaf92edf360fb5312532Manohar Vanga bus_num = VME_USER_BUS_MAX; 650238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 651238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 6525d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga /* 6535d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga * Here we just register the maximum number of devices we can and 6545d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga * leave vme_user_match() to allow only 1 to go through to probe(). 6555d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga * This way, if we later want to allow multiple user access devices, 6565d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga * we just change the code in vme_user_match(). 6575d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga */ 6585d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga retval = vme_register_driver(&vme_user_driver, VME_MAX_SLOTS); 659238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (retval != 0) 660238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_reg; 661238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 662238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return retval; 663238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 664238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_reg: 665238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_nocard: 666f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 667f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 668f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 6695d6abf379d73efe390488e8edba972af4e93cb1cManohar Vangastatic int vme_user_match(struct vme_dev *vdev) 6705d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga{ 6710a4b6b0279d903df2d62aaf92edf360fb5312532Manohar Vanga if (vdev->num >= VME_USER_BUS_MAX) 6725d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga return 0; 6735d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga return 1; 6745d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga} 6755d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga 676f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 677238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * In this simple access driver, the old behaviour is being preserved as much 678238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * as practical. We will therefore reserve the buffers and request the images 679238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * here so that we don't have to do it later. 680f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 6818f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastatic int __devinit vme_user_probe(struct vme_dev *vdev) 682f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 683f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch int i, err; 684beb9ccc635433065a099b75dc8b22caf0844014aMartyn Welch char name[12]; 685f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 686238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* Save pointer to the bridge device */ 687238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (vme_user_bridge != NULL) { 688238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_ERR "%s: Driver can only be loaded for 1 device\n", 689238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch driver_name); 690238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch err = -EINVAL; 691238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_dev; 692238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 6938f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga vme_user_bridge = vdev; 694f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 695f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Initialise descriptors */ 696f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for (i = 0; i < VME_DEVS; i++) { 697f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].kern_buf = NULL; 698f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].pci_buf = 0; 699886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota sema_init(&image[i].sem, 1); 700f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].device = NULL; 701f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].resource = NULL; 702f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].users = 0; 703f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 704f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 705f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Initialise statistics counters */ 706f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch reset_counters(); 707f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 708f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Assign major and minor numbers for the driver */ 709f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = register_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS, 710f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch driver_name); 711f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (err) { 712f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "%s: Error getting Major Number %d for " 713f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "driver.\n", driver_name, VME_MAJOR); 714f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_region; 715f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 716f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 717f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Register the driver as a char device */ 718f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_user_cdev = cdev_alloc(); 719f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_user_cdev->ops = &vme_user_fops; 720f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_user_cdev->owner = THIS_MODULE; 721f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = cdev_add(vme_user_cdev, MKDEV(VME_MAJOR, 0), VME_DEVS); 722f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (err) { 723f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "%s: cdev_all failed\n", driver_name); 724f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_char; 725f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 726f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 727f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Request slave resources and allocate buffers (128kB wide) */ 728f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) { 729f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Need to properly request attributes */ 7305188d74cc4597a63a0907b8996ca0a2d36f1b970Arthur Benilov /* For ca91cx42 bridge there are only two slave windows 7315188d74cc4597a63a0907b8996ca0a2d36f1b970Arthur Benilov * supporting A16 addressing, so we request A24 supported 7325188d74cc4597a63a0907b8996ca0a2d36f1b970Arthur Benilov * by all windows. 7335188d74cc4597a63a0907b8996ca0a2d36f1b970Arthur Benilov */ 734f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].resource = vme_slave_request(vme_user_bridge, 7355188d74cc4597a63a0907b8996ca0a2d36f1b970Arthur Benilov VME_A24, VME_SCT); 736f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (image[i].resource == NULL) { 737f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Unable to allocate slave " 738f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "resource\n"); 739238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_slave; 740f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 741f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].size_buf = PCI_BUF_SIZE; 742f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].kern_buf = vme_alloc_consistent(image[i].resource, 743886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota image[i].size_buf, &image[i].pci_buf); 744f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (image[i].kern_buf == NULL) { 745f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Unable to allocate memory for " 746f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "buffer\n"); 747f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].pci_buf = 0; 748f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_slave_free(image[i].resource); 749f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = -ENOMEM; 750238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_slave; 751f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 752f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 753f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 754f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* 755f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Request master resources allocate page sized buffers for small 756f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * reads and writes 757f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 758f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) { 759f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Need to properly request attributes */ 760f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].resource = vme_master_request(vme_user_bridge, 761f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch VME_A32, VME_SCT, VME_D32); 762f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (image[i].resource == NULL) { 763f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Unable to allocate master " 764f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "resource\n"); 765238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_master; 766f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 76733e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov image[i].size_buf = PCI_BUF_SIZE; 76833e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov image[i].kern_buf = kmalloc(image[i].size_buf, GFP_KERNEL); 76933e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov if (image[i].kern_buf == NULL) { 77033e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov printk(KERN_WARNING "Unable to allocate memory for " 77133e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov "master window buffers\n"); 77233e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov err = -ENOMEM; 77333e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov goto err_master_buf; 77433e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov } 775f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 776f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 777f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Create sysfs entries - on udev systems this creates the dev files */ 778f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_user_sysfs_class = class_create(THIS_MODULE, driver_name); 779f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (IS_ERR(vme_user_sysfs_class)) { 780f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_ERR "Error creating vme_user class.\n"); 781f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = PTR_ERR(vme_user_sysfs_class); 782f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_class; 783f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 784f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 785f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Add sysfs Entries */ 78645f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos for (i = 0; i < VME_DEVS; i++) { 787584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossier int num; 788f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch switch (type[i]) { 789f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case MASTER_MINOR: 79045f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos sprintf(name, "bus/vme/m%%d"); 791f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 792f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case CONTROL_MINOR: 79345f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos sprintf(name, "bus/vme/ctl"); 794f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 795f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case SLAVE_MINOR: 79645f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos sprintf(name, "bus/vme/s%%d"); 797f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 798f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch default: 799f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = -EINVAL; 800f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_sysfs; 801f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 802f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 803f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 804584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossier num = (type[i] == SLAVE_MINOR) ? i - (MASTER_MAX + 1) : i; 805584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossier image[i].device = device_create(vme_user_sysfs_class, NULL, 806584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossier MKDEV(VME_MAJOR, i), NULL, name, num); 807f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (IS_ERR(image[i].device)) { 80845f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos printk(KERN_INFO "%s: Error creating sysfs device\n", 809f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch driver_name); 810f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = PTR_ERR(image[i].device); 811f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_sysfs; 812f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 813f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 814f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 815f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 816f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 817f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure counter set correcty to destroy all sysfs devices */ 818f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch i = VME_DEVS; 819f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_sysfs: 82045f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos while (i > 0) { 821f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch i--; 822f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i)); 823f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 824f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch class_destroy(vme_user_sysfs_class); 825f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 826238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* Ensure counter set correcty to unalloc all master windows */ 827238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch i = MASTER_MAX + 1; 82833e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Beniloverr_master_buf: 82933e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) 83033e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov kfree(image[i].kern_buf); 831238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_master: 832238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch while (i > MASTER_MINOR) { 833238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch i--; 834238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch vme_master_free(image[i].resource); 835238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 836238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 837238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* 838238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * Ensure counter set correcty to unalloc all slave windows and buffers 839238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 840f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch i = SLAVE_MAX + 1; 841238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_slave: 842238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch while (i > SLAVE_MINOR) { 843f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch i--; 844f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch buf_unalloc(i); 8451daa38d379932bde0d2036c2e10ced3e8842b74fEmilio G. Cota vme_slave_free(image[i].resource); 846f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 847f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_class: 848f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch cdev_del(vme_user_cdev); 849f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_char: 850f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS); 851f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_region: 852238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_dev: 853f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return err; 854f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 855f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 8568f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastatic int __devexit vme_user_remove(struct vme_dev *dev) 857f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 858f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch int i; 859f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 860f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Remove sysfs Entries */ 86145f9f018967c3fc112a03a99a8fdfad3621407a7Nanakos Chrysostomos for (i = 0; i < VME_DEVS; i++) 862f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i)); 863f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch class_destroy(vme_user_sysfs_class); 864f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 865b62c99b17c2c513eaf6b77a76907a13a1beb86d3Emilio G. Cota for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) { 86633e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov kfree(image[i].kern_buf); 867b62c99b17c2c513eaf6b77a76907a13a1beb86d3Emilio G. Cota vme_master_free(image[i].resource); 868b62c99b17c2c513eaf6b77a76907a13a1beb86d3Emilio G. Cota } 86933e920d9ebaddbc9cf51cf6e1de7baa8d7b8d6ddArthur Benilov 870f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) { 871238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0); 872f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch buf_unalloc(i); 8731daa38d379932bde0d2036c2e10ced3e8842b74fEmilio G. Cota vme_slave_free(image[i].resource); 874f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 875f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 876f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Unregister device driver */ 877f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch cdev_del(vme_user_cdev); 878f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 879f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Unregiser the major and minor device numbers */ 880f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS); 881238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 882238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return 0; 883f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 884f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 885238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic void __exit vme_user_exit(void) 886238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch{ 887238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch vme_unregister_driver(&vme_user_driver); 888238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch} 889238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 890238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 891238add523bf9c89db1a191599fff2770af55e0fdMartyn WelchMODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the driver is connected"); 892238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchmodule_param_array(bus, int, &bus_num, 0); 893238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 894f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn WelchMODULE_DESCRIPTION("VME User Space Access Driver"); 89566bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn WelchMODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com"); 896f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn WelchMODULE_LICENSE("GPL"); 897f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 898238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchmodule_init(vme_user_init); 899238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchmodule_exit(vme_user_exit); 900