Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/sh/boards/mach-landisk/gio.c
26490 views
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
166