Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
input
serio
ct82c710.c
Go to the documentation of this file.
1
/*
2
* Copyright (c) 1999-2001 Vojtech Pavlik
3
*/
4
5
/*
6
* 82C710 C&T mouse port chip driver for Linux
7
*/
8
9
/*
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
14
*
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
19
*
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
*
24
* Should you need to contact me, the author, you can do so either by
25
* e-mail - mail your message to <
[email protected]
>, or by paper mail:
26
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
27
*/
28
29
#include <
linux/delay.h
>
30
#include <linux/module.h>
31
#include <
linux/ioport.h
>
32
#include <
linux/init.h
>
33
#include <
linux/interrupt.h
>
34
#include <linux/serio.h>
35
#include <linux/errno.h>
36
#include <
linux/err.h
>
37
#include <
linux/platform_device.h
>
38
#include <linux/slab.h>
39
40
#include <asm/io.h>
41
42
MODULE_AUTHOR
(
"Vojtech Pavlik <
[email protected]
>"
);
43
MODULE_DESCRIPTION
(
"82C710 C&T mouse port chip driver"
);
44
MODULE_LICENSE
(
"GPL"
);
45
46
/*
47
* ct82c710 interface
48
*/
49
50
#define CT82C710_DEV_IDLE 0x01
/* Device Idle */
51
#define CT82C710_RX_FULL 0x02
/* Device Char received */
52
#define CT82C710_TX_IDLE 0x04
/* Device XMIT Idle */
53
#define CT82C710_RESET 0x08
/* Device Reset */
54
#define CT82C710_INTS_ON 0x10
/* Device Interrupt On */
55
#define CT82C710_ERROR_FLAG 0x20
/* Device Error */
56
#define CT82C710_CLEAR 0x40
/* Device Clear */
57
#define CT82C710_ENABLE 0x80
/* Device Enable */
58
59
#define CT82C710_IRQ 12
60
61
#define CT82C710_DATA ct82c710_iores.start
62
#define CT82C710_STATUS (ct82c710_iores.start + 1)
63
64
static
struct
serio
*ct82c710_port;
65
static
struct
platform_device
*ct82c710_device;
66
static
struct
resource
ct82c710_iores;
67
68
/*
69
* Interrupt handler for the 82C710 mouse port. A character
70
* is waiting in the 82C710.
71
*/
72
73
static
irqreturn_t
ct82c710_interrupt(
int
cpl,
void
*
dev_id
)
74
{
75
return
serio_interrupt
(ct82c710_port,
inb
(
CT82C710_DATA
), 0);
76
}
77
78
/*
79
* Wait for device to send output char and flush any input char.
80
*/
81
82
static
int
ct82c170_wait(
void
)
83
{
84
int
timeout
= 60000;
85
86
while
((
inb
(
CT82C710_STATUS
) & (
CT82C710_RX_FULL
|
CT82C710_TX_IDLE
|
CT82C710_DEV_IDLE
))
87
!= (
CT82C710_DEV_IDLE
|
CT82C710_TX_IDLE
) && timeout) {
88
89
if
(
inb_p
(
CT82C710_STATUS
) &
CT82C710_RX_FULL
)
inb_p
(
CT82C710_DATA
);
90
91
udelay
(1);
92
timeout--;
93
}
94
95
return
!timeout;
96
}
97
98
static
void
ct82c710_close(
struct
serio
*
serio
)
99
{
100
if
(ct82c170_wait())
101
printk
(
KERN_WARNING
"ct82c710.c: Device busy in close()\n"
);
102
103
outb_p
(
inb_p
(
CT82C710_STATUS
) & ~(
CT82C710_ENABLE
|
CT82C710_INTS_ON
),
CT82C710_STATUS
);
104
105
if
(ct82c170_wait())
106
printk
(
KERN_WARNING
"ct82c710.c: Device busy in close()\n"
);
107
108
free_irq
(
CT82C710_IRQ
,
NULL
);
109
}
110
111
static
int
ct82c710_open(
struct
serio *serio)
112
{
113
unsigned
char
status
;
114
int
err
;
115
116
err =
request_irq
(
CT82C710_IRQ
, ct82c710_interrupt, 0,
"ct82c710"
,
NULL
);
117
if
(err)
118
return
err
;
119
120
status =
inb_p
(
CT82C710_STATUS
);
121
122
status |= (
CT82C710_ENABLE
|
CT82C710_RESET
);
123
outb_p
(status,
CT82C710_STATUS
);
124
125
status &= ~(
CT82C710_RESET
);
126
outb_p
(status,
CT82C710_STATUS
);
127
128
status |=
CT82C710_INTS_ON
;
129
outb_p
(status,
CT82C710_STATUS
);
/* Enable interrupts */
130
131
while
(ct82c170_wait()) {
132
printk
(
KERN_ERR
"ct82c710: Device busy in open()\n"
);
133
status &= ~(
CT82C710_ENABLE
|
CT82C710_INTS_ON
);
134
outb_p
(status,
CT82C710_STATUS
);
135
free_irq
(
CT82C710_IRQ
,
NULL
);
136
return
-
EBUSY
;
137
}
138
139
return
0;
140
}
141
142
/*
143
* Write to the 82C710 mouse device.
144
*/
145
146
static
int
ct82c710_write(
struct
serio *
port
,
unsigned
char
c
)
147
{
148
if
(ct82c170_wait())
return
-1;
149
outb_p
(c,
CT82C710_DATA
);
150
return
0;
151
}
152
153
/*
154
* See if we can find a 82C710 device. Read mouse address.
155
*/
156
157
static
int
__init
ct82c710_detect(
void
)
158
{
159
outb_p
(0x55, 0x2fa);
/* Any value except 9, ff or 36 */
160
outb_p
(0xaa, 0x3fa);
/* Inverse of 55 */
161
outb_p
(0x36, 0x3fa);
/* Address the chip */
162
outb_p
(0xe4, 0x3fa);
/* 390/4; 390 = config address */
163
outb_p
(0x1b, 0x2fa);
/* Inverse of e4 */
164
outb_p
(0x0f, 0x390);
/* Write index */
165
if
(
inb_p
(0x391) != 0xe4)
/* Config address found? */
166
return
-
ENODEV
;
/* No: no 82C710 here */
167
168
outb_p
(0x0d, 0x390);
/* Write index */
169
ct82c710_iores.start =
inb_p
(0x391) << 2;
/* Get mouse I/O address */
170
ct82c710_iores.end = ct82c710_iores.start + 1;
171
ct82c710_iores.flags =
IORESOURCE_IO
;
172
outb_p
(0x0f, 0x390);
173
outb_p
(0x0f, 0x391);
/* Close config mode */
174
175
return
0;
176
}
177
178
static
int
__devinit
ct82c710_probe(
struct
platform_device
*
dev
)
179
{
180
ct82c710_port = kzalloc(
sizeof
(
struct
serio),
GFP_KERNEL
);
181
if
(!ct82c710_port)
182
return
-
ENOMEM
;
183
184
ct82c710_port->
id
.type =
SERIO_8042
;
185
ct82c710_port->
dev
.parent = &dev->
dev
;
186
ct82c710_port->
open
= ct82c710_open;
187
ct82c710_port->
close
= ct82c710_close;
188
ct82c710_port->
write
= ct82c710_write;
189
strlcpy
(ct82c710_port->
name
,
"C&T 82c710 mouse port"
,
190
sizeof
(ct82c710_port->
name
));
191
snprintf
(ct82c710_port->
phys
,
sizeof
(ct82c710_port->
phys
),
192
"isa%16llx/serio0"
, (
unsigned
long
long
)
CT82C710_DATA
);
193
194
serio_register_port
(ct82c710_port);
195
196
printk
(
KERN_INFO
"serio: C&T 82c710 mouse port at %#llx irq %d\n"
,
197
(
unsigned
long
long
)
CT82C710_DATA
,
CT82C710_IRQ
);
198
199
return
0;
200
}
201
202
static
int
__devexit
ct82c710_remove(
struct
platform_device
*dev)
203
{
204
serio_unregister_port
(ct82c710_port);
205
206
return
0;
207
}
208
209
static
struct
platform_driver
ct82c710_driver = {
210
.driver = {
211
.name =
"ct82c710"
,
212
.owner =
THIS_MODULE
,
213
},
214
.probe = ct82c710_probe,
215
.remove =
__devexit_p
(ct82c710_remove),
216
};
217
218
219
static
int
__init
ct82c710_init(
void
)
220
{
221
int
error
;
222
223
error = ct82c710_detect();
224
if
(error)
225
return
error
;
226
227
error =
platform_driver_register
(&ct82c710_driver);
228
if
(error)
229
return
error
;
230
231
ct82c710_device =
platform_device_alloc
(
"ct82c710"
, -1);
232
if
(!ct82c710_device) {
233
error = -
ENOMEM
;
234
goto
err_unregister_driver;
235
}
236
237
error =
platform_device_add_resources
(ct82c710_device, &ct82c710_iores, 1);
238
if
(error)
239
goto
err_free_device;
240
241
error =
platform_device_add
(ct82c710_device);
242
if
(error)
243
goto
err_free_device;
244
245
return
0;
246
247
err_free_device:
248
platform_device_put
(ct82c710_device);
249
err_unregister_driver:
250
platform_driver_unregister
(&ct82c710_driver);
251
return
error
;
252
}
253
254
static
void
__exit
ct82c710_exit(
void
)
255
{
256
platform_device_unregister
(ct82c710_device);
257
platform_driver_unregister
(&ct82c710_driver);
258
}
259
260
module_init
(ct82c710_init);
261
module_exit
(ct82c710_exit);
Generated on Thu Jan 10 2013 13:39:50 for Linux Kernel by
1.8.2