Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/sh/boards/mach-landisk/gio.c
15126 views
1
/*
2
* arch/sh/boards/landisk/gio.c - driver for landisk
3
*
4
* This driver will also support the I-O DATA Device, Inc. LANDISK Board.
5
* LANDISK and USL-5P Button, LED and GIO driver drive function.
6
*
7
* Copylight (C) 2006 kogiidena
8
* Copylight (C) 2002 Atom Create Engineering Co., Ltd. *
9
*
10
* This file is subject to the terms and conditions of the GNU General Public
11
* License. See the file "COPYING" in the main directory of this archive
12
* for more details.
13
*
14
*/
15
#include <linux/module.h>
16
#include <linux/init.h>
17
#include <linux/kdev_t.h>
18
#include <linux/cdev.h>
19
#include <linux/fs.h>
20
#include <asm/io.h>
21
#include <asm/uaccess.h>
22
#include <mach-landisk/mach/gio.h>
23
#include <mach-landisk/mach/iodata_landisk.h>
24
25
#define DEVCOUNT 4
26
#define GIO_MINOR 2 /* GIO minor no. */
27
28
static dev_t dev;
29
static struct cdev *cdev_p;
30
static int openCnt;
31
32
static int gio_open(struct inode *inode, struct file *filp)
33
{
34
int minor;
35
int ret = -ENOENT;
36
37
preempt_disable();
38
minor = MINOR(inode->i_rdev);
39
if (minor < DEVCOUNT) {
40
if (openCnt > 0) {
41
ret = -EALREADY;
42
} else {
43
openCnt++;
44
ret = 0;
45
}
46
}
47
preempt_enable();
48
return ret;
49
}
50
51
static int gio_close(struct inode *inode, struct file *filp)
52
{
53
int minor;
54
55
minor = MINOR(inode->i_rdev);
56
if (minor < DEVCOUNT) {
57
openCnt--;
58
}
59
return 0;
60
}
61
62
static long gio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
63
{
64
unsigned int data;
65
static unsigned int addr = 0;
66
67
if (cmd & 0x01) { /* write */
68
if (copy_from_user(&data, (int *)arg, sizeof(int))) {
69
return -EFAULT;
70
}
71
}
72
73
switch (cmd) {
74
case GIODRV_IOCSGIOSETADDR: /* address set */
75
addr = data;
76
break;
77
78
case GIODRV_IOCSGIODATA1: /* write byte */
79
__raw_writeb((unsigned char)(0x0ff & data), addr);
80
break;
81
82
case GIODRV_IOCSGIODATA2: /* write word */
83
if (addr & 0x01) {
84
return -EFAULT;
85
}
86
__raw_writew((unsigned short int)(0x0ffff & data), addr);
87
break;
88
89
case GIODRV_IOCSGIODATA4: /* write long */
90
if (addr & 0x03) {
91
return -EFAULT;
92
}
93
__raw_writel(data, addr);
94
break;
95
96
case GIODRV_IOCGGIODATA1: /* read byte */
97
data = __raw_readb(addr);
98
break;
99
100
case GIODRV_IOCGGIODATA2: /* read word */
101
if (addr & 0x01) {
102
return -EFAULT;
103
}
104
data = __raw_readw(addr);
105
break;
106
107
case GIODRV_IOCGGIODATA4: /* read long */
108
if (addr & 0x03) {
109
return -EFAULT;
110
}
111
data = __raw_readl(addr);
112
break;
113
default:
114
return -EFAULT;
115
break;
116
}
117
118
if ((cmd & 0x01) == 0) { /* read */
119
if (copy_to_user((int *)arg, &data, sizeof(int))) {
120
return -EFAULT;
121
}
122
}
123
return 0;
124
}
125
126
static const struct file_operations gio_fops = {
127
.owner = THIS_MODULE,
128
.open = gio_open, /* open */
129
.release = gio_close, /* release */
130
.unlocked_ioctl = gio_ioctl,
131
.llseek = noop_llseek,
132
};
133
134
static int __init gio_init(void)
135
{
136
int error;
137
138
printk(KERN_INFO "gio: driver initialized\n");
139
140
openCnt = 0;
141
142
if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) {
143
printk(KERN_ERR
144
"gio: Couldn't alloc_chrdev_region, error=%d\n",
145
error);
146
return 1;
147
}
148
149
cdev_p = cdev_alloc();
150
cdev_p->ops = &gio_fops;
151
error = cdev_add(cdev_p, dev, DEVCOUNT);
152
if (error) {
153
printk(KERN_ERR
154
"gio: Couldn't cdev_add, error=%d\n", error);
155
return 1;
156
}
157
158
return 0;
159
}
160
161
static void __exit gio_exit(void)
162
{
163
cdev_del(cdev_p);
164
unregister_chrdev_region(dev, DEVCOUNT);
165
}
166
167
module_init(gio_init);
168
module_exit(gio_exit);
169
170
MODULE_LICENSE("GPL");
171
172