1 /* 2 * arch/sh/boards/landisk/gio.c - driver for landisk 3 * 4 * This driver will also support the I-O DATA Device, Inc. LANDISK Board. 5 * LANDISK and USL-5P Button, LED and GIO driver drive function. 6 * 7 * Copylight (C) 2006 kogiidena 8 * Copylight (C) 2002 Atom Create Engineering Co., Ltd. * 9 * 10 * This file is subject to the terms and conditions of the GNU General Public 11 * License. See the file "COPYING" in the main directory of this archive 12 * for more details. 13 * 14 */ 15 #include <linux/module.h> 16 #include <linux/init.h> 17 #include <linux/smp_lock.h> 18 #include <linux/kdev_t.h> 19 #include <linux/cdev.h> 20 #include <linux/fs.h> 21 #include <asm/io.h> 22 #include <asm/uaccess.h> 23 #include <mach-landisk/mach/gio.h> 24 #include <mach-landisk/mach/iodata_landisk.h> 25 26 #define DEVCOUNT 4 27 #define GIO_MINOR 2 /* GIO minor no. */ 28 29 static dev_t dev; 30 static struct cdev *cdev_p; 31 static int openCnt; 32 33 static int gio_open(struct inode *inode, struct file *filp) 34 { 35 int minor; 36 int ret = -ENOENT; 37 38 lock_kernel(); 39 minor = MINOR(inode->i_rdev); 40 if (minor < DEVCOUNT) { 41 if (openCnt > 0) { 42 ret = -EALREADY; 43 } else { 44 openCnt++; 45 ret = 0; 46 } 47 } 48 unlock_kernel(); 49 return ret; 50 } 51 52 static int gio_close(struct inode *inode, struct file *filp) 53 { 54 int minor; 55 56 minor = MINOR(inode->i_rdev); 57 if (minor < DEVCOUNT) { 58 openCnt--; 59 } 60 return 0; 61 } 62 63 static int gio_ioctl(struct inode *inode, struct file *filp, 64 unsigned int cmd, unsigned long arg) 65 { 66 unsigned int data; 67 static unsigned int addr = 0; 68 69 if (cmd & 0x01) { /* write */ 70 if (copy_from_user(&data, (int *)arg, sizeof(int))) { 71 return -EFAULT; 72 } 73 } 74 75 switch (cmd) { 76 case GIODRV_IOCSGIOSETADDR: /* address set */ 77 addr = data; 78 break; 79 80 case GIODRV_IOCSGIODATA1: /* write byte */ 81 ctrl_outb((unsigned char)(0x0ff & data), addr); 82 break; 83 84 case GIODRV_IOCSGIODATA2: /* write word */ 85 if (addr & 0x01) { 86 return -EFAULT; 87 } 88 ctrl_outw((unsigned short int)(0x0ffff & data), addr); 89 break; 90 91 case GIODRV_IOCSGIODATA4: /* write long */ 92 if (addr & 0x03) { 93 return -EFAULT; 94 } 95 ctrl_outl(data, addr); 96 break; 97 98 case GIODRV_IOCGGIODATA1: /* read byte */ 99 data = ctrl_inb(addr); 100 break; 101 102 case GIODRV_IOCGGIODATA2: /* read word */ 103 if (addr & 0x01) { 104 return -EFAULT; 105 } 106 data = ctrl_inw(addr); 107 break; 108 109 case GIODRV_IOCGGIODATA4: /* read long */ 110 if (addr & 0x03) { 111 return -EFAULT; 112 } 113 data = ctrl_inl(addr); 114 break; 115 default: 116 return -EFAULT; 117 break; 118 } 119 120 if ((cmd & 0x01) == 0) { /* read */ 121 if (copy_to_user((int *)arg, &data, sizeof(int))) { 122 return -EFAULT; 123 } 124 } 125 return 0; 126 } 127 128 static const struct file_operations gio_fops = { 129 .owner = THIS_MODULE, 130 .open = gio_open, /* open */ 131 .release = gio_close, /* release */ 132 .ioctl = gio_ioctl, /* ioctl */ 133 }; 134 135 static int __init gio_init(void) 136 { 137 int error; 138 139 printk(KERN_INFO "gio: driver initialized\n"); 140 141 openCnt = 0; 142 143 if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) { 144 printk(KERN_ERR 145 "gio: Couldn't alloc_chrdev_region, error=%d\n", 146 error); 147 return 1; 148 } 149 150 cdev_p = cdev_alloc(); 151 cdev_p->ops = &gio_fops; 152 error = cdev_add(cdev_p, dev, DEVCOUNT); 153 if (error) { 154 printk(KERN_ERR 155 "gio: Couldn't cdev_add, error=%d\n", error); 156 return 1; 157 } 158 159 return 0; 160 } 161 162 static void __exit gio_exit(void) 163 { 164 cdev_del(cdev_p); 165 unregister_chrdev_region(dev, DEVCOUNT); 166 } 167 168 module_init(gio_init); 169 module_exit(gio_exit); 170 171 MODULE_LICENSE("GPL"); 172