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