gio.c (3251B)
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 24static dev_t dev; 25static struct cdev *cdev_p; 26static int openCnt; 27 28static 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 46static 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 56static 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 120static 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 128static 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 155static void __exit gio_exit(void) 156{ 157 cdev_del(cdev_p); 158 unregister_chrdev_region(dev, DEVCOUNT); 159} 160 161module_init(gio_init); 162module_exit(gio_exit); 163 164MODULE_LICENSE("GPL");