Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / sh / boards / mach-landisk / gio.c
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");