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(to: &data, from: (int *)arg, n: 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(val: (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(val: (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(val: 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(to: (int *)arg, from: &data, n: 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 | |