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/kdev_t.h> 18#include <linux/cdev.h> 19#include <linux/fs.h> 20#include <asm/io.h> 21#include <asm/uaccess.h> 22#include <mach-landisk/mach/gio.h> 23#include <mach-landisk/mach/iodata_landisk.h> 24 25#define DEVCOUNT 4 26#define GIO_MINOR 2 /* GIO minor no. */ 27 28static dev_t dev; 29static struct cdev *cdev_p; 30static int openCnt; 31 32static int gio_open(struct inode *inode, struct file *filp) 33{ 34 int minor; 35 int ret = -ENOENT; 36 37 preempt_disable(); 38 minor = MINOR(inode->i_rdev); 39 if (minor < DEVCOUNT) { 40 if (openCnt > 0) { 41 ret = -EALREADY; 42 } else { 43 openCnt++; 44 ret = 0; 45 } 46 } 47 preempt_enable(); 48 return ret; 49} 50 51static int gio_close(struct inode *inode, struct file *filp) 52{ 53 int minor; 54 55 minor = MINOR(inode->i_rdev); 56 if (minor < DEVCOUNT) { 57 openCnt--; 58 } 59 return 0; 60} 61 62static long gio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 63{ 64 unsigned int data; 65 static unsigned int addr = 0; 66 67 if (cmd & 0x01) { /* write */ 68 if (copy_from_user(&data, (int *)arg, sizeof(int))) { 69 return -EFAULT; 70 } 71 } 72 73 switch (cmd) { 74 case GIODRV_IOCSGIOSETADDR: /* address set */ 75 addr = data; 76 break; 77 78 case GIODRV_IOCSGIODATA1: /* write byte */ 79 __raw_writeb((unsigned char)(0x0ff & data), addr); 80 break; 81 82 case GIODRV_IOCSGIODATA2: /* write word */ 83 if (addr & 0x01) { 84 return -EFAULT; 85 } 86 __raw_writew((unsigned short int)(0x0ffff & data), addr); 87 break; 88 89 case GIODRV_IOCSGIODATA4: /* write long */ 90 if (addr & 0x03) { 91 return -EFAULT; 92 } 93 __raw_writel(data, addr); 94 break; 95 96 case GIODRV_IOCGGIODATA1: /* read byte */ 97 data = __raw_readb(addr); 98 break; 99 100 case GIODRV_IOCGGIODATA2: /* read word */ 101 if (addr & 0x01) { 102 return -EFAULT; 103 } 104 data = __raw_readw(addr); 105 break; 106 107 case GIODRV_IOCGGIODATA4: /* read long */ 108 if (addr & 0x03) { 109 return -EFAULT; 110 } 111 data = __raw_readl(addr); 112 break; 113 default: 114 return -EFAULT; 115 break; 116 } 117 118 if ((cmd & 0x01) == 0) { /* read */ 119 if (copy_to_user((int *)arg, &data, sizeof(int))) { 120 return -EFAULT; 121 } 122 } 123 return 0; 124} 125 126static const struct file_operations gio_fops = { 127 .owner = THIS_MODULE, 128 .open = gio_open, /* open */ 129 .release = gio_close, /* release */ 130 .unlocked_ioctl = gio_ioctl, 131 .llseek = noop_llseek, 132}; 133 134static int __init gio_init(void) 135{ 136 int error; 137 138 printk(KERN_INFO "gio: driver initialized\n"); 139 140 openCnt = 0; 141 142 if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) { 143 printk(KERN_ERR 144 "gio: Couldn't alloc_chrdev_region, error=%d\n", 145 error); 146 return 1; 147 } 148 149 cdev_p = cdev_alloc(); 150 cdev_p->ops = &gio_fops; 151 error = cdev_add(cdev_p, dev, DEVCOUNT); 152 if (error) { 153 printk(KERN_ERR 154 "gio: Couldn't cdev_add, error=%d\n", error); 155 return 1; 156 } 157 158 return 0; 159} 160 161static void __exit gio_exit(void) 162{ 163 cdev_del(cdev_p); 164 unregister_chrdev_region(dev, DEVCOUNT); 165} 166 167module_init(gio_init); 168module_exit(gio_exit); 169 170MODULE_LICENSE("GPL"); 171