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