vme_user.c revision 238add523bf9c89db1a191599fff2770af55e0fd
1f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 2f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * VMEbus User access driver 3f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 4f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Author: Martyn Welch <martyn.welch@gefanuc.com> 5f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Copyright 2008 GE Fanuc 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> 31f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/spinlock.h> 32f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/syscalls.h> 33f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/types.h> 34f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <linux/version.h> 35f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 36f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <asm/io.h> 37f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include <asm/uaccess.h> 38f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 39f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include "../vme.h" 40f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#include "vme_user.h" 41f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 42238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic char driver_name[] = "vme_user"; 43238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 44238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic int bus[USER_BUS_MAX]; 45238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic int bus_num; 46238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 47f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* Currently Documentation/devices.txt defines the following for VME: 48f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 49f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 221 char VME bus 50f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 0 = /dev/bus/vme/m0 First master image 51f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 1 = /dev/bus/vme/m1 Second master image 52f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 2 = /dev/bus/vme/m2 Third master image 53f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 3 = /dev/bus/vme/m3 Fourth master image 54f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 4 = /dev/bus/vme/s0 First slave image 55f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 5 = /dev/bus/vme/s1 Second slave image 56f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 6 = /dev/bus/vme/s2 Third slave image 57f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 7 = /dev/bus/vme/s3 Fourth slave image 58f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 8 = /dev/bus/vme/ctl Control 59f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 60f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * It is expected that all VME bus drivers will use the 61f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * same interface. For interface documentation see 62f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * http://www.vmelinux.org/. 63f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 64f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * However the VME driver at http://www.vmelinux.org/ is rather old and doesn't 65f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * even support the tsi148 chipset (which has 8 master and 8 slave windows). 66f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * We'll run with this or now as far as possible, however it probably makes 67f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * sense to get rid of the old mappings and just do everything dynamically. 68f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * 69f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * So for now, we'll restrict the driver to providing 4 masters and 4 slaves as 70f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * defined above and try to support at least some of the interface from 71f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * http://www.vmelinux.org/ as an alternative drive can be written providing a 72f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * saner interface later. 73238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * 74238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * The vmelinux.org driver never supported slave images, the devices reserved 75238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * for slaves were repurposed to support all 8 master images on the UniverseII! 76238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * We shall support 4 masters and 4 slaves with this driver. 77f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 78f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define VME_MAJOR 221 /* VME Major Device Number */ 79f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define VME_DEVS 9 /* Number of dev entries */ 80f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 81f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define MASTER_MINOR 0 82f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define MASTER_MAX 3 83f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define SLAVE_MINOR 4 84f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define SLAVE_MAX 7 85f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define CONTROL_MINOR 8 86f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 87f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#define PCI_BUF_SIZE 0x20000 /* Size of one slave image buffer */ 88f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 89f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 90f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Structure to handle image related parameters. 91f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 92f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchtypedef struct { 93f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch void __iomem *kern_buf; /* Buffer address in kernel space */ 94f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch dma_addr_t pci_buf; /* Buffer address in PCI address space */ 95f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long long size_buf; /* Buffer size */ 96f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch struct semaphore sem; /* Semaphore for locking image */ 97f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch struct device *device; /* Sysfs device */ 98f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch struct vme_resource *resource; /* VME resource */ 99f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch int users; /* Number of current users */ 100f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} image_desc_t; 101f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic image_desc_t image[VME_DEVS]; 102f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 103f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchtypedef struct { 104f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long reads; 105f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long writes; 106f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long ioctls; 107f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long irqs; 108f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long berrs; 109f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long dmaErrors; 110f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long timeouts; 111f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long external; 112f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} driver_stats_t; 113f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic driver_stats_t statistics; 114f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 115f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstruct cdev *vme_user_cdev; /* Character device */ 116f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstruct class *vme_user_sysfs_class; /* Sysfs class */ 117f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstruct device *vme_user_bridge; /* Pointer to the bridge device */ 118f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 119f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 120f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR, 121f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch MASTER_MINOR, MASTER_MINOR, 122f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch SLAVE_MINOR, SLAVE_MINOR, 123f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch SLAVE_MINOR, SLAVE_MINOR, 124f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch CONTROL_MINOR 125f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch }; 126f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 127f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 128f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_open(struct inode *, struct file *); 129f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_release(struct inode *, struct file *); 130f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t vme_user_read(struct file *, char *, size_t, loff_t *); 131f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t vme_user_write(struct file *, const char *, size_t, loff_t *); 132f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic loff_t vme_user_llseek(struct file *, loff_t, int); 133f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_ioctl(struct inode *, struct file *, unsigned int, 134f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned long); 135f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 136238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic int __init vme_user_probe(struct device *, int, int); 137238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic int __exit vme_user_remove(struct device *, int, int); 138f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 139f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic struct file_operations vme_user_fops = { 140f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch .open = vme_user_open, 141f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch .release = vme_user_release, 142f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch .read = vme_user_read, 143f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch .write = vme_user_write, 144f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch .llseek = vme_user_llseek, 145f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch .ioctl = vme_user_ioctl, 146f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch}; 147f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 148f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 149f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 150f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Reset all the statistic counters 151f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 152f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic void reset_counters(void) 153f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 154f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch statistics.reads = 0; 155f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch statistics.writes = 0; 156f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch statistics.ioctls = 0; 157f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch statistics.irqs = 0; 158f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch statistics.berrs = 0; 159f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch statistics.dmaErrors = 0; 160f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch statistics.timeouts = 0; 161f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 162f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 163f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_open(struct inode *inode, struct file *file) 164f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 165f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch int err; 166f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(inode->i_rdev); 167f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 168f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch down(&image[minor].sem); 169f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Only allow device to be opened if a resource is allocated */ 170f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (image[minor].resource == NULL) { 171f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_ERR "No resources allocated for device\n"); 172f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = -EINVAL; 173f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_res; 174f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 175f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 176f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Increment user count */ 177f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[minor].users++; 178f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 179f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 180f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 181f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 182f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 183f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_res: 184f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 185f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 186f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return err; 187f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 188f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 189f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_release(struct inode *inode, struct file *file) 190f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 191f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(inode->i_rdev); 192f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 193f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch down(&image[minor].sem); 194f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 195f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Decrement user count */ 196f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[minor].users--; 197f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 198f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 199f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 200f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 201f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 202f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 203f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 204f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * We are going ot alloc a page during init per window for small transfers. 205f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Small transfers will go VME -> buffer -> user space. Larger (more than a 206f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * page) transfers will lock the user space buffer into memory and then 207f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * transfer the data directly into the user space buffers. 208f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 209f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t resource_to_user(int minor, char __user *buf, size_t count, 210f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch loff_t *ppos) 211f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 212f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 213f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t copied = 0; 214f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 215f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (count <= image[minor].size_buf) { 216f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* We copy to kernel buffer */ 217f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = vme_master_read(image[minor].resource, 218f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[minor].kern_buf, count, *ppos); 219f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (copied < 0) { 220f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return (int)copied; 221f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 222f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 223f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = __copy_to_user(buf, image[minor].kern_buf, 224f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch (unsigned long)copied); 225f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval != 0) { 226f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = (copied - retval); 227f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk("User copy failed\n"); 228f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EINVAL; 229f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 230f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 231f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else { 232f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Need to write this */ 233f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk("Currently don't support large transfers\n"); 234f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Map in pages from userspace */ 235f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 236f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Call vme_master_read to do the transfer */ 237f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EINVAL; 238f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 239f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 240f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return copied; 241f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 242f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 243f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 244f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * We are going ot alloc a page during init per window for small transfers. 245f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Small transfers will go user space -> buffer -> VME. Larger (more than a 246f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * page) transfers will lock the user space buffer into memory and then 247f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * transfer the data directly from the user space buffers out to VME. 248f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 249f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t resource_from_user(unsigned int minor, const char *buf, 250f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t count, loff_t *ppos) 251f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 252f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 253f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t copied = 0; 254f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 255f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (count <= image[minor].size_buf) { 256f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = __copy_from_user(image[minor].kern_buf, buf, 257f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch (unsigned long)count); 258f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval != 0) 259f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = (copied - retval); 260f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch else 261f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = count; 262f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 263f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch copied = vme_master_write(image[minor].resource, 264f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[minor].kern_buf, copied, *ppos); 265f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else { 266f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Need to write this */ 267f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk("Currently don't support large transfers\n"); 268f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Map in pages from userspace */ 269f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 270f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Call vme_master_write to do the transfer */ 271f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EINVAL; 272f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 273f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 274f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return copied; 275f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 276f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 277f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t buffer_to_user(unsigned int minor, char __user *buf, 278f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t count, loff_t *ppos) 279f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 280f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch void __iomem *image_ptr; 281f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 282f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 283f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image_ptr = image[minor].kern_buf + *ppos; 284f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 285f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = __copy_to_user(buf, image_ptr, (unsigned long)count); 286f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval != 0) { 287f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = (count - retval); 288f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Partial copy to userspace\n"); 289f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else 290f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = count; 291f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 292f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Return number of bytes successfully read */ 293f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 294f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 295f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 296f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t buffer_from_user(unsigned int minor, const char *buf, 297f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t count, loff_t *ppos) 298f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 299f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch void __iomem *image_ptr; 300f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t retval; 301f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 302f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image_ptr = image[minor].kern_buf + *ppos; 303f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 304f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = __copy_from_user(image_ptr, buf, (unsigned long)count); 305f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval != 0) { 306f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = (count - retval); 307f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Partial copy to userspace\n"); 308f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else 309f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = count; 310f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 311f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Return number of bytes successfully read */ 312f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 313f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 314f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 315f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t vme_user_read(struct file *file, char *buf, size_t count, 316f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch loff_t * ppos) 317f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 318f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); 319f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 320f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t image_size; 321f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t okcount; 322f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 323f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch down(&image[minor].sem); 324f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 325f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Do we *really* want this helper - we can use vme_*_get ? */ 326f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image_size = vme_get_size(image[minor].resource); 327f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 328f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure we are starting at a valid location */ 329f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if ((*ppos < 0) || (*ppos > (image_size - 1))) { 330f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 331f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 332f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 333f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 334f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure not reading past end of the image */ 335f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (*ppos + count > image_size) 336f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch okcount = image_size - *ppos; 337f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch else 338f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch okcount = count; 339f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 340f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch switch (type[minor]){ 341f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case MASTER_MINOR: 342f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = resource_to_user(minor, buf, okcount, ppos); 343f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 344f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case SLAVE_MINOR: 345f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = buffer_to_user(minor, buf, okcount, ppos); 346f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 347f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch default: 348f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = -EINVAL; 349f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 350f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 351f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 352f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 353f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval > 0) 354f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch *ppos += retval; 355f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 356f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 357f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 358f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 359f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic ssize_t vme_user_write(struct file *file, const char *buf, size_t count, 360f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch loff_t *ppos) 361f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 362f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); 363f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch ssize_t retval; 364f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t image_size; 365f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch size_t okcount; 366f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 367f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch down(&image[minor].sem); 368f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 369f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image_size = vme_get_size(image[minor].resource); 370f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 371f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure we are starting at a valid location */ 372f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if ((*ppos < 0) || (*ppos > (image_size - 1))) { 373f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 374f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 375f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 376f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 377f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure not reading past end of the image */ 378f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (*ppos + count > image_size) 379f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch okcount = image_size - *ppos; 380f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch else 381f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch okcount = count; 382f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 383f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch switch (type[minor]){ 384f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case MASTER_MINOR: 385f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = resource_from_user(minor, buf, okcount, ppos); 386f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 387f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case SLAVE_MINOR: 388f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = buffer_from_user(minor, buf, okcount, ppos); 389f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 390f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch default: 391f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = -EINVAL; 392f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 393f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 394f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch up(&image[minor].sem); 395f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 396f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (retval > 0) 397f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch *ppos += retval; 398f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 399f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 400f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 401f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 402f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic loff_t vme_user_llseek(struct file *file, loff_t off, int whence) 403f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 404f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_ERR "Llseek currently incomplete\n"); 405f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EINVAL; 406f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 407f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 408238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch/* 409238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * The ioctls provided by the old VME access method (the one at vmelinux.org) 410238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * are most certainly wrong as the effectively push the registers layout 411238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * through to user space. Given that the VME core can handle multiple bridges, 412238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * with different register layouts this is most certainly not the way to go. 413238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * 414238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * We aren't using the structures defined in the Motorola driver either - these 415238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * are also quite low level, however we should use the definitions that have 416238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * already been defined. 417238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 418f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic int vme_user_ioctl(struct inode *inode, struct file *file, 419f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int cmd, unsigned long arg) 420f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 421238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch struct vme_master master; 422238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch struct vme_slave slave; 423238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch unsigned long copied; 424f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unsigned int minor = MINOR(inode->i_rdev); 425238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch int retval; 426238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch dma_addr_t pci_addr; 427f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 428f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch statistics.ioctls++; 429238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 430f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch switch (type[minor]) { 431f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case CONTROL_MINOR: 432f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 433f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case MASTER_MINOR: 434f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch switch (cmd) { 435238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch case VME_GET_MASTER: 436238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch memset(&master, 0, sizeof(struct vme_master)); 437238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 438238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* XXX We do not want to push aspace, cycle and width 439238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * to userspace as they are 440238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 441238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch retval = vme_master_get(image[minor].resource, 442238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch &(master.enable), &(master.vme_addr), 443238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch &(master.size), &(master.aspace), 444238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch &(master.cycle), &(master.dwidth)); 445238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 446238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch copied = copy_to_user((char *)arg, &master, 447238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch sizeof(struct vme_master)); 448238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (copied != 0) { 449238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_WARNING "Partial copy to " 450238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch "userspace\n"); 451238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return -EFAULT; 452238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 453f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 454238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return retval; 455238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch break; 456238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 457238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch case VME_SET_MASTER: 458238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 459238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch copied = copy_from_user(&master, (char *)arg, 460238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch sizeof(master)); 461238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (copied != 0) { 462f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Partial copy from " 463f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "userspace\n"); 464f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EFAULT; 465f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 466f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 467238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* XXX We do not want to push aspace, cycle and width 468238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * to userspace as they are 469238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 470238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return vme_master_set(image[minor].resource, 471238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch master.enable, master.vme_addr, master.size, 472238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch master.aspace, master.cycle, master.dwidth); 473f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 474f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 475238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 476238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch break; 477238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch case SLAVE_MINOR: 478238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch switch (cmd) { 479f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case VME_GET_SLAVE: 480238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch memset(&slave, 0, sizeof(struct vme_slave)); 481238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 482238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* XXX We do not want to push aspace, cycle and width 483238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * to userspace as they are 484238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 485238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch retval = vme_slave_get(image[minor].resource, 486238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch &(slave.enable), &(slave.vme_addr), 487238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch &(slave.size), &pci_addr, &(slave.aspace), 488238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch &(slave.cycle)); 489238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 490238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch copied = copy_to_user((char *)arg, &slave, 491238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch sizeof(struct vme_slave)); 492238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (copied != 0) { 493238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_WARNING "Partial copy to " 494238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch "userspace\n"); 495238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return -EFAULT; 496238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 497238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 498238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return retval; 499238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch break; 500f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 501238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch case VME_SET_SLAVE: 502f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 503238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch copied = copy_from_user(&slave, (char *)arg, 504f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch sizeof(slave)); 505238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (copied != 0) { 506238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_WARNING "Partial copy from " 507f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "userspace\n"); 508f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EFAULT; 509f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 510f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 511238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* XXX We do not want to push aspace, cycle and width 512238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * to userspace as they are 513238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 514238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return vme_slave_set(image[minor].resource, 515238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch slave.enable, slave.vme_addr, slave.size, 516238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch image[minor].pci_buf, slave.aspace, 517238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch slave.cycle); 518238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 519f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 520f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 521f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 522f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 523f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 524f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return -EINVAL; 525f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 526f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 527f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 528f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 529f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Unallocate a previously allocated buffer 530f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 531f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic void buf_unalloc (int num) 532f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 533f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (image[num].kern_buf) { 534f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#ifdef VME_DEBUG 535f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_DEBUG "UniverseII:Releasing buffer at %p\n", 536f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].pci_buf); 537f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#endif 538f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 539f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_free_consistent(image[num].resource, image[num].size_buf, 540f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].kern_buf, image[num].pci_buf); 541f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 542f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].kern_buf = NULL; 543f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].pci_buf = 0; 544f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[num].size_buf = 0; 545f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 546f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#ifdef VME_DEBUG 547f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } else { 548f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_DEBUG "UniverseII: Buffer not allocated\n"); 549f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch#endif 550f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 551f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 552f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 553f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welchstatic struct vme_driver vme_user_driver = { 554f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch .name = driver_name, 555f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch .probe = vme_user_probe, 556238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch .remove = vme_user_remove, 557f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch}; 558f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 559f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 560238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic int __init vme_user_init(void) 561f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 562238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch int retval = 0; 563238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch int i; 564238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch struct vme_device_id *ids; 565238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 566f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_INFO "VME User Space Access Driver\n"); 567238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 568238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (bus_num == 0) { 569238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_ERR "%s: No cards, skipping registration\n", 570238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch driver_name); 571238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_nocard; 572238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 573238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 574238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* Let's start by supporting one bus, we can support more than one 575238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * in future revisions if that ever becomes necessary. 576238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 577238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (bus_num > USER_BUS_MAX) { 578238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_ERR "%s: Driver only able to handle %d PIO2 " 579238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch "Cards\n", driver_name, USER_BUS_MAX); 580238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch bus_num = USER_BUS_MAX; 581238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 582238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 583238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 584238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* Dynamically create the bind table based on module parameters */ 585238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch ids = kmalloc(sizeof(struct vme_device_id) * (bus_num + 1), GFP_KERNEL); 586238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (ids == NULL) { 587238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_ERR "%s: Unable to allocate ID table\n", 588238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch driver_name); 589238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_id; 590238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 591238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 592238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch memset(ids, 0, (sizeof(struct vme_device_id) * (bus_num + 1))); 593238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 594238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch for (i = 0; i < bus_num; i++) { 595238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch ids[i].bus = bus[i]; 596238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* 597238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * We register the driver against the slot occupied by *this* 598238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * card, since it's really a low level way of controlling 599238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * the VME bridge 600238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 601238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch ids[i].slot = VME_SLOT_CURRENT; 602238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 603238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 604238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch vme_user_driver.bind_table = ids; 605238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 606f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch retval = vme_register_driver(&vme_user_driver); 607238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (retval != 0) 608238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_reg; 609238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 610238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return retval; 611238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 612238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch vme_unregister_driver(&vme_user_driver); 613238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_reg: 614238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch kfree(ids); 615238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_id: 616238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_nocard: 617f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return retval; 618f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 619f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 620f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch/* 621238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * In this simple access driver, the old behaviour is being preserved as much 622238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * as practical. We will therefore reserve the buffers and request the images 623238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * here so that we don't have to do it later. 624f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 625238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot) 626f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 627f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch int i, err; 628f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch char name[8]; 629f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 630238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* Save pointer to the bridge device */ 631238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch if (vme_user_bridge != NULL) { 632238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch printk(KERN_ERR "%s: Driver can only be loaded for 1 device\n", 633238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch driver_name); 634238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch err = -EINVAL; 635238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_dev; 636238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 637f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_user_bridge = dev; 638f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 639f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Initialise descriptors */ 640f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for (i = 0; i < VME_DEVS; i++) { 641f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].kern_buf = NULL; 642f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].pci_buf = 0; 643f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch init_MUTEX(&(image[i].sem)); 644f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].device = NULL; 645f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].resource = NULL; 646f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].users = 0; 647f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 648f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 649f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Initialise statistics counters */ 650f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch reset_counters(); 651f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 652f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Assign major and minor numbers for the driver */ 653f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = register_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS, 654f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch driver_name); 655f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (err) { 656f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "%s: Error getting Major Number %d for " 657f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "driver.\n", driver_name, VME_MAJOR); 658f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_region; 659f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 660f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 661f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Register the driver as a char device */ 662f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_user_cdev = cdev_alloc(); 663f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_user_cdev->ops = &vme_user_fops; 664f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_user_cdev->owner = THIS_MODULE; 665f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = cdev_add(vme_user_cdev, MKDEV(VME_MAJOR, 0), VME_DEVS); 666f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (err) { 667f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "%s: cdev_all failed\n", driver_name); 668f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_char; 669f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 670f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 671f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Request slave resources and allocate buffers (128kB wide) */ 672f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) { 673f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Need to properly request attributes */ 674f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].resource = vme_slave_request(vme_user_bridge, 675f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch VME_A16, VME_SCT); 676f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (image[i].resource == NULL) { 677f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Unable to allocate slave " 678f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "resource\n"); 679238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_slave; 680f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 681f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].size_buf = PCI_BUF_SIZE; 682f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].kern_buf = vme_alloc_consistent(image[i].resource, 683f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].size_buf, &(image[i].pci_buf)); 684f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (image[i].kern_buf == NULL) { 685f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Unable to allocate memory for " 686f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "buffer\n"); 687f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].pci_buf = 0; 688f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_slave_free(image[i].resource); 689f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = -ENOMEM; 690238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_slave; 691f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 692f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 693f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 694f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* 695f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * Request master resources allocate page sized buffers for small 696f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch * reads and writes 697f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch */ 698f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) { 699f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* XXX Need to properly request attributes */ 700f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].resource = vme_master_request(vme_user_bridge, 701f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch VME_A32, VME_SCT, VME_D32); 702f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (image[i].resource == NULL) { 703f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_WARNING "Unable to allocate master " 704f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch "resource\n"); 705238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch goto err_master; 706f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 707f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 708f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 709f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Create sysfs entries - on udev systems this creates the dev files */ 710f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_user_sysfs_class = class_create(THIS_MODULE, driver_name); 711f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (IS_ERR(vme_user_sysfs_class)) { 712f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk(KERN_ERR "Error creating vme_user class.\n"); 713f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = PTR_ERR(vme_user_sysfs_class); 714f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_class; 715f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 716f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 717f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Add sysfs Entries */ 718f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for (i=0; i<VME_DEVS; i++) { 719f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch switch (type[i]) { 720f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case MASTER_MINOR: 721f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch sprintf(name,"bus/vme/m%%d"); 722f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 723f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case CONTROL_MINOR: 724f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch sprintf(name,"bus/vme/ctl"); 725f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 726f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch case SLAVE_MINOR: 727f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch sprintf(name,"bus/vme/s%%d"); 728f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 729f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch default: 730f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = -EINVAL; 731f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_sysfs; 732f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch break; 733f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 734f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 735f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch image[i].device = 736f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch device_create(vme_user_sysfs_class, NULL, 737f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch MKDEV(VME_MAJOR, i), NULL, name, 738f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch (type[i] == SLAVE_MINOR)? i - (MASTER_MAX + 1) : i); 739f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch if (IS_ERR(image[i].device)) { 740f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch printk("%s: Error creating sysfs device\n", 741f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch driver_name); 742f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch err = PTR_ERR(image[i].device); 743f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch goto err_sysfs; 744f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 745f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 746f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 747f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return 0; 748f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 749f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Ensure counter set correcty to destroy all sysfs devices */ 750f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch i = VME_DEVS; 751f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_sysfs: 752f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch while (i > 0){ 753f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch i--; 754f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i)); 755f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 756f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch class_destroy(vme_user_sysfs_class); 757f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 758238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* Ensure counter set correcty to unalloc all master windows */ 759238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch i = MASTER_MAX + 1; 760238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_master: 761238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch while (i > MASTER_MINOR) { 762238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch i--; 763238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch vme_master_free(image[i].resource); 764238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch } 765238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 766238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch /* 767238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch * Ensure counter set correcty to unalloc all slave windows and buffers 768238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch */ 769f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch i = SLAVE_MAX + 1; 770238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_slave: 771238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch while (i > SLAVE_MINOR) { 772f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch i--; 773f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch vme_slave_free(image[i].resource); 774f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch buf_unalloc(i); 775f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 776f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_class: 777f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch cdev_del(vme_user_cdev); 778f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_char: 779f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS); 780f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welcherr_region: 781238add523bf9c89db1a191599fff2770af55e0fdMartyn Welcherr_dev: 782f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch return err; 783f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 784f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 785238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot) 786f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch{ 787f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch int i; 788f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 789f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Remove sysfs Entries */ 790f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for(i=0; i<VME_DEVS; i++) { 791f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i)); 792f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 793f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch class_destroy(vme_user_sysfs_class); 794f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 795f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) { 796238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0); 797238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch vme_slave_free(image[i].resource); 798f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch buf_unalloc(i); 799f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch } 800f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 801f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Unregister device driver */ 802f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch cdev_del(vme_user_cdev); 803f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 804f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch /* Unregiser the major and minor device numbers */ 805f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS); 806238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 807238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch return 0; 808f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch} 809f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 810238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchstatic void __exit vme_user_exit(void) 811238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch{ 812238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch vme_unregister_driver(&vme_user_driver); 813238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 814238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch kfree(vme_user_driver.bind_table); 815238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch} 816238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 817238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 818238add523bf9c89db1a191599fff2770af55e0fdMartyn WelchMODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the driver is connected"); 819238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchmodule_param_array(bus, int, &bus_num, 0); 820238add523bf9c89db1a191599fff2770af55e0fdMartyn Welch 821f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn WelchMODULE_DESCRIPTION("VME User Space Access Driver"); 822f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn WelchMODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com"); 823f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn WelchMODULE_LICENSE("GPL"); 824f00a86d98a1ec3e99d352cda926fab767ba43b1fMartyn Welch 825238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchmodule_init(vme_user_init); 826238add523bf9c89db1a191599fff2770af55e0fdMartyn Welchmodule_exit(vme_user_exit); 827