diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/input/serio |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/input/serio')
26 files changed, 8661 insertions, 0 deletions
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig new file mode 100644 index 000000000000..b3710733b36b --- /dev/null +++ b/drivers/input/serio/Kconfig | |||
@@ -0,0 +1,183 @@ | |||
1 | # | ||
2 | # Input core configuration | ||
3 | # | ||
4 | config SERIO | ||
5 | tristate "Serial I/O support" if EMBEDDED || !X86 | ||
6 | default y | ||
7 | ---help--- | ||
8 | Say Yes here if you have any input device that uses serial I/O to | ||
9 | communicate with the system. This includes the | ||
10 | * standard AT keyboard and PS/2 mouse * | ||
11 | as well as serial mice, Sun keyboards, some joysticks and 6dof | ||
12 | devices and more. | ||
13 | |||
14 | If unsure, say Y. | ||
15 | |||
16 | To compile this driver as a module, choose M here: the | ||
17 | module will be called serio. | ||
18 | |||
19 | if SERIO | ||
20 | |||
21 | config SERIO_I8042 | ||
22 | tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 | ||
23 | default y | ||
24 | depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K | ||
25 | ---help--- | ||
26 | i8042 is the chip over which the standard AT keyboard and PS/2 | ||
27 | mouse are connected to the computer. If you use these devices, | ||
28 | you'll need to say Y here. | ||
29 | |||
30 | If unsure, say Y. | ||
31 | |||
32 | To compile this driver as a module, choose M here: the | ||
33 | module will be called i8042. | ||
34 | |||
35 | config SERIO_SERPORT | ||
36 | tristate "Serial port line discipline" | ||
37 | default y | ||
38 | ---help--- | ||
39 | Say Y here if you plan to use an input device (mouse, joystick, | ||
40 | tablet, 6dof) that communicates over the RS232 serial (COM) port. | ||
41 | |||
42 | More information is available: <file:Documentation/input/input.txt> | ||
43 | |||
44 | If unsure, say Y. | ||
45 | |||
46 | To compile this driver as a module, choose M here: the | ||
47 | module will be called serport. | ||
48 | |||
49 | config SERIO_CT82C710 | ||
50 | tristate "ct82c710 Aux port controller" | ||
51 | depends on X86 | ||
52 | ---help--- | ||
53 | Say Y here if you have a Texas Instruments TravelMate notebook | ||
54 | equipped with the ct82c710 chip and want to use a mouse connected | ||
55 | to the "QuickPort". | ||
56 | |||
57 | If unsure, say N. | ||
58 | |||
59 | To compile this driver as a module, choose M here: the | ||
60 | module will be called ct82c710. | ||
61 | |||
62 | config SERIO_Q40KBD | ||
63 | tristate "Q40 keyboard controller" | ||
64 | depends on Q40 | ||
65 | |||
66 | config SERIO_PARKBD | ||
67 | tristate "Parallel port keyboard adapter" | ||
68 | depends on PARPORT | ||
69 | ---help--- | ||
70 | Say Y here if you built a simple parallel port adapter to attach | ||
71 | an additional AT keyboard, XT keyboard or PS/2 mouse. | ||
72 | |||
73 | More information is available: <file:Documentation/input/input.txt> | ||
74 | |||
75 | If unsure, say N. | ||
76 | |||
77 | To compile this driver as a module, choose M here: the | ||
78 | module will be called parkbd. | ||
79 | |||
80 | config SERIO_RPCKBD | ||
81 | tristate "Acorn RiscPC keyboard controller" | ||
82 | depends on ARCH_ACORN || ARCH_CLPS7500 | ||
83 | default y | ||
84 | help | ||
85 | Say Y here if you have the Acorn RiscPC and want to use an AT | ||
86 | keyboard connected to its keyboard controller. | ||
87 | |||
88 | To compile this driver as a module, choose M here: the | ||
89 | module will be called rpckbd. | ||
90 | |||
91 | config SERIO_AMBAKMI | ||
92 | tristate "AMBA KMI keyboard controller" | ||
93 | depends on ARM_AMBA | ||
94 | |||
95 | config SERIO_SA1111 | ||
96 | tristate "Intel SA1111 keyboard controller" | ||
97 | depends on SA1111 | ||
98 | |||
99 | config SERIO_GSCPS2 | ||
100 | tristate "HP GSC PS/2 keyboard and PS/2 mouse controller" | ||
101 | depends on GSC | ||
102 | default y | ||
103 | help | ||
104 | This driver provides support for the PS/2 ports on PA-RISC machines | ||
105 | over which HP PS/2 keyboards and PS/2 mice may be connected. | ||
106 | If you use these devices, you'll need to say Y here. | ||
107 | |||
108 | It's safe to enable this driver, so if unsure, say Y. | ||
109 | |||
110 | To compile this driver as a module, choose M here: the | ||
111 | module will be called gscps2. | ||
112 | |||
113 | config HP_SDC | ||
114 | tristate "HP System Device Controller i8042 Support" | ||
115 | depends on GSC && SERIO | ||
116 | default y | ||
117 | ---help--- | ||
118 | This option enables supports for the the "System Device | ||
119 | Controller", an i8042 carrying microcode to manage a | ||
120 | few miscellanous devices on some Hewlett Packard systems. | ||
121 | The SDC itself contains a 10ms resolution timer/clock capable | ||
122 | of delivering interrupts on a periodic and one-shot basis. | ||
123 | The SDC may also be connected to a battery-backed real-time | ||
124 | clock, a basic audio waveform generator, and an HP-HIL Master | ||
125 | Link Controller serving up to seven input devices. | ||
126 | |||
127 | By itself this option is rather useless, but enabling it will | ||
128 | enable selection of drivers for the abovementioned devices. | ||
129 | It is, however, incompatible with the old, reliable HIL keyboard | ||
130 | driver, and the new HIL driver is experimental, so if you plan | ||
131 | to use a HIL keyboard as your primary keyboard, you may wish | ||
132 | to keep using that driver until the new HIL drivers have had | ||
133 | more testing. | ||
134 | |||
135 | config HIL_MLC | ||
136 | tristate "HIL MLC Support (needed for HIL input devices)" | ||
137 | depends on HP_SDC | ||
138 | |||
139 | config SERIO_PCIPS2 | ||
140 | tristate "PCI PS/2 keyboard and PS/2 mouse controller" | ||
141 | depends on PCI | ||
142 | help | ||
143 | Say Y here if you have a Mobility Docking station with PS/2 | ||
144 | keyboard and mice ports. | ||
145 | |||
146 | To compile this driver as a module, choose M here: the | ||
147 | module will be called pcips2. | ||
148 | |||
149 | config SERIO_MACEPS2 | ||
150 | tristate "SGI O2 MACE PS/2 controller" | ||
151 | depends on SGI_IP32 | ||
152 | help | ||
153 | Say Y here if you have SGI O2 workstation and want to use its | ||
154 | PS/2 ports. | ||
155 | |||
156 | To compile this driver as a module, choose M here: the | ||
157 | module will be called maceps2. | ||
158 | |||
159 | config SERIO_LIBPS2 | ||
160 | tristate "PS/2 driver library" if EMBEDDED | ||
161 | help | ||
162 | Say Y here if you are using a driver for device connected | ||
163 | to a PS/2 port, such as PS/2 mouse or standard AT keyboard. | ||
164 | |||
165 | To compile this driver as a module, choose M here: the | ||
166 | module will be called libps2. | ||
167 | |||
168 | config SERIO_RAW | ||
169 | tristate "Raw access to serio ports" | ||
170 | help | ||
171 | Say Y here if you want to have raw access to serio ports, such as | ||
172 | AUX ports on i8042 keyboard controller. Each serio port that is | ||
173 | bound to this driver will be accessible via a char device with | ||
174 | major 10 and dynamically allocated minor. The driver will try | ||
175 | allocating minor 1 (that historically corresponds to /dev/psaux) | ||
176 | first. To bind this driver to a serio port use sysfs interface: | ||
177 | |||
178 | echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver | ||
179 | |||
180 | To compile this driver as a module, choose M here: the | ||
181 | module will be called serio_raw. | ||
182 | |||
183 | endif | ||
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile new file mode 100644 index 000000000000..678a8599f9ff --- /dev/null +++ b/drivers/input/serio/Makefile | |||
@@ -0,0 +1,23 @@ | |||
1 | # | ||
2 | # Makefile for the input core drivers. | ||
3 | # | ||
4 | |||
5 | # Each configuration option enables a list of files. | ||
6 | |||
7 | obj-$(CONFIG_SERIO) += serio.o | ||
8 | obj-$(CONFIG_SERIO_I8042) += i8042.o | ||
9 | obj-$(CONFIG_SERIO_PARKBD) += parkbd.o | ||
10 | obj-$(CONFIG_SERIO_SERPORT) += serport.o | ||
11 | obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o | ||
12 | obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o | ||
13 | obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o | ||
14 | obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o | ||
15 | obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o | ||
16 | obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o | ||
17 | obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o | ||
18 | obj-$(CONFIG_HP_SDC) += hp_sdc.o | ||
19 | obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o | ||
20 | obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o | ||
21 | obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o | ||
22 | obj-$(CONFIG_SERIO_LIBPS2) += libps2.o | ||
23 | obj-$(CONFIG_SERIO_RAW) += serio_raw.o | ||
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c new file mode 100644 index 000000000000..9b1ab5e7a98d --- /dev/null +++ b/drivers/input/serio/ambakmi.c | |||
@@ -0,0 +1,231 @@ | |||
1 | /* | ||
2 | * linux/drivers/input/serio/ambakmi.c | ||
3 | * | ||
4 | * Copyright (C) 2000-2003 Deep Blue Solutions Ltd. | ||
5 | * Copyright (C) 2002 Russell King. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/serio.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/err.h> | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include <asm/irq.h> | ||
25 | #include <asm/hardware/amba.h> | ||
26 | #include <asm/hardware/amba_kmi.h> | ||
27 | #include <asm/hardware/clock.h> | ||
28 | |||
29 | #define KMI_BASE (kmi->base) | ||
30 | |||
31 | struct amba_kmi_port { | ||
32 | struct serio *io; | ||
33 | struct clk *clk; | ||
34 | void __iomem *base; | ||
35 | unsigned int irq; | ||
36 | unsigned int divisor; | ||
37 | unsigned int open; | ||
38 | }; | ||
39 | |||
40 | static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) | ||
41 | { | ||
42 | struct amba_kmi_port *kmi = dev_id; | ||
43 | unsigned int status = readb(KMIIR); | ||
44 | int handled = IRQ_NONE; | ||
45 | |||
46 | while (status & KMIIR_RXINTR) { | ||
47 | serio_interrupt(kmi->io, readb(KMIDATA), 0, regs); | ||
48 | status = readb(KMIIR); | ||
49 | handled = IRQ_HANDLED; | ||
50 | } | ||
51 | |||
52 | return handled; | ||
53 | } | ||
54 | |||
55 | static int amba_kmi_write(struct serio *io, unsigned char val) | ||
56 | { | ||
57 | struct amba_kmi_port *kmi = io->port_data; | ||
58 | unsigned int timeleft = 10000; /* timeout in 100ms */ | ||
59 | |||
60 | while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--) | ||
61 | udelay(10); | ||
62 | |||
63 | if (timeleft) | ||
64 | writeb(val, KMIDATA); | ||
65 | |||
66 | return timeleft ? 0 : SERIO_TIMEOUT; | ||
67 | } | ||
68 | |||
69 | static int amba_kmi_open(struct serio *io) | ||
70 | { | ||
71 | struct amba_kmi_port *kmi = io->port_data; | ||
72 | unsigned int divisor; | ||
73 | int ret; | ||
74 | |||
75 | ret = clk_use(kmi->clk); | ||
76 | if (ret) | ||
77 | goto out; | ||
78 | |||
79 | ret = clk_enable(kmi->clk); | ||
80 | if (ret) | ||
81 | goto clk_unuse; | ||
82 | |||
83 | divisor = clk_get_rate(kmi->clk) / 8000000 - 1; | ||
84 | writeb(divisor, KMICLKDIV); | ||
85 | writeb(KMICR_EN, KMICR); | ||
86 | |||
87 | ret = request_irq(kmi->irq, amba_kmi_int, 0, "kmi-pl050", kmi); | ||
88 | if (ret) { | ||
89 | printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq); | ||
90 | writeb(0, KMICR); | ||
91 | goto clk_disable; | ||
92 | } | ||
93 | |||
94 | writeb(KMICR_EN | KMICR_RXINTREN, KMICR); | ||
95 | |||
96 | return 0; | ||
97 | |||
98 | clk_disable: | ||
99 | clk_disable(kmi->clk); | ||
100 | clk_unuse: | ||
101 | clk_unuse(kmi->clk); | ||
102 | out: | ||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | static void amba_kmi_close(struct serio *io) | ||
107 | { | ||
108 | struct amba_kmi_port *kmi = io->port_data; | ||
109 | |||
110 | writeb(0, KMICR); | ||
111 | |||
112 | free_irq(kmi->irq, kmi); | ||
113 | clk_disable(kmi->clk); | ||
114 | clk_unuse(kmi->clk); | ||
115 | } | ||
116 | |||
117 | static int amba_kmi_probe(struct amba_device *dev, void *id) | ||
118 | { | ||
119 | struct amba_kmi_port *kmi; | ||
120 | struct serio *io; | ||
121 | int ret; | ||
122 | |||
123 | ret = amba_request_regions(dev, NULL); | ||
124 | if (ret) | ||
125 | return ret; | ||
126 | |||
127 | kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); | ||
128 | io = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
129 | if (!kmi || !io) { | ||
130 | ret = -ENOMEM; | ||
131 | goto out; | ||
132 | } | ||
133 | |||
134 | memset(kmi, 0, sizeof(struct amba_kmi_port)); | ||
135 | memset(io, 0, sizeof(struct serio)); | ||
136 | |||
137 | io->id.type = SERIO_8042; | ||
138 | io->write = amba_kmi_write; | ||
139 | io->open = amba_kmi_open; | ||
140 | io->close = amba_kmi_close; | ||
141 | strlcpy(io->name, dev->dev.bus_id, sizeof(io->name)); | ||
142 | strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys)); | ||
143 | io->port_data = kmi; | ||
144 | io->dev.parent = &dev->dev; | ||
145 | |||
146 | kmi->io = io; | ||
147 | kmi->base = ioremap(dev->res.start, KMI_SIZE); | ||
148 | if (!kmi->base) { | ||
149 | ret = -ENOMEM; | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | kmi->clk = clk_get(&dev->dev, "KMIREFCLK"); | ||
154 | if (IS_ERR(kmi->clk)) { | ||
155 | ret = PTR_ERR(kmi->clk); | ||
156 | goto unmap; | ||
157 | } | ||
158 | |||
159 | kmi->irq = dev->irq[0]; | ||
160 | amba_set_drvdata(dev, kmi); | ||
161 | |||
162 | serio_register_port(kmi->io); | ||
163 | return 0; | ||
164 | |||
165 | unmap: | ||
166 | iounmap(kmi->base); | ||
167 | out: | ||
168 | kfree(kmi); | ||
169 | kfree(io); | ||
170 | amba_release_regions(dev); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | static int amba_kmi_remove(struct amba_device *dev) | ||
175 | { | ||
176 | struct amba_kmi_port *kmi = amba_get_drvdata(dev); | ||
177 | |||
178 | amba_set_drvdata(dev, NULL); | ||
179 | |||
180 | serio_unregister_port(kmi->io); | ||
181 | clk_put(kmi->clk); | ||
182 | iounmap(kmi->base); | ||
183 | kfree(kmi); | ||
184 | amba_release_regions(dev); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static int amba_kmi_resume(struct amba_device *dev) | ||
189 | { | ||
190 | struct amba_kmi_port *kmi = amba_get_drvdata(dev); | ||
191 | |||
192 | /* kick the serio layer to rescan this port */ | ||
193 | serio_reconnect(kmi->io); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static struct amba_id amba_kmi_idtable[] = { | ||
199 | { | ||
200 | .id = 0x00041050, | ||
201 | .mask = 0x000fffff, | ||
202 | }, | ||
203 | { 0, 0 } | ||
204 | }; | ||
205 | |||
206 | static struct amba_driver ambakmi_driver = { | ||
207 | .drv = { | ||
208 | .name = "kmi-pl050", | ||
209 | }, | ||
210 | .id_table = amba_kmi_idtable, | ||
211 | .probe = amba_kmi_probe, | ||
212 | .remove = amba_kmi_remove, | ||
213 | .resume = amba_kmi_resume, | ||
214 | }; | ||
215 | |||
216 | static int __init amba_kmi_init(void) | ||
217 | { | ||
218 | return amba_driver_register(&ambakmi_driver); | ||
219 | } | ||
220 | |||
221 | static void __exit amba_kmi_exit(void) | ||
222 | { | ||
223 | amba_driver_unregister(&ambakmi_driver); | ||
224 | } | ||
225 | |||
226 | module_init(amba_kmi_init); | ||
227 | module_exit(amba_kmi_exit); | ||
228 | |||
229 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); | ||
230 | MODULE_DESCRIPTION("AMBA KMI controller driver"); | ||
231 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c new file mode 100644 index 000000000000..dd0f5bd90241 --- /dev/null +++ b/drivers/input/serio/ct82c710.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * $Id: ct82c710.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 82C710 C&T mouse port chip driver for Linux | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | * Should you need to contact me, the author, you can do so either by | ||
27 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
28 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
29 | */ | ||
30 | |||
31 | #include <linux/delay.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/ioport.h> | ||
34 | #include <linux/config.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/serio.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/err.h> | ||
40 | |||
41 | #include <asm/io.h> | ||
42 | |||
43 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
44 | MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); | ||
45 | MODULE_LICENSE("GPL"); | ||
46 | |||
47 | /* | ||
48 | * ct82c710 interface | ||
49 | */ | ||
50 | |||
51 | #define CT82C710_DEV_IDLE 0x01 /* Device Idle */ | ||
52 | #define CT82C710_RX_FULL 0x02 /* Device Char received */ | ||
53 | #define CT82C710_TX_IDLE 0x04 /* Device XMIT Idle */ | ||
54 | #define CT82C710_RESET 0x08 /* Device Reset */ | ||
55 | #define CT82C710_INTS_ON 0x10 /* Device Interrupt On */ | ||
56 | #define CT82C710_ERROR_FLAG 0x20 /* Device Error */ | ||
57 | #define CT82C710_CLEAR 0x40 /* Device Clear */ | ||
58 | #define CT82C710_ENABLE 0x80 /* Device Enable */ | ||
59 | |||
60 | #define CT82C710_IRQ 12 | ||
61 | |||
62 | #define CT82C710_DATA ct82c710_iores.start | ||
63 | #define CT82C710_STATUS (ct82c710_iores.start + 1) | ||
64 | |||
65 | static struct serio *ct82c710_port; | ||
66 | static struct platform_device *ct82c710_device; | ||
67 | static struct resource ct82c710_iores; | ||
68 | |||
69 | /* | ||
70 | * Interrupt handler for the 82C710 mouse port. A character | ||
71 | * is waiting in the 82C710. | ||
72 | */ | ||
73 | |||
74 | static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) | ||
75 | { | ||
76 | return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs); | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * Wait for device to send output char and flush any input char. | ||
81 | */ | ||
82 | |||
83 | static int ct82c170_wait(void) | ||
84 | { | ||
85 | int timeout = 60000; | ||
86 | |||
87 | while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) | ||
88 | != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) { | ||
89 | |||
90 | if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA); | ||
91 | |||
92 | udelay(1); | ||
93 | timeout--; | ||
94 | } | ||
95 | |||
96 | return !timeout; | ||
97 | } | ||
98 | |||
99 | static void ct82c710_close(struct serio *serio) | ||
100 | { | ||
101 | if (ct82c170_wait()) | ||
102 | printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); | ||
103 | |||
104 | outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS); | ||
105 | |||
106 | if (ct82c170_wait()) | ||
107 | printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); | ||
108 | |||
109 | free_irq(CT82C710_IRQ, NULL); | ||
110 | } | ||
111 | |||
112 | static int ct82c710_open(struct serio *serio) | ||
113 | { | ||
114 | unsigned char status; | ||
115 | |||
116 | if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) | ||
117 | return -1; | ||
118 | |||
119 | status = inb_p(CT82C710_STATUS); | ||
120 | |||
121 | status |= (CT82C710_ENABLE | CT82C710_RESET); | ||
122 | outb_p(status, CT82C710_STATUS); | ||
123 | |||
124 | status &= ~(CT82C710_RESET); | ||
125 | outb_p(status, CT82C710_STATUS); | ||
126 | |||
127 | status |= CT82C710_INTS_ON; | ||
128 | outb_p(status, CT82C710_STATUS); /* Enable interrupts */ | ||
129 | |||
130 | while (ct82c170_wait()) { | ||
131 | printk(KERN_ERR "ct82c710: Device busy in open()\n"); | ||
132 | status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); | ||
133 | outb_p(status, CT82C710_STATUS); | ||
134 | free_irq(CT82C710_IRQ, NULL); | ||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * Write to the 82C710 mouse device. | ||
143 | */ | ||
144 | |||
145 | static int ct82c710_write(struct serio *port, unsigned char c) | ||
146 | { | ||
147 | if (ct82c170_wait()) return -1; | ||
148 | outb_p(c, CT82C710_DATA); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * See if we can find a 82C710 device. Read mouse address. | ||
154 | */ | ||
155 | |||
156 | static int __init ct82c710_probe(void) | ||
157 | { | ||
158 | outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ | ||
159 | outb_p(0xaa, 0x3fa); /* Inverse of 55 */ | ||
160 | outb_p(0x36, 0x3fa); /* Address the chip */ | ||
161 | outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ | ||
162 | outb_p(0x1b, 0x2fa); /* Inverse of e4 */ | ||
163 | outb_p(0x0f, 0x390); /* Write index */ | ||
164 | if (inb_p(0x391) != 0xe4) /* Config address found? */ | ||
165 | return -1; /* No: no 82C710 here */ | ||
166 | |||
167 | outb_p(0x0d, 0x390); /* Write index */ | ||
168 | ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */ | ||
169 | ct82c710_iores.end = ct82c710_iores.start + 1; | ||
170 | ct82c710_iores.flags = IORESOURCE_IO; | ||
171 | outb_p(0x0f, 0x390); | ||
172 | outb_p(0x0f, 0x391); /* Close config mode */ | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static struct serio * __init ct82c710_allocate_port(void) | ||
178 | { | ||
179 | struct serio *serio; | ||
180 | |||
181 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
182 | if (serio) { | ||
183 | memset(serio, 0, sizeof(struct serio)); | ||
184 | serio->id.type = SERIO_8042; | ||
185 | serio->open = ct82c710_open; | ||
186 | serio->close = ct82c710_close; | ||
187 | serio->write = ct82c710_write; | ||
188 | serio->dev.parent = &ct82c710_device->dev; | ||
189 | strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name)); | ||
190 | snprintf(serio->phys, sizeof(serio->phys), "isa%04lx/serio0", CT82C710_DATA); | ||
191 | } | ||
192 | |||
193 | return serio; | ||
194 | } | ||
195 | |||
196 | static int __init ct82c710_init(void) | ||
197 | { | ||
198 | if (ct82c710_probe()) | ||
199 | return -ENODEV; | ||
200 | |||
201 | ct82c710_device = platform_device_register_simple("ct82c710", -1, &ct82c710_iores, 1); | ||
202 | if (IS_ERR(ct82c710_device)) | ||
203 | return PTR_ERR(ct82c710_device); | ||
204 | |||
205 | if (!(ct82c710_port = ct82c710_allocate_port())) { | ||
206 | platform_device_unregister(ct82c710_device); | ||
207 | return -ENOMEM; | ||
208 | } | ||
209 | |||
210 | serio_register_port(ct82c710_port); | ||
211 | |||
212 | printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n", | ||
213 | CT82C710_DATA, CT82C710_IRQ); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void __exit ct82c710_exit(void) | ||
219 | { | ||
220 | serio_unregister_port(ct82c710_port); | ||
221 | platform_device_unregister(ct82c710_device); | ||
222 | } | ||
223 | |||
224 | module_init(ct82c710_init); | ||
225 | module_exit(ct82c710_exit); | ||
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c new file mode 100644 index 000000000000..897e4c12b642 --- /dev/null +++ b/drivers/input/serio/gscps2.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | * drivers/input/serio/gscps2.c | ||
3 | * | ||
4 | * Copyright (c) 2004 Helge Deller <deller@gmx.de> | ||
5 | * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr> | ||
6 | * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org> | ||
7 | * | ||
8 | * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c | ||
9 | * Copyright (c) 1999 Alex deVries <alex@onefishtwo.ca> | ||
10 | * Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org> | ||
11 | * Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr> | ||
12 | * Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr> | ||
13 | * | ||
14 | * HP GSC PS/2 port driver, found in PA/RISC Workstations | ||
15 | * | ||
16 | * This file is subject to the terms and conditions of the GNU General Public | ||
17 | * License. See the file "COPYING" in the main directory of this archive | ||
18 | * for more details. | ||
19 | * | ||
20 | * TODO: | ||
21 | * - Dino testing (did HP ever shipped a machine on which this port | ||
22 | * was usable/enabled ?) | ||
23 | */ | ||
24 | |||
25 | #include <linux/config.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/serio.h> | ||
29 | #include <linux/input.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/ioport.h> | ||
34 | #include <linux/pci_ids.h> | ||
35 | |||
36 | #include <asm/irq.h> | ||
37 | #include <asm/io.h> | ||
38 | #include <asm/parisc-device.h> | ||
39 | |||
40 | MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@parisc-linux.org>, Helge Deller <deller@gmx.de>"); | ||
41 | MODULE_DESCRIPTION("HP GSC PS2 port driver"); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); | ||
44 | |||
45 | #define PFX "gscps2.c: " | ||
46 | |||
47 | /* | ||
48 | * Driver constants | ||
49 | */ | ||
50 | |||
51 | /* various constants */ | ||
52 | #define ENABLE 1 | ||
53 | #define DISABLE 0 | ||
54 | |||
55 | #define GSC_DINO_OFFSET 0x0800 /* offset for DINO controller versus LASI one */ | ||
56 | |||
57 | /* PS/2 IO port offsets */ | ||
58 | #define GSC_ID 0x00 /* device ID offset (see: GSC_ID_XXX) */ | ||
59 | #define GSC_RESET 0x00 /* reset port offset */ | ||
60 | #define GSC_RCVDATA 0x04 /* receive port offset */ | ||
61 | #define GSC_XMTDATA 0x04 /* transmit port offset */ | ||
62 | #define GSC_CONTROL 0x08 /* see: Control register bits */ | ||
63 | #define GSC_STATUS 0x0C /* see: Status register bits */ | ||
64 | |||
65 | /* Control register bits */ | ||
66 | #define GSC_CTRL_ENBL 0x01 /* enable interface */ | ||
67 | #define GSC_CTRL_LPBXR 0x02 /* loopback operation */ | ||
68 | #define GSC_CTRL_DIAG 0x20 /* directly control clock/data line */ | ||
69 | #define GSC_CTRL_DATDIR 0x40 /* data line direct control */ | ||
70 | #define GSC_CTRL_CLKDIR 0x80 /* clock line direct control */ | ||
71 | |||
72 | /* Status register bits */ | ||
73 | #define GSC_STAT_RBNE 0x01 /* Receive Buffer Not Empty */ | ||
74 | #define GSC_STAT_TBNE 0x02 /* Transmit Buffer Not Empty */ | ||
75 | #define GSC_STAT_TERR 0x04 /* Timeout Error */ | ||
76 | #define GSC_STAT_PERR 0x08 /* Parity Error */ | ||
77 | #define GSC_STAT_CMPINTR 0x10 /* Composite Interrupt = irq on any port */ | ||
78 | #define GSC_STAT_DATSHD 0x40 /* Data Line Shadow */ | ||
79 | #define GSC_STAT_CLKSHD 0x80 /* Clock Line Shadow */ | ||
80 | |||
81 | /* IDs returned by GSC_ID port register */ | ||
82 | #define GSC_ID_KEYBOARD 0 /* device ID values */ | ||
83 | #define GSC_ID_MOUSE 1 | ||
84 | |||
85 | |||
86 | static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs); | ||
87 | |||
88 | #define BUFFER_SIZE 0x0f | ||
89 | |||
90 | /* GSC PS/2 port device struct */ | ||
91 | struct gscps2port { | ||
92 | struct list_head node; | ||
93 | struct parisc_device *padev; | ||
94 | struct serio *port; | ||
95 | spinlock_t lock; | ||
96 | char *addr; | ||
97 | u8 act, append; /* position in buffer[] */ | ||
98 | struct { | ||
99 | u8 data; | ||
100 | u8 str; | ||
101 | } buffer[BUFFER_SIZE+1]; | ||
102 | int id; | ||
103 | }; | ||
104 | |||
105 | /* | ||
106 | * Various HW level routines | ||
107 | */ | ||
108 | |||
109 | #define gscps2_readb_input(x) readb((x)+GSC_RCVDATA) | ||
110 | #define gscps2_readb_control(x) readb((x)+GSC_CONTROL) | ||
111 | #define gscps2_readb_status(x) readb((x)+GSC_STATUS) | ||
112 | #define gscps2_writeb_control(x, y) writeb((x), (y)+GSC_CONTROL) | ||
113 | |||
114 | |||
115 | /* | ||
116 | * wait_TBE() - wait for Transmit Buffer Empty | ||
117 | */ | ||
118 | |||
119 | static int wait_TBE(char *addr) | ||
120 | { | ||
121 | int timeout = 25000; /* device is expected to react within 250 msec */ | ||
122 | while (gscps2_readb_status(addr) & GSC_STAT_TBNE) { | ||
123 | if (!--timeout) | ||
124 | return 0; /* This should not happen */ | ||
125 | udelay(10); | ||
126 | } | ||
127 | return 1; | ||
128 | } | ||
129 | |||
130 | |||
131 | /* | ||
132 | * gscps2_flush() - flush the receive buffer | ||
133 | */ | ||
134 | |||
135 | static void gscps2_flush(struct gscps2port *ps2port) | ||
136 | { | ||
137 | while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE) | ||
138 | gscps2_readb_input(ps2port->addr); | ||
139 | ps2port->act = ps2port->append = 0; | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * gscps2_writeb_output() - write a byte to the port | ||
144 | * | ||
145 | * returns 1 on sucess, 0 on error | ||
146 | */ | ||
147 | |||
148 | static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data) | ||
149 | { | ||
150 | unsigned long flags; | ||
151 | char *addr = ps2port->addr; | ||
152 | |||
153 | if (!wait_TBE(addr)) { | ||
154 | printk(KERN_DEBUG PFX "timeout - could not write byte %#x\n", data); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE) | ||
159 | /* wait */; | ||
160 | |||
161 | spin_lock_irqsave(&ps2port->lock, flags); | ||
162 | writeb(data, addr+GSC_XMTDATA); | ||
163 | spin_unlock_irqrestore(&ps2port->lock, flags); | ||
164 | |||
165 | /* this is ugly, but due to timing of the port it seems to be necessary. */ | ||
166 | mdelay(6); | ||
167 | |||
168 | /* make sure any received data is returned as fast as possible */ | ||
169 | /* this is important e.g. when we set the LEDs on the keyboard */ | ||
170 | gscps2_interrupt(0, NULL, NULL); | ||
171 | |||
172 | return 1; | ||
173 | } | ||
174 | |||
175 | |||
176 | /* | ||
177 | * gscps2_enable() - enables or disables the port | ||
178 | */ | ||
179 | |||
180 | static void gscps2_enable(struct gscps2port *ps2port, int enable) | ||
181 | { | ||
182 | unsigned long flags; | ||
183 | u8 data; | ||
184 | |||
185 | /* now enable/disable the port */ | ||
186 | spin_lock_irqsave(&ps2port->lock, flags); | ||
187 | gscps2_flush(ps2port); | ||
188 | data = gscps2_readb_control(ps2port->addr); | ||
189 | if (enable) | ||
190 | data |= GSC_CTRL_ENBL; | ||
191 | else | ||
192 | data &= ~GSC_CTRL_ENBL; | ||
193 | gscps2_writeb_control(data, ps2port->addr); | ||
194 | spin_unlock_irqrestore(&ps2port->lock, flags); | ||
195 | wait_TBE(ps2port->addr); | ||
196 | gscps2_flush(ps2port); | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * gscps2_reset() - resets the PS/2 port | ||
201 | */ | ||
202 | |||
203 | static void gscps2_reset(struct gscps2port *ps2port) | ||
204 | { | ||
205 | char *addr = ps2port->addr; | ||
206 | unsigned long flags; | ||
207 | |||
208 | /* reset the interface */ | ||
209 | spin_lock_irqsave(&ps2port->lock, flags); | ||
210 | gscps2_flush(ps2port); | ||
211 | writeb(0xff, addr+GSC_RESET); | ||
212 | gscps2_flush(ps2port); | ||
213 | spin_unlock_irqrestore(&ps2port->lock, flags); | ||
214 | |||
215 | /* enable it */ | ||
216 | gscps2_enable(ps2port, ENABLE); | ||
217 | } | ||
218 | |||
219 | static LIST_HEAD(ps2port_list); | ||
220 | |||
221 | /** | ||
222 | * gscps2_interrupt() - Interruption service routine | ||
223 | * | ||
224 | * This function reads received PS/2 bytes and processes them on | ||
225 | * all interfaces. | ||
226 | * The problematic part here is, that the keyboard and mouse PS/2 port | ||
227 | * share the same interrupt and it's not possible to send data if any | ||
228 | * one of them holds input data. To solve this problem we try to receive | ||
229 | * the data as fast as possible and handle the reporting to the upper layer | ||
230 | * later. | ||
231 | */ | ||
232 | |||
233 | static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
234 | { | ||
235 | struct gscps2port *ps2port; | ||
236 | |||
237 | list_for_each_entry(ps2port, &ps2port_list, node) { | ||
238 | |||
239 | unsigned long flags; | ||
240 | spin_lock_irqsave(&ps2port->lock, flags); | ||
241 | |||
242 | while ( (ps2port->buffer[ps2port->append].str = | ||
243 | gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) { | ||
244 | ps2port->buffer[ps2port->append].data = | ||
245 | gscps2_readb_input(ps2port->addr); | ||
246 | ps2port->append = ((ps2port->append+1) & BUFFER_SIZE); | ||
247 | } | ||
248 | |||
249 | spin_unlock_irqrestore(&ps2port->lock, flags); | ||
250 | |||
251 | } /* list_for_each_entry */ | ||
252 | |||
253 | /* all data was read from the ports - now report the data to upper layer */ | ||
254 | |||
255 | list_for_each_entry(ps2port, &ps2port_list, node) { | ||
256 | |||
257 | while (ps2port->act != ps2port->append) { | ||
258 | |||
259 | unsigned int rxflags; | ||
260 | u8 data, status; | ||
261 | |||
262 | /* Did new data arrived while we read existing data ? | ||
263 | If yes, exit now and let the new irq handler start over again */ | ||
264 | if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR) | ||
265 | return IRQ_HANDLED; | ||
266 | |||
267 | status = ps2port->buffer[ps2port->act].str; | ||
268 | data = ps2port->buffer[ps2port->act].data; | ||
269 | |||
270 | ps2port->act = ((ps2port->act+1) & BUFFER_SIZE); | ||
271 | rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | | ||
272 | ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); | ||
273 | |||
274 | serio_interrupt(ps2port->port, data, rxflags, regs); | ||
275 | |||
276 | } /* while() */ | ||
277 | |||
278 | } /* list_for_each_entry */ | ||
279 | |||
280 | return IRQ_HANDLED; | ||
281 | } | ||
282 | |||
283 | |||
284 | /* | ||
285 | * gscps2_write() - send a byte out through the aux interface. | ||
286 | */ | ||
287 | |||
288 | static int gscps2_write(struct serio *port, unsigned char data) | ||
289 | { | ||
290 | struct gscps2port *ps2port = port->port_data; | ||
291 | |||
292 | if (!gscps2_writeb_output(ps2port, data)) { | ||
293 | printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data); | ||
294 | return -1; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * gscps2_open() is called when a port is opened by the higher layer. | ||
301 | * It resets and enables the port. | ||
302 | */ | ||
303 | |||
304 | static int gscps2_open(struct serio *port) | ||
305 | { | ||
306 | struct gscps2port *ps2port = port->port_data; | ||
307 | |||
308 | gscps2_reset(ps2port); | ||
309 | |||
310 | gscps2_interrupt(0, NULL, NULL); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * gscps2_close() disables the port | ||
317 | */ | ||
318 | |||
319 | static void gscps2_close(struct serio *port) | ||
320 | { | ||
321 | struct gscps2port *ps2port = port->port_data; | ||
322 | gscps2_enable(ps2port, DISABLE); | ||
323 | } | ||
324 | |||
325 | /** | ||
326 | * gscps2_probe() - Probes PS2 devices | ||
327 | * @return: success/error report | ||
328 | */ | ||
329 | |||
330 | static int __init gscps2_probe(struct parisc_device *dev) | ||
331 | { | ||
332 | struct gscps2port *ps2port; | ||
333 | struct serio *serio; | ||
334 | unsigned long hpa = dev->hpa; | ||
335 | int ret; | ||
336 | |||
337 | if (!dev->irq) | ||
338 | return -ENODEV; | ||
339 | |||
340 | /* Offset for DINO PS/2. Works with LASI even */ | ||
341 | if (dev->id.sversion == 0x96) | ||
342 | hpa += GSC_DINO_OFFSET; | ||
343 | |||
344 | ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL); | ||
345 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
346 | if (!ps2port || !serio) { | ||
347 | ret = -ENOMEM; | ||
348 | goto fail_nomem; | ||
349 | } | ||
350 | |||
351 | dev_set_drvdata(&dev->dev, ps2port); | ||
352 | |||
353 | memset(ps2port, 0, sizeof(struct gscps2port)); | ||
354 | memset(serio, 0, sizeof(struct serio)); | ||
355 | ps2port->port = serio; | ||
356 | ps2port->padev = dev; | ||
357 | ps2port->addr = ioremap(hpa, GSC_STATUS + 4); | ||
358 | spin_lock_init(&ps2port->lock); | ||
359 | |||
360 | gscps2_reset(ps2port); | ||
361 | ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f; | ||
362 | |||
363 | snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s", | ||
364 | (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse"); | ||
365 | strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); | ||
366 | serio->id.type = SERIO_8042; | ||
367 | serio->write = gscps2_write; | ||
368 | serio->open = gscps2_open; | ||
369 | serio->close = gscps2_close; | ||
370 | serio->port_data = ps2port; | ||
371 | serio->dev.parent = &dev->dev; | ||
372 | |||
373 | list_add_tail(&ps2port->node, &ps2port_list); | ||
374 | |||
375 | ret = -EBUSY; | ||
376 | if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port)) | ||
377 | goto fail_miserably; | ||
378 | |||
379 | if (ps2port->id != GSC_ID_KEYBOARD && ps2port->id != GSC_ID_MOUSE) { | ||
380 | printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n", | ||
381 | hpa, ps2port->id); | ||
382 | ret = -ENODEV; | ||
383 | goto fail; | ||
384 | } | ||
385 | |||
386 | #if 0 | ||
387 | if (!request_mem_region(hpa, GSC_STATUS + 4, ps2port->port.name)) | ||
388 | goto fail; | ||
389 | #endif | ||
390 | |||
391 | printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", | ||
392 | ps2port->port->name, | ||
393 | ps2port->addr, | ||
394 | ps2port->padev->irq, | ||
395 | ps2port->port->phys); | ||
396 | |||
397 | serio_register_port(ps2port->port); | ||
398 | |||
399 | return 0; | ||
400 | |||
401 | fail: | ||
402 | free_irq(dev->irq, ps2port); | ||
403 | |||
404 | fail_miserably: | ||
405 | list_del(&ps2port->node); | ||
406 | iounmap(ps2port->addr); | ||
407 | release_mem_region(dev->hpa, GSC_STATUS + 4); | ||
408 | |||
409 | fail_nomem: | ||
410 | kfree(ps2port); | ||
411 | kfree(serio); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * gscps2_remove() - Removes PS2 devices | ||
417 | * @return: success/error report | ||
418 | */ | ||
419 | |||
420 | static int __devexit gscps2_remove(struct parisc_device *dev) | ||
421 | { | ||
422 | struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); | ||
423 | |||
424 | serio_unregister_port(ps2port->port); | ||
425 | free_irq(dev->irq, ps2port); | ||
426 | gscps2_flush(ps2port); | ||
427 | list_del(&ps2port->node); | ||
428 | iounmap(ps2port->addr); | ||
429 | #if 0 | ||
430 | release_mem_region(dev->hpa, GSC_STATUS + 4); | ||
431 | #endif | ||
432 | dev_set_drvdata(&dev->dev, NULL); | ||
433 | kfree(ps2port); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | |||
438 | static struct parisc_device_id gscps2_device_tbl[] = { | ||
439 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */ | ||
440 | #ifdef DINO_TESTED | ||
441 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */ | ||
442 | #endif | ||
443 | { 0, } /* 0 terminated list */ | ||
444 | }; | ||
445 | |||
446 | static struct parisc_driver parisc_ps2_driver = { | ||
447 | .name = "GSC PS2", | ||
448 | .id_table = gscps2_device_tbl, | ||
449 | .probe = gscps2_probe, | ||
450 | .remove = gscps2_remove, | ||
451 | }; | ||
452 | |||
453 | static int __init gscps2_init(void) | ||
454 | { | ||
455 | register_parisc_driver(&parisc_ps2_driver); | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static void __exit gscps2_exit(void) | ||
460 | { | ||
461 | unregister_parisc_driver(&parisc_ps2_driver); | ||
462 | } | ||
463 | |||
464 | |||
465 | module_init(gscps2_init); | ||
466 | module_exit(gscps2_exit); | ||
467 | |||
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c new file mode 100644 index 000000000000..c243cb6fdfc4 --- /dev/null +++ b/drivers/input/serio/hil_mlc.c | |||
@@ -0,0 +1,949 @@ | |||
1 | /* | ||
2 | * HIL MLC state machine and serio interface driver | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A | ||
31 | * | ||
32 | * | ||
33 | * Driver theory of operation: | ||
34 | * | ||
35 | * Some access methods and an ISR is defined by the sub-driver | ||
36 | * (e.g. hp_sdc_mlc.c). These methods are expected to provide a | ||
37 | * few bits of logic in addition to raw access to the HIL MLC, | ||
38 | * specifically, the ISR, which is entirely registered by the | ||
39 | * sub-driver and invoked directly, must check for record | ||
40 | * termination or packet match, at which point a semaphore must | ||
41 | * be cleared and then the hil_mlcs_tasklet must be scheduled. | ||
42 | * | ||
43 | * The hil_mlcs_tasklet processes the state machine for all MLCs | ||
44 | * each time it runs, checking each MLC's progress at the current | ||
45 | * node in the state machine, and moving the MLC to subsequent nodes | ||
46 | * in the state machine when appropriate. It will reschedule | ||
47 | * itself if output is pending. (This rescheduling should be replaced | ||
48 | * at some point with a sub-driver-specific mechanism.) | ||
49 | * | ||
50 | * A timer task prods the tasklet once per second to prevent | ||
51 | * hangups when attached devices do not return expected data | ||
52 | * and to initiate probes of the loop for new devices. | ||
53 | */ | ||
54 | |||
55 | #include <linux/hil_mlc.h> | ||
56 | #include <linux/errno.h> | ||
57 | #include <linux/kernel.h> | ||
58 | #include <linux/module.h> | ||
59 | #include <linux/init.h> | ||
60 | #include <linux/interrupt.h> | ||
61 | #include <linux/timer.h> | ||
62 | #include <linux/sched.h> | ||
63 | #include <linux/list.h> | ||
64 | |||
65 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
66 | MODULE_DESCRIPTION("HIL MLC serio"); | ||
67 | MODULE_LICENSE("Dual BSD/GPL"); | ||
68 | |||
69 | EXPORT_SYMBOL(hil_mlc_register); | ||
70 | EXPORT_SYMBOL(hil_mlc_unregister); | ||
71 | |||
72 | #define PREFIX "HIL MLC: " | ||
73 | |||
74 | static LIST_HEAD(hil_mlcs); | ||
75 | static DEFINE_RWLOCK(hil_mlcs_lock); | ||
76 | static struct timer_list hil_mlcs_kicker; | ||
77 | static int hil_mlcs_probe; | ||
78 | |||
79 | static void hil_mlcs_process(unsigned long unused); | ||
80 | DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0); | ||
81 | |||
82 | |||
83 | /* #define HIL_MLC_DEBUG */ | ||
84 | |||
85 | /********************** Device info/instance management **********************/ | ||
86 | |||
87 | static void hil_mlc_clear_di_map (hil_mlc *mlc, int val) { | ||
88 | int j; | ||
89 | for (j = val; j < 7 ; j++) { | ||
90 | mlc->di_map[j] = -1; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | static void hil_mlc_clear_di_scratch (hil_mlc *mlc) { | ||
95 | memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch)); | ||
96 | } | ||
97 | |||
98 | static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) { | ||
99 | memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch)); | ||
100 | } | ||
101 | |||
102 | static int hil_mlc_match_di_scratch (hil_mlc *mlc) { | ||
103 | int idx; | ||
104 | |||
105 | for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { | ||
106 | int j, found; | ||
107 | |||
108 | /* In-use slots are not eligible. */ | ||
109 | found = 0; | ||
110 | for (j = 0; j < 7 ; j++) { | ||
111 | if (mlc->di_map[j] == idx) found++; | ||
112 | } | ||
113 | if (found) continue; | ||
114 | if (!memcmp(mlc->di + idx, | ||
115 | &(mlc->di_scratch), | ||
116 | sizeof(mlc->di_scratch))) break; | ||
117 | } | ||
118 | return((idx >= HIL_MLC_DEVMEM) ? -1 : idx); | ||
119 | } | ||
120 | |||
121 | static int hil_mlc_find_free_di(hil_mlc *mlc) { | ||
122 | int idx; | ||
123 | /* TODO: Pick all-zero slots first, failing that, | ||
124 | * randomize the slot picked among those eligible. | ||
125 | */ | ||
126 | for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { | ||
127 | int j, found; | ||
128 | found = 0; | ||
129 | for (j = 0; j < 7 ; j++) { | ||
130 | if (mlc->di_map[j] == idx) found++; | ||
131 | } | ||
132 | if (!found) break; | ||
133 | } | ||
134 | return(idx); /* Note: It is guaranteed at least one above will match */ | ||
135 | } | ||
136 | |||
137 | static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) { | ||
138 | int idx; | ||
139 | for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { | ||
140 | int j, found; | ||
141 | found = 0; | ||
142 | for (j = 0; j < 7 ; j++) { | ||
143 | if (mlc->di_map[j] == idx) found++; | ||
144 | } | ||
145 | if (!found) mlc->serio_map[idx].di_revmap = -1; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void hil_mlc_send_polls(hil_mlc *mlc) { | ||
150 | int did, i, cnt; | ||
151 | struct serio *serio; | ||
152 | struct serio_driver *drv; | ||
153 | |||
154 | i = cnt = 0; | ||
155 | did = (mlc->ipacket[0] & HIL_PKT_ADDR_MASK) >> 8; | ||
156 | serio = did ? mlc->serio[mlc->di_map[did - 1]] : NULL; | ||
157 | drv = (serio != NULL) ? serio->drv : NULL; | ||
158 | |||
159 | while (mlc->icount < 15 - i) { | ||
160 | hil_packet p; | ||
161 | p = mlc->ipacket[i]; | ||
162 | if (did != (p & HIL_PKT_ADDR_MASK) >> 8) { | ||
163 | if (drv == NULL || drv->interrupt == NULL) goto skip; | ||
164 | |||
165 | drv->interrupt(serio, 0, 0, NULL); | ||
166 | drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); | ||
167 | drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL); | ||
168 | drv->interrupt(serio, HIL_CMD_POL + cnt, 0, NULL); | ||
169 | skip: | ||
170 | did = (p & HIL_PKT_ADDR_MASK) >> 8; | ||
171 | serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL; | ||
172 | drv = (serio != NULL) ? serio->drv : NULL; | ||
173 | cnt = 0; | ||
174 | } | ||
175 | cnt++; i++; | ||
176 | if (drv == NULL || drv->interrupt == NULL) continue; | ||
177 | drv->interrupt(serio, (p >> 24), 0, NULL); | ||
178 | drv->interrupt(serio, (p >> 16) & 0xff, 0, NULL); | ||
179 | drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0, NULL); | ||
180 | drv->interrupt(serio, p & 0xff, 0, NULL); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /*************************** State engine *********************************/ | ||
185 | |||
186 | #define HILSEN_SCHED 0x000100 /* Schedule the tasklet */ | ||
187 | #define HILSEN_BREAK 0x000200 /* Wait until next pass */ | ||
188 | #define HILSEN_UP 0x000400 /* relative node#, decrement */ | ||
189 | #define HILSEN_DOWN 0x000800 /* relative node#, increment */ | ||
190 | #define HILSEN_FOLLOW 0x001000 /* use retval as next node# */ | ||
191 | |||
192 | #define HILSEN_MASK 0x0000ff | ||
193 | #define HILSEN_START 0 | ||
194 | #define HILSEN_RESTART 1 | ||
195 | #define HILSEN_DHR 9 | ||
196 | #define HILSEN_DHR2 10 | ||
197 | #define HILSEN_IFC 14 | ||
198 | #define HILSEN_HEAL0 16 | ||
199 | #define HILSEN_HEAL 18 | ||
200 | #define HILSEN_ACF 21 | ||
201 | #define HILSEN_ACF2 22 | ||
202 | #define HILSEN_DISC0 25 | ||
203 | #define HILSEN_DISC 27 | ||
204 | #define HILSEN_MATCH 40 | ||
205 | #define HILSEN_OPERATE 41 | ||
206 | #define HILSEN_PROBE 44 | ||
207 | #define HILSEN_DSR 52 | ||
208 | #define HILSEN_REPOLL 55 | ||
209 | #define HILSEN_IFCACF 58 | ||
210 | #define HILSEN_END 60 | ||
211 | |||
212 | #define HILSEN_NEXT (HILSEN_DOWN | 1) | ||
213 | #define HILSEN_SAME (HILSEN_DOWN | 0) | ||
214 | #define HILSEN_LAST (HILSEN_UP | 1) | ||
215 | |||
216 | #define HILSEN_DOZE (HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK) | ||
217 | #define HILSEN_SLEEP (HILSEN_SAME | HILSEN_BREAK) | ||
218 | |||
219 | static int hilse_match(hil_mlc *mlc, int unused) { | ||
220 | int rc; | ||
221 | rc = hil_mlc_match_di_scratch(mlc); | ||
222 | if (rc == -1) { | ||
223 | rc = hil_mlc_find_free_di(mlc); | ||
224 | if (rc == -1) goto err; | ||
225 | #ifdef HIL_MLC_DEBUG | ||
226 | printk(KERN_DEBUG PREFIX "new in slot %i\n", rc); | ||
227 | #endif | ||
228 | hil_mlc_copy_di_scratch(mlc, rc); | ||
229 | mlc->di_map[mlc->ddi] = rc; | ||
230 | mlc->serio_map[rc].di_revmap = mlc->ddi; | ||
231 | hil_mlc_clean_serio_map(mlc); | ||
232 | serio_rescan(mlc->serio[rc]); | ||
233 | return -1; | ||
234 | } | ||
235 | mlc->di_map[mlc->ddi] = rc; | ||
236 | #ifdef HIL_MLC_DEBUG | ||
237 | printk(KERN_DEBUG PREFIX "same in slot %i\n", rc); | ||
238 | #endif | ||
239 | mlc->serio_map[rc].di_revmap = mlc->ddi; | ||
240 | hil_mlc_clean_serio_map(mlc); | ||
241 | return 0; | ||
242 | err: | ||
243 | printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n"); | ||
244 | return 1; | ||
245 | } | ||
246 | |||
247 | /* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */ | ||
248 | static int hilse_init_lcv(hil_mlc *mlc, int unused) { | ||
249 | struct timeval tv; | ||
250 | |||
251 | do_gettimeofday(&tv); | ||
252 | |||
253 | if(mlc->lcv == 0) goto restart; /* First init, no need to dally */ | ||
254 | if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1; | ||
255 | restart: | ||
256 | mlc->lcv_tv = tv; | ||
257 | mlc->lcv = 0; | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int hilse_inc_lcv(hil_mlc *mlc, int lim) { | ||
262 | if (mlc->lcv++ >= lim) return -1; | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | #if 0 | ||
267 | static int hilse_set_lcv(hil_mlc *mlc, int val) { | ||
268 | mlc->lcv = val; | ||
269 | return 0; | ||
270 | } | ||
271 | #endif | ||
272 | |||
273 | /* Management of the discovered device index (zero based, -1 means no devs) */ | ||
274 | static int hilse_set_ddi(hil_mlc *mlc, int val) { | ||
275 | mlc->ddi = val; | ||
276 | hil_mlc_clear_di_map(mlc, val + 1); | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int hilse_dec_ddi(hil_mlc *mlc, int unused) { | ||
281 | mlc->ddi--; | ||
282 | if (mlc->ddi <= -1) { | ||
283 | mlc->ddi = -1; | ||
284 | hil_mlc_clear_di_map(mlc, 0); | ||
285 | return -1; | ||
286 | } | ||
287 | hil_mlc_clear_di_map(mlc, mlc->ddi + 1); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int hilse_inc_ddi(hil_mlc *mlc, int unused) { | ||
292 | if (mlc->ddi >= 6) { | ||
293 | BUG(); | ||
294 | return -1; | ||
295 | } | ||
296 | mlc->ddi++; | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int hilse_take_idd(hil_mlc *mlc, int unused) { | ||
301 | int i; | ||
302 | |||
303 | /* Help the state engine: | ||
304 | * Is this a real IDD response or just an echo? | ||
305 | * | ||
306 | * Real IDD response does not start with a command. | ||
307 | */ | ||
308 | if (mlc->ipacket[0] & HIL_PKT_CMD) goto bail; | ||
309 | /* Should have the command echoed further down. */ | ||
310 | for (i = 1; i < 16; i++) { | ||
311 | if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) == | ||
312 | (mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) && | ||
313 | (mlc->ipacket[i] & HIL_PKT_CMD) && | ||
314 | ((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD)) | ||
315 | break; | ||
316 | } | ||
317 | if (i > 15) goto bail; | ||
318 | /* And the rest of the packets should still be clear. */ | ||
319 | while (++i < 16) { | ||
320 | if (mlc->ipacket[i]) break; | ||
321 | } | ||
322 | if (i < 16) goto bail; | ||
323 | for (i = 0; i < 16; i++) { | ||
324 | mlc->di_scratch.idd[i] = | ||
325 | mlc->ipacket[i] & HIL_PKT_DATA_MASK; | ||
326 | } | ||
327 | /* Next step is to see if RSC supported */ | ||
328 | if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC) | ||
329 | return HILSEN_NEXT; | ||
330 | if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) | ||
331 | return HILSEN_DOWN | 4; | ||
332 | return 0; | ||
333 | bail: | ||
334 | mlc->ddi--; | ||
335 | return -1; /* This should send us off to ACF */ | ||
336 | } | ||
337 | |||
338 | static int hilse_take_rsc(hil_mlc *mlc, int unused) { | ||
339 | int i; | ||
340 | |||
341 | for (i = 0; i < 16; i++) { | ||
342 | mlc->di_scratch.rsc[i] = | ||
343 | mlc->ipacket[i] & HIL_PKT_DATA_MASK; | ||
344 | } | ||
345 | /* Next step is to see if EXD supported (IDD has already been read) */ | ||
346 | if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) | ||
347 | return HILSEN_NEXT; | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int hilse_take_exd(hil_mlc *mlc, int unused) { | ||
352 | int i; | ||
353 | |||
354 | for (i = 0; i < 16; i++) { | ||
355 | mlc->di_scratch.exd[i] = | ||
356 | mlc->ipacket[i] & HIL_PKT_DATA_MASK; | ||
357 | } | ||
358 | /* Next step is to see if RNM supported. */ | ||
359 | if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM) | ||
360 | return HILSEN_NEXT; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int hilse_take_rnm(hil_mlc *mlc, int unused) { | ||
365 | int i; | ||
366 | |||
367 | for (i = 0; i < 16; i++) { | ||
368 | mlc->di_scratch.rnm[i] = | ||
369 | mlc->ipacket[i] & HIL_PKT_DATA_MASK; | ||
370 | } | ||
371 | do { | ||
372 | char nam[17]; | ||
373 | snprintf(nam, 16, "%s", mlc->di_scratch.rnm); | ||
374 | nam[16] = '\0'; | ||
375 | printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam); | ||
376 | } while (0); | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int hilse_operate(hil_mlc *mlc, int repoll) { | ||
381 | |||
382 | if (mlc->opercnt == 0) hil_mlcs_probe = 0; | ||
383 | mlc->opercnt = 1; | ||
384 | |||
385 | hil_mlc_send_polls(mlc); | ||
386 | |||
387 | if (!hil_mlcs_probe) return 0; | ||
388 | hil_mlcs_probe = 0; | ||
389 | mlc->opercnt = 0; | ||
390 | return 1; | ||
391 | } | ||
392 | |||
393 | #define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \ | ||
394 | { HILSE_FUNC, { func: &funct }, funct_arg, zero_rc, neg_rc, pos_rc }, | ||
395 | #define OUT(pack) \ | ||
396 | { HILSE_OUT, { packet: pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 }, | ||
397 | #define CTS \ | ||
398 | { HILSE_CTS, { packet: 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 }, | ||
399 | #define EXPECT(comp, to, got, got_wrong, timed_out) \ | ||
400 | { HILSE_EXPECT, { packet: comp }, to, got, got_wrong, timed_out }, | ||
401 | #define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \ | ||
402 | { HILSE_EXPECT_LAST, { packet: comp }, to, got, got_wrong, timed_out }, | ||
403 | #define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \ | ||
404 | { HILSE_EXPECT_DISC, { packet: comp }, to, got, got_wrong, timed_out }, | ||
405 | #define IN(to, got, got_error, timed_out) \ | ||
406 | { HILSE_IN, { packet: 0 }, to, got, got_error, timed_out }, | ||
407 | #define OUT_DISC(pack) \ | ||
408 | { HILSE_OUT_DISC, { packet: pack }, 0, 0, 0, 0 }, | ||
409 | #define OUT_LAST(pack) \ | ||
410 | { HILSE_OUT_LAST, { packet: pack }, 0, 0, 0, 0 }, | ||
411 | |||
412 | struct hilse_node hil_mlc_se[HILSEN_END] = { | ||
413 | |||
414 | /* 0 HILSEN_START */ | ||
415 | FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0) | ||
416 | |||
417 | /* 1 HILSEN_RESTART */ | ||
418 | FUNC(hilse_inc_lcv, 10, HILSEN_NEXT, HILSEN_START, 0) | ||
419 | OUT(HIL_CTRL_ONLY) /* Disable APE */ | ||
420 | CTS | ||
421 | |||
422 | #define TEST_PACKET(x) \ | ||
423 | (HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT) | x << 4 | x) | ||
424 | |||
425 | OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0x5)) | ||
426 | EXPECT(HIL_ERR_INT | TEST_PACKET(0x5), | ||
427 | 2000, HILSEN_NEXT, HILSEN_RESTART, HILSEN_RESTART) | ||
428 | OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0xa)) | ||
429 | EXPECT(HIL_ERR_INT | TEST_PACKET(0xa), | ||
430 | 2000, HILSEN_NEXT, HILSEN_RESTART, HILSEN_RESTART) | ||
431 | OUT(HIL_CTRL_ONLY | 0) /* Disable test mode */ | ||
432 | |||
433 | /* 9 HILSEN_DHR */ | ||
434 | FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0) | ||
435 | |||
436 | /* 10 HILSEN_DHR2 */ | ||
437 | FUNC(hilse_inc_lcv, 10, HILSEN_NEXT, HILSEN_START, 0) | ||
438 | FUNC(hilse_set_ddi, -1, HILSEN_NEXT, 0, 0) | ||
439 | OUT(HIL_PKT_CMD | HIL_CMD_DHR) | ||
440 | IN(300000, HILSEN_DHR2, HILSEN_DHR2, HILSEN_NEXT) | ||
441 | |||
442 | /* 14 HILSEN_IFC */ | ||
443 | OUT(HIL_PKT_CMD | HIL_CMD_IFC) | ||
444 | EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT, | ||
445 | 20000, HILSEN_DISC, HILSEN_DHR2, HILSEN_NEXT ) | ||
446 | |||
447 | /* If devices are there, they weren't in PUP or other loopback mode. | ||
448 | * We're more concerned at this point with restoring operation | ||
449 | * to devices than discovering new ones, so we try to salvage | ||
450 | * the loop configuration by closing off the loop. | ||
451 | */ | ||
452 | |||
453 | /* 16 HILSEN_HEAL0 */ | ||
454 | FUNC(hilse_dec_ddi, 0, HILSEN_NEXT, HILSEN_ACF, 0) | ||
455 | FUNC(hilse_inc_ddi, 0, HILSEN_NEXT, 0, 0) | ||
456 | |||
457 | /* 18 HILSEN_HEAL */ | ||
458 | OUT_LAST(HIL_CMD_ELB) | ||
459 | EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT, | ||
460 | 20000, HILSEN_REPOLL, HILSEN_DSR, HILSEN_NEXT) | ||
461 | FUNC(hilse_dec_ddi, 0, HILSEN_HEAL, HILSEN_NEXT, 0) | ||
462 | |||
463 | /* 21 HILSEN_ACF */ | ||
464 | FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_DOZE, 0) | ||
465 | |||
466 | /* 22 HILSEN_ACF2 */ | ||
467 | FUNC(hilse_inc_lcv, 10, HILSEN_NEXT, HILSEN_START, 0) | ||
468 | OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1) | ||
469 | IN(20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_NEXT) | ||
470 | |||
471 | /* 25 HILSEN_DISC0 */ | ||
472 | OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB) | ||
473 | EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_ELB | HIL_ERR_INT, | ||
474 | 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) | ||
475 | |||
476 | /* Only enter here if response just received */ | ||
477 | /* 27 HILSEN_DISC */ | ||
478 | OUT_DISC(HIL_PKT_CMD | HIL_CMD_IDD) | ||
479 | EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_IDD | HIL_ERR_INT, | ||
480 | 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_START) | ||
481 | FUNC(hilse_inc_ddi, 0, HILSEN_NEXT, HILSEN_START, 0) | ||
482 | FUNC(hilse_take_idd, 0, HILSEN_MATCH, HILSEN_IFCACF, HILSEN_FOLLOW) | ||
483 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_RSC) | ||
484 | EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RSC | HIL_ERR_INT, | ||
485 | 30000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) | ||
486 | FUNC(hilse_take_rsc, 0, HILSEN_MATCH, 0, HILSEN_FOLLOW) | ||
487 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_EXD) | ||
488 | EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_EXD | HIL_ERR_INT, | ||
489 | 30000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) | ||
490 | FUNC(hilse_take_exd, 0, HILSEN_MATCH, 0, HILSEN_FOLLOW) | ||
491 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_RNM) | ||
492 | EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RNM | HIL_ERR_INT, | ||
493 | 30000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) | ||
494 | FUNC(hilse_take_rnm, 0, HILSEN_MATCH, 0, 0) | ||
495 | |||
496 | /* 40 HILSEN_MATCH */ | ||
497 | FUNC(hilse_match, 0, HILSEN_NEXT, HILSEN_NEXT, /* TODO */ 0) | ||
498 | |||
499 | /* 41 HILSEN_OPERATE */ | ||
500 | OUT(HIL_PKT_CMD | HIL_CMD_POL) | ||
501 | EXPECT(HIL_PKT_CMD | HIL_CMD_POL | HIL_ERR_INT, | ||
502 | 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_NEXT) | ||
503 | FUNC(hilse_operate, 0, HILSEN_OPERATE, HILSEN_IFC, HILSEN_NEXT) | ||
504 | |||
505 | /* 44 HILSEN_PROBE */ | ||
506 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT) | ||
507 | IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT) | ||
508 | OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB) | ||
509 | IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT) | ||
510 | OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1) | ||
511 | IN(10000, HILSEN_DISC0, HILSEN_DSR, HILSEN_NEXT) | ||
512 | OUT_LAST(HIL_PKT_CMD | HIL_CMD_ELB) | ||
513 | IN(10000, HILSEN_OPERATE, HILSEN_DSR, HILSEN_DSR) | ||
514 | |||
515 | /* 52 HILSEN_DSR */ | ||
516 | FUNC(hilse_set_ddi, -1, HILSEN_NEXT, 0, 0) | ||
517 | OUT(HIL_PKT_CMD | HIL_CMD_DSR) | ||
518 | IN(20000, HILSEN_DHR, HILSEN_DHR, HILSEN_IFC) | ||
519 | |||
520 | /* 55 HILSEN_REPOLL */ | ||
521 | OUT(HIL_PKT_CMD | HIL_CMD_RPL) | ||
522 | EXPECT(HIL_PKT_CMD | HIL_CMD_RPL | HIL_ERR_INT, | ||
523 | 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_NEXT) | ||
524 | FUNC(hilse_operate, 1, HILSEN_OPERATE, HILSEN_IFC, HILSEN_PROBE) | ||
525 | |||
526 | /* 58 HILSEN_IFCACF */ | ||
527 | OUT(HIL_PKT_CMD | HIL_CMD_IFC) | ||
528 | EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT, | ||
529 | 20000, HILSEN_ACF2, HILSEN_DHR2, HILSEN_HEAL) | ||
530 | |||
531 | /* 60 HILSEN_END */ | ||
532 | }; | ||
533 | |||
534 | static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) { | ||
535 | |||
536 | switch (node->act) { | ||
537 | case HILSE_EXPECT_DISC: | ||
538 | mlc->imatch = node->object.packet; | ||
539 | mlc->imatch |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT); | ||
540 | break; | ||
541 | case HILSE_EXPECT_LAST: | ||
542 | mlc->imatch = node->object.packet; | ||
543 | mlc->imatch |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT); | ||
544 | break; | ||
545 | case HILSE_EXPECT: | ||
546 | mlc->imatch = node->object.packet; | ||
547 | break; | ||
548 | case HILSE_IN: | ||
549 | mlc->imatch = 0; | ||
550 | break; | ||
551 | default: | ||
552 | BUG(); | ||
553 | } | ||
554 | mlc->istarted = 1; | ||
555 | mlc->intimeout = node->arg; | ||
556 | do_gettimeofday(&(mlc->instart)); | ||
557 | mlc->icount = 15; | ||
558 | memset(mlc->ipacket, 0, 16 * sizeof(hil_packet)); | ||
559 | if (down_trylock(&(mlc->isem))) BUG(); | ||
560 | |||
561 | return; | ||
562 | } | ||
563 | |||
564 | #ifdef HIL_MLC_DEBUG | ||
565 | static int doze = 0; | ||
566 | static int seidx; /* For debug */ | ||
567 | static int kick = 1; | ||
568 | #endif | ||
569 | |||
570 | static int hilse_donode (hil_mlc *mlc) { | ||
571 | struct hilse_node *node; | ||
572 | int nextidx = 0; | ||
573 | int sched_long = 0; | ||
574 | unsigned long flags; | ||
575 | |||
576 | #ifdef HIL_MLC_DEBUG | ||
577 | if (mlc->seidx && (mlc->seidx != seidx) && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) { | ||
578 | printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx); | ||
579 | doze = 0; | ||
580 | } | ||
581 | kick = 0; | ||
582 | |||
583 | seidx = mlc->seidx; | ||
584 | #endif | ||
585 | node = hil_mlc_se + mlc->seidx; | ||
586 | |||
587 | switch (node->act) { | ||
588 | int rc; | ||
589 | hil_packet pack; | ||
590 | |||
591 | case HILSE_FUNC: | ||
592 | if (node->object.func == NULL) break; | ||
593 | rc = node->object.func(mlc, node->arg); | ||
594 | nextidx = (rc > 0) ? node->ugly : | ||
595 | ((rc < 0) ? node->bad : node->good); | ||
596 | if (nextidx == HILSEN_FOLLOW) nextidx = rc; | ||
597 | break; | ||
598 | case HILSE_EXPECT_LAST: | ||
599 | case HILSE_EXPECT_DISC: | ||
600 | case HILSE_EXPECT: | ||
601 | case HILSE_IN: | ||
602 | /* Already set up from previous HILSE_OUT_* */ | ||
603 | write_lock_irqsave(&(mlc->lock), flags); | ||
604 | rc = mlc->in(mlc, node->arg); | ||
605 | if (rc == 2) { | ||
606 | nextidx = HILSEN_DOZE; | ||
607 | sched_long = 1; | ||
608 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
609 | break; | ||
610 | } | ||
611 | if (rc == 1) nextidx = node->ugly; | ||
612 | else if (rc == 0) nextidx = node->good; | ||
613 | else nextidx = node->bad; | ||
614 | mlc->istarted = 0; | ||
615 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
616 | break; | ||
617 | case HILSE_OUT_LAST: | ||
618 | write_lock_irqsave(&(mlc->lock), flags); | ||
619 | pack = node->object.packet; | ||
620 | pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT); | ||
621 | goto out; | ||
622 | case HILSE_OUT_DISC: | ||
623 | write_lock_irqsave(&(mlc->lock), flags); | ||
624 | pack = node->object.packet; | ||
625 | pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT); | ||
626 | goto out; | ||
627 | case HILSE_OUT: | ||
628 | write_lock_irqsave(&(mlc->lock), flags); | ||
629 | pack = node->object.packet; | ||
630 | out: | ||
631 | if (mlc->istarted) goto out2; | ||
632 | /* Prepare to receive input */ | ||
633 | if ((node + 1)->act & HILSE_IN) | ||
634 | hilse_setup_input(mlc, node + 1); | ||
635 | |||
636 | out2: | ||
637 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
638 | |||
639 | if (down_trylock(&mlc->osem)) { | ||
640 | nextidx = HILSEN_DOZE; | ||
641 | break; | ||
642 | } | ||
643 | up(&mlc->osem); | ||
644 | |||
645 | write_lock_irqsave(&(mlc->lock), flags); | ||
646 | if (!(mlc->ostarted)) { | ||
647 | mlc->ostarted = 1; | ||
648 | mlc->opacket = pack; | ||
649 | mlc->out(mlc); | ||
650 | nextidx = HILSEN_DOZE; | ||
651 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
652 | break; | ||
653 | } | ||
654 | mlc->ostarted = 0; | ||
655 | do_gettimeofday(&(mlc->instart)); | ||
656 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
657 | nextidx = HILSEN_NEXT; | ||
658 | break; | ||
659 | case HILSE_CTS: | ||
660 | nextidx = mlc->cts(mlc) ? node->bad : node->good; | ||
661 | break; | ||
662 | default: | ||
663 | BUG(); | ||
664 | nextidx = 0; | ||
665 | break; | ||
666 | } | ||
667 | |||
668 | #ifdef HIL_MLC_DEBUG | ||
669 | if (nextidx == HILSEN_DOZE) doze++; | ||
670 | #endif | ||
671 | |||
672 | while (nextidx & HILSEN_SCHED) { | ||
673 | struct timeval tv; | ||
674 | |||
675 | if (!sched_long) goto sched; | ||
676 | |||
677 | do_gettimeofday(&tv); | ||
678 | tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec); | ||
679 | tv.tv_usec -= mlc->instart.tv_usec; | ||
680 | if (tv.tv_usec >= mlc->intimeout) goto sched; | ||
681 | tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / 1000000; | ||
682 | if (!tv.tv_usec) goto sched; | ||
683 | mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec); | ||
684 | break; | ||
685 | sched: | ||
686 | tasklet_schedule(&hil_mlcs_tasklet); | ||
687 | break; | ||
688 | } | ||
689 | if (nextidx & HILSEN_DOWN) mlc->seidx += nextidx & HILSEN_MASK; | ||
690 | else if (nextidx & HILSEN_UP) mlc->seidx -= nextidx & HILSEN_MASK; | ||
691 | else mlc->seidx = nextidx & HILSEN_MASK; | ||
692 | |||
693 | if (nextidx & HILSEN_BREAK) return 1; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /******************** tasklet context functions **************************/ | ||
698 | static void hil_mlcs_process(unsigned long unused) { | ||
699 | struct list_head *tmp; | ||
700 | |||
701 | read_lock(&hil_mlcs_lock); | ||
702 | list_for_each(tmp, &hil_mlcs) { | ||
703 | struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list); | ||
704 | while (hilse_donode(mlc) == 0) { | ||
705 | #ifdef HIL_MLC_DEBUG | ||
706 | if (mlc->seidx != 41 && | ||
707 | mlc->seidx != 42 && | ||
708 | mlc->seidx != 43) | ||
709 | printk(KERN_DEBUG PREFIX " + "); | ||
710 | #endif | ||
711 | }; | ||
712 | } | ||
713 | read_unlock(&hil_mlcs_lock); | ||
714 | } | ||
715 | |||
716 | /************************* Keepalive timer task *********************/ | ||
717 | |||
718 | void hil_mlcs_timer (unsigned long data) { | ||
719 | hil_mlcs_probe = 1; | ||
720 | tasklet_schedule(&hil_mlcs_tasklet); | ||
721 | /* Re-insert the periodic task. */ | ||
722 | if (!timer_pending(&hil_mlcs_kicker)) | ||
723 | mod_timer(&hil_mlcs_kicker, jiffies + HZ); | ||
724 | } | ||
725 | |||
726 | /******************** user/kernel context functions **********************/ | ||
727 | |||
728 | static int hil_mlc_serio_write(struct serio *serio, unsigned char c) { | ||
729 | struct hil_mlc_serio_map *map; | ||
730 | struct hil_mlc *mlc; | ||
731 | struct serio_driver *drv; | ||
732 | uint8_t *idx, *last; | ||
733 | |||
734 | map = serio->port_data; | ||
735 | if (map == NULL) { | ||
736 | BUG(); | ||
737 | return -EIO; | ||
738 | } | ||
739 | mlc = map->mlc; | ||
740 | if (mlc == NULL) { | ||
741 | BUG(); | ||
742 | return -EIO; | ||
743 | } | ||
744 | mlc->serio_opacket[map->didx] |= | ||
745 | ((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx])); | ||
746 | |||
747 | if (mlc->serio_oidx[map->didx] >= 3) { | ||
748 | /* for now only commands */ | ||
749 | if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD)) | ||
750 | return -EIO; | ||
751 | switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) { | ||
752 | case HIL_CMD_IDD: | ||
753 | idx = mlc->di[map->didx].idd; | ||
754 | goto emu; | ||
755 | case HIL_CMD_RSC: | ||
756 | idx = mlc->di[map->didx].rsc; | ||
757 | goto emu; | ||
758 | case HIL_CMD_EXD: | ||
759 | idx = mlc->di[map->didx].exd; | ||
760 | goto emu; | ||
761 | case HIL_CMD_RNM: | ||
762 | idx = mlc->di[map->didx].rnm; | ||
763 | goto emu; | ||
764 | default: | ||
765 | break; | ||
766 | } | ||
767 | mlc->serio_oidx[map->didx] = 0; | ||
768 | mlc->serio_opacket[map->didx] = 0; | ||
769 | } | ||
770 | |||
771 | mlc->serio_oidx[map->didx]++; | ||
772 | return -EIO; | ||
773 | emu: | ||
774 | drv = serio->drv; | ||
775 | if (drv == NULL) { | ||
776 | BUG(); | ||
777 | return -EIO; | ||
778 | } | ||
779 | last = idx + 15; | ||
780 | while ((last != idx) && (*last == 0)) last--; | ||
781 | |||
782 | while (idx != last) { | ||
783 | drv->interrupt(serio, 0, 0, NULL); | ||
784 | drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); | ||
785 | drv->interrupt(serio, 0, 0, NULL); | ||
786 | drv->interrupt(serio, *idx, 0, NULL); | ||
787 | idx++; | ||
788 | } | ||
789 | drv->interrupt(serio, 0, 0, NULL); | ||
790 | drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); | ||
791 | drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL); | ||
792 | drv->interrupt(serio, *idx, 0, NULL); | ||
793 | |||
794 | mlc->serio_oidx[map->didx] = 0; | ||
795 | mlc->serio_opacket[map->didx] = 0; | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static int hil_mlc_serio_open(struct serio *serio) { | ||
801 | struct hil_mlc_serio_map *map; | ||
802 | struct hil_mlc *mlc; | ||
803 | |||
804 | if (serio->private != NULL) return -EBUSY; | ||
805 | |||
806 | map = serio->port_data; | ||
807 | if (map == NULL) { | ||
808 | BUG(); | ||
809 | return -ENODEV; | ||
810 | } | ||
811 | mlc = map->mlc; | ||
812 | if (mlc == NULL) { | ||
813 | BUG(); | ||
814 | return -ENODEV; | ||
815 | } | ||
816 | |||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static void hil_mlc_serio_close(struct serio *serio) { | ||
821 | struct hil_mlc_serio_map *map; | ||
822 | struct hil_mlc *mlc; | ||
823 | |||
824 | map = serio->port_data; | ||
825 | if (map == NULL) { | ||
826 | BUG(); | ||
827 | return; | ||
828 | } | ||
829 | mlc = map->mlc; | ||
830 | if (mlc == NULL) { | ||
831 | BUG(); | ||
832 | return; | ||
833 | } | ||
834 | |||
835 | serio->private = NULL; | ||
836 | serio->drv = NULL; | ||
837 | /* TODO wake up interruptable */ | ||
838 | } | ||
839 | |||
840 | int hil_mlc_register(hil_mlc *mlc) { | ||
841 | int i; | ||
842 | unsigned long flags; | ||
843 | |||
844 | if (mlc == NULL) { | ||
845 | return -EINVAL; | ||
846 | } | ||
847 | |||
848 | mlc->istarted = 0; | ||
849 | mlc->ostarted = 0; | ||
850 | |||
851 | rwlock_init(&mlc->lock); | ||
852 | init_MUTEX(&(mlc->osem)); | ||
853 | |||
854 | init_MUTEX(&(mlc->isem)); | ||
855 | mlc->icount = -1; | ||
856 | mlc->imatch = 0; | ||
857 | |||
858 | mlc->opercnt = 0; | ||
859 | |||
860 | init_MUTEX_LOCKED(&(mlc->csem)); | ||
861 | |||
862 | hil_mlc_clear_di_scratch(mlc); | ||
863 | hil_mlc_clear_di_map(mlc, 0); | ||
864 | for (i = 0; i < HIL_MLC_DEVMEM; i++) { | ||
865 | struct serio *mlc_serio; | ||
866 | hil_mlc_copy_di_scratch(mlc, i); | ||
867 | mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL); | ||
868 | mlc->serio[i] = mlc_serio; | ||
869 | memset(mlc_serio, 0, sizeof(*mlc_serio)); | ||
870 | mlc_serio->type = SERIO_HIL | SERIO_HIL_MLC; | ||
871 | mlc_serio->write = hil_mlc_serio_write; | ||
872 | mlc_serio->open = hil_mlc_serio_open; | ||
873 | mlc_serio->close = hil_mlc_serio_close; | ||
874 | mlc_serio->port_data = &(mlc->serio_map[i]); | ||
875 | mlc->serio_map[i].mlc = mlc; | ||
876 | mlc->serio_map[i].didx = i; | ||
877 | mlc->serio_map[i].di_revmap = -1; | ||
878 | mlc->serio_opacket[i] = 0; | ||
879 | mlc->serio_oidx[i] = 0; | ||
880 | serio_register_port(mlc_serio); | ||
881 | } | ||
882 | |||
883 | mlc->tasklet = &hil_mlcs_tasklet; | ||
884 | |||
885 | write_lock_irqsave(&hil_mlcs_lock, flags); | ||
886 | list_add_tail(&mlc->list, &hil_mlcs); | ||
887 | mlc->seidx = HILSEN_START; | ||
888 | write_unlock_irqrestore(&hil_mlcs_lock, flags); | ||
889 | |||
890 | tasklet_schedule(&hil_mlcs_tasklet); | ||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | int hil_mlc_unregister(hil_mlc *mlc) { | ||
895 | struct list_head *tmp; | ||
896 | unsigned long flags; | ||
897 | int i; | ||
898 | |||
899 | if (mlc == NULL) | ||
900 | return -EINVAL; | ||
901 | |||
902 | write_lock_irqsave(&hil_mlcs_lock, flags); | ||
903 | list_for_each(tmp, &hil_mlcs) { | ||
904 | if (list_entry(tmp, hil_mlc, list) == mlc) | ||
905 | goto found; | ||
906 | } | ||
907 | |||
908 | /* not found in list */ | ||
909 | write_unlock_irqrestore(&hil_mlcs_lock, flags); | ||
910 | tasklet_schedule(&hil_mlcs_tasklet); | ||
911 | return -ENODEV; | ||
912 | |||
913 | found: | ||
914 | list_del(tmp); | ||
915 | write_unlock_irqrestore(&hil_mlcs_lock, flags); | ||
916 | |||
917 | for (i = 0; i < HIL_MLC_DEVMEM; i++) { | ||
918 | serio_unregister_port(mlc->serio[i]); | ||
919 | mlc->serio[i] = NULL; | ||
920 | } | ||
921 | |||
922 | tasklet_schedule(&hil_mlcs_tasklet); | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | /**************************** Module interface *************************/ | ||
927 | |||
928 | static int __init hil_mlc_init(void) | ||
929 | { | ||
930 | init_timer(&hil_mlcs_kicker); | ||
931 | hil_mlcs_kicker.expires = jiffies + HZ; | ||
932 | hil_mlcs_kicker.function = &hil_mlcs_timer; | ||
933 | add_timer(&hil_mlcs_kicker); | ||
934 | |||
935 | tasklet_enable(&hil_mlcs_tasklet); | ||
936 | |||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | static void __exit hil_mlc_exit(void) | ||
941 | { | ||
942 | del_timer(&hil_mlcs_kicker); | ||
943 | |||
944 | tasklet_disable(&hil_mlcs_tasklet); | ||
945 | tasklet_kill(&hil_mlcs_tasklet); | ||
946 | } | ||
947 | |||
948 | module_init(hil_mlc_init); | ||
949 | module_exit(hil_mlc_exit); | ||
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c new file mode 100644 index 000000000000..7629452dd64b --- /dev/null +++ b/drivers/input/serio/hp_sdc.c | |||
@@ -0,0 +1,1054 @@ | |||
1 | /* | ||
2 | * HP i8042-based System Device Controller driver. | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * System Device Controller Microprocessor Firmware Theory of Operation | ||
31 | * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 | ||
32 | * Helge Deller's original hilkbd.c port for PA-RISC. | ||
33 | * | ||
34 | * | ||
35 | * Driver theory of operation: | ||
36 | * | ||
37 | * hp_sdc_put does all writing to the SDC. ISR can run on a different | ||
38 | * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time | ||
39 | * (it cannot really benefit from SMP anyway.) A tasket fit this perfectly. | ||
40 | * | ||
41 | * All data coming back from the SDC is sent via interrupt and can be read | ||
42 | * fully in the ISR, so there are no latency/throughput problems there. | ||
43 | * The problem is with output, due to the slow clock speed of the SDC | ||
44 | * compared to the CPU. This should not be too horrible most of the time, | ||
45 | * but if used with HIL devices that support the multibyte transfer command, | ||
46 | * keeping outbound throughput flowing at the 6500KBps that the HIL is | ||
47 | * capable of is more than can be done at HZ=100. | ||
48 | * | ||
49 | * Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf | ||
50 | * is set to 0 when the IBF flag in the status register has cleared. ISR | ||
51 | * may do this, and may also access the parts of queued transactions related | ||
52 | * to reading data back from the SDC, but otherwise will not touch the | ||
53 | * hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1. | ||
54 | * | ||
55 | * The i8042 write index and the values in the 4-byte input buffer | ||
56 | * starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively, | ||
57 | * to minimize the amount of IO needed to the SDC. However these values | ||
58 | * do not need to be locked since they are only ever accessed by hp_sdc_put. | ||
59 | * | ||
60 | * A timer task schedules the tasklet once per second just to make | ||
61 | * sure it doesn't freeze up and to allow for bad reads to time out. | ||
62 | */ | ||
63 | |||
64 | #include <linux/hp_sdc.h> | ||
65 | #include <linux/sched.h> | ||
66 | #include <linux/errno.h> | ||
67 | #include <linux/init.h> | ||
68 | #include <linux/module.h> | ||
69 | #include <linux/ioport.h> | ||
70 | #include <linux/time.h> | ||
71 | #include <linux/slab.h> | ||
72 | #include <linux/hil.h> | ||
73 | #include <asm/io.h> | ||
74 | #include <asm/system.h> | ||
75 | |||
76 | /* Machine-specific abstraction */ | ||
77 | |||
78 | #if defined(__hppa__) | ||
79 | # include <asm/parisc-device.h> | ||
80 | # define sdc_readb(p) gsc_readb(p) | ||
81 | # define sdc_writeb(v,p) gsc_writeb((v),(p)) | ||
82 | #elif defined(__mc68000__) | ||
83 | # include <asm/uaccess.h> | ||
84 | # define sdc_readb(p) in_8(p) | ||
85 | # define sdc_writeb(v,p) out_8((p),(v)) | ||
86 | #else | ||
87 | # error "HIL is not supported on this platform" | ||
88 | #endif | ||
89 | |||
90 | #define PREFIX "HP SDC: " | ||
91 | |||
92 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
93 | MODULE_DESCRIPTION("HP i8042-based SDC Driver"); | ||
94 | MODULE_LICENSE("Dual BSD/GPL"); | ||
95 | |||
96 | EXPORT_SYMBOL(hp_sdc_request_timer_irq); | ||
97 | EXPORT_SYMBOL(hp_sdc_request_hil_irq); | ||
98 | EXPORT_SYMBOL(hp_sdc_request_cooked_irq); | ||
99 | |||
100 | EXPORT_SYMBOL(hp_sdc_release_timer_irq); | ||
101 | EXPORT_SYMBOL(hp_sdc_release_hil_irq); | ||
102 | EXPORT_SYMBOL(hp_sdc_release_cooked_irq); | ||
103 | |||
104 | EXPORT_SYMBOL(hp_sdc_enqueue_transaction); | ||
105 | EXPORT_SYMBOL(hp_sdc_dequeue_transaction); | ||
106 | |||
107 | static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */ | ||
108 | |||
109 | /*************** primitives for use in any context *********************/ | ||
110 | static inline uint8_t hp_sdc_status_in8 (void) { | ||
111 | uint8_t status; | ||
112 | unsigned long flags; | ||
113 | |||
114 | write_lock_irqsave(&hp_sdc.ibf_lock, flags); | ||
115 | status = sdc_readb(hp_sdc.status_io); | ||
116 | if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0; | ||
117 | write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); | ||
118 | |||
119 | return status; | ||
120 | } | ||
121 | |||
122 | static inline uint8_t hp_sdc_data_in8 (void) { | ||
123 | return sdc_readb(hp_sdc.data_io); | ||
124 | } | ||
125 | |||
126 | static inline void hp_sdc_status_out8 (uint8_t val) { | ||
127 | unsigned long flags; | ||
128 | |||
129 | write_lock_irqsave(&hp_sdc.ibf_lock, flags); | ||
130 | hp_sdc.ibf = 1; | ||
131 | if ((val & 0xf0) == 0xe0) hp_sdc.wi = 0xff; | ||
132 | sdc_writeb(val, hp_sdc.status_io); | ||
133 | write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); | ||
134 | } | ||
135 | |||
136 | static inline void hp_sdc_data_out8 (uint8_t val) { | ||
137 | unsigned long flags; | ||
138 | |||
139 | write_lock_irqsave(&hp_sdc.ibf_lock, flags); | ||
140 | hp_sdc.ibf = 1; | ||
141 | sdc_writeb(val, hp_sdc.data_io); | ||
142 | write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); | ||
143 | } | ||
144 | |||
145 | /* Care must be taken to only invoke hp_sdc_spin_ibf when | ||
146 | * absolutely needed, or in rarely invoked subroutines. | ||
147 | * Not only does it waste CPU cycles, it also wastes bus cycles. | ||
148 | */ | ||
149 | static inline void hp_sdc_spin_ibf(void) { | ||
150 | unsigned long flags; | ||
151 | rwlock_t *lock; | ||
152 | |||
153 | lock = &hp_sdc.ibf_lock; | ||
154 | |||
155 | read_lock_irqsave(lock, flags); | ||
156 | if (!hp_sdc.ibf) { | ||
157 | read_unlock_irqrestore(lock, flags); | ||
158 | return; | ||
159 | } | ||
160 | read_unlock(lock); | ||
161 | write_lock(lock); | ||
162 | while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {}; | ||
163 | hp_sdc.ibf = 0; | ||
164 | write_unlock_irqrestore(lock, flags); | ||
165 | } | ||
166 | |||
167 | |||
168 | /************************ Interrupt context functions ************************/ | ||
169 | static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) { | ||
170 | hp_sdc_transaction *curr; | ||
171 | |||
172 | read_lock(&hp_sdc.rtq_lock); | ||
173 | if (hp_sdc.rcurr < 0) { | ||
174 | read_unlock(&hp_sdc.rtq_lock); | ||
175 | return; | ||
176 | } | ||
177 | curr = hp_sdc.tq[hp_sdc.rcurr]; | ||
178 | read_unlock(&hp_sdc.rtq_lock); | ||
179 | |||
180 | curr->seq[curr->idx++] = status; | ||
181 | curr->seq[curr->idx++] = data; | ||
182 | hp_sdc.rqty -= 2; | ||
183 | do_gettimeofday(&hp_sdc.rtv); | ||
184 | |||
185 | if (hp_sdc.rqty <= 0) { | ||
186 | /* All data has been gathered. */ | ||
187 | if(curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) { | ||
188 | if (curr->act.semaphore) up(curr->act.semaphore); | ||
189 | } | ||
190 | if(curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) { | ||
191 | if (curr->act.irqhook) | ||
192 | curr->act.irqhook(irq, dev_id, status, data); | ||
193 | } | ||
194 | curr->actidx = curr->idx; | ||
195 | curr->idx++; | ||
196 | /* Return control of this transaction */ | ||
197 | write_lock(&hp_sdc.rtq_lock); | ||
198 | hp_sdc.rcurr = -1; | ||
199 | hp_sdc.rqty = 0; | ||
200 | write_unlock(&hp_sdc.rtq_lock); | ||
201 | tasklet_schedule(&hp_sdc.task); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | static irqreturn_t hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) { | ||
206 | uint8_t status, data; | ||
207 | |||
208 | status = hp_sdc_status_in8(); | ||
209 | /* Read data unconditionally to advance i8042. */ | ||
210 | data = hp_sdc_data_in8(); | ||
211 | |||
212 | /* For now we are ignoring these until we get the SDC to behave. */ | ||
213 | if (((status & 0xf1) == 0x51) && data == 0x82) { | ||
214 | return IRQ_HANDLED; | ||
215 | } | ||
216 | |||
217 | switch(status & HP_SDC_STATUS_IRQMASK) { | ||
218 | case 0: /* This case is not documented. */ | ||
219 | break; | ||
220 | case HP_SDC_STATUS_USERTIMER: | ||
221 | case HP_SDC_STATUS_PERIODIC: | ||
222 | case HP_SDC_STATUS_TIMER: | ||
223 | read_lock(&hp_sdc.hook_lock); | ||
224 | if (hp_sdc.timer != NULL) | ||
225 | hp_sdc.timer(irq, dev_id, status, data); | ||
226 | read_unlock(&hp_sdc.hook_lock); | ||
227 | break; | ||
228 | case HP_SDC_STATUS_REG: | ||
229 | hp_sdc_take(irq, dev_id, status, data); | ||
230 | break; | ||
231 | case HP_SDC_STATUS_HILCMD: | ||
232 | case HP_SDC_STATUS_HILDATA: | ||
233 | read_lock(&hp_sdc.hook_lock); | ||
234 | if (hp_sdc.hil != NULL) | ||
235 | hp_sdc.hil(irq, dev_id, status, data); | ||
236 | read_unlock(&hp_sdc.hook_lock); | ||
237 | break; | ||
238 | case HP_SDC_STATUS_PUP: | ||
239 | read_lock(&hp_sdc.hook_lock); | ||
240 | if (hp_sdc.pup != NULL) | ||
241 | hp_sdc.pup(irq, dev_id, status, data); | ||
242 | else printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n"); | ||
243 | read_unlock(&hp_sdc.hook_lock); | ||
244 | break; | ||
245 | default: | ||
246 | read_lock(&hp_sdc.hook_lock); | ||
247 | if (hp_sdc.cooked != NULL) | ||
248 | hp_sdc.cooked(irq, dev_id, status, data); | ||
249 | read_unlock(&hp_sdc.hook_lock); | ||
250 | break; | ||
251 | } | ||
252 | return IRQ_HANDLED; | ||
253 | } | ||
254 | |||
255 | |||
256 | static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id, struct pt_regs * regs) { | ||
257 | int status; | ||
258 | |||
259 | status = hp_sdc_status_in8(); | ||
260 | printk(KERN_WARNING PREFIX "NMI !\n"); | ||
261 | |||
262 | #if 0 | ||
263 | if (status & HP_SDC_NMISTATUS_FHS) { | ||
264 | read_lock(&hp_sdc.hook_lock); | ||
265 | if (hp_sdc.timer != NULL) | ||
266 | hp_sdc.timer(irq, dev_id, status, 0); | ||
267 | read_unlock(&hp_sdc.hook_lock); | ||
268 | } | ||
269 | else { | ||
270 | /* TODO: pass this on to the HIL handler, or do SAK here? */ | ||
271 | printk(KERN_WARNING PREFIX "HIL NMI\n"); | ||
272 | } | ||
273 | #endif | ||
274 | return IRQ_HANDLED; | ||
275 | } | ||
276 | |||
277 | |||
278 | /***************** Kernel (tasklet) context functions ****************/ | ||
279 | |||
280 | unsigned long hp_sdc_put(void); | ||
281 | |||
282 | static void hp_sdc_tasklet(unsigned long foo) { | ||
283 | |||
284 | write_lock_irq(&hp_sdc.rtq_lock); | ||
285 | if (hp_sdc.rcurr >= 0) { | ||
286 | struct timeval tv; | ||
287 | do_gettimeofday(&tv); | ||
288 | if (tv.tv_sec > hp_sdc.rtv.tv_sec) tv.tv_usec += 1000000; | ||
289 | if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) { | ||
290 | hp_sdc_transaction *curr; | ||
291 | uint8_t tmp; | ||
292 | |||
293 | curr = hp_sdc.tq[hp_sdc.rcurr]; | ||
294 | /* If this turns out to be a normal failure mode | ||
295 | * we'll need to figure out a way to communicate | ||
296 | * it back to the application. and be less verbose. | ||
297 | */ | ||
298 | printk(KERN_WARNING PREFIX "read timeout (%ius)!\n", | ||
299 | tv.tv_usec - hp_sdc.rtv.tv_usec); | ||
300 | curr->idx += hp_sdc.rqty; | ||
301 | hp_sdc.rqty = 0; | ||
302 | tmp = curr->seq[curr->actidx]; | ||
303 | curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD; | ||
304 | if(tmp & HP_SDC_ACT_SEMAPHORE) { | ||
305 | if (curr->act.semaphore) | ||
306 | up(curr->act.semaphore); | ||
307 | } | ||
308 | if(tmp & HP_SDC_ACT_CALLBACK) { | ||
309 | /* Note this means that irqhooks may be called | ||
310 | * in tasklet/bh context. | ||
311 | */ | ||
312 | if (curr->act.irqhook) | ||
313 | curr->act.irqhook(0, 0, 0, 0); | ||
314 | } | ||
315 | curr->actidx = curr->idx; | ||
316 | curr->idx++; | ||
317 | hp_sdc.rcurr = -1; | ||
318 | } | ||
319 | } | ||
320 | write_unlock_irq(&hp_sdc.rtq_lock); | ||
321 | hp_sdc_put(); | ||
322 | } | ||
323 | |||
324 | unsigned long hp_sdc_put(void) { | ||
325 | hp_sdc_transaction *curr; | ||
326 | uint8_t act; | ||
327 | int idx, curridx; | ||
328 | |||
329 | int limit = 0; | ||
330 | |||
331 | write_lock(&hp_sdc.lock); | ||
332 | |||
333 | /* If i8042 buffers are full, we cannot do anything that | ||
334 | requires output, so we skip to the administrativa. */ | ||
335 | if (hp_sdc.ibf) { | ||
336 | hp_sdc_status_in8(); | ||
337 | if (hp_sdc.ibf) goto finish; | ||
338 | } | ||
339 | |||
340 | anew: | ||
341 | /* See if we are in the middle of a sequence. */ | ||
342 | if (hp_sdc.wcurr < 0) hp_sdc.wcurr = 0; | ||
343 | read_lock_irq(&hp_sdc.rtq_lock); | ||
344 | if (hp_sdc.rcurr == hp_sdc.wcurr) hp_sdc.wcurr++; | ||
345 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
346 | if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; | ||
347 | curridx = hp_sdc.wcurr; | ||
348 | |||
349 | if (hp_sdc.tq[curridx] != NULL) goto start; | ||
350 | |||
351 | while (++curridx != hp_sdc.wcurr) { | ||
352 | if (curridx >= HP_SDC_QUEUE_LEN) { | ||
353 | curridx = -1; /* Wrap to top */ | ||
354 | continue; | ||
355 | } | ||
356 | read_lock_irq(&hp_sdc.rtq_lock); | ||
357 | if (hp_sdc.rcurr == curridx) { | ||
358 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
359 | continue; | ||
360 | } | ||
361 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
362 | if (hp_sdc.tq[curridx] != NULL) break; /* Found one. */ | ||
363 | } | ||
364 | if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */ | ||
365 | curridx = -1; | ||
366 | } | ||
367 | hp_sdc.wcurr = curridx; | ||
368 | |||
369 | start: | ||
370 | |||
371 | /* Check to see if the interrupt mask needs to be set. */ | ||
372 | if (hp_sdc.set_im) { | ||
373 | hp_sdc_status_out8(hp_sdc.im | HP_SDC_CMD_SET_IM); | ||
374 | hp_sdc.set_im = 0; | ||
375 | goto finish; | ||
376 | } | ||
377 | |||
378 | if (hp_sdc.wcurr == -1) goto done; | ||
379 | |||
380 | curr = hp_sdc.tq[curridx]; | ||
381 | idx = curr->actidx; | ||
382 | |||
383 | if (curr->actidx >= curr->endidx) { | ||
384 | hp_sdc.tq[curridx] = NULL; | ||
385 | /* Interleave outbound data between the transactions. */ | ||
386 | hp_sdc.wcurr++; | ||
387 | if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; | ||
388 | goto finish; | ||
389 | } | ||
390 | |||
391 | act = curr->seq[idx]; | ||
392 | idx++; | ||
393 | |||
394 | if (curr->idx >= curr->endidx) { | ||
395 | if (act & HP_SDC_ACT_DEALLOC) kfree(curr); | ||
396 | hp_sdc.tq[curridx] = NULL; | ||
397 | /* Interleave outbound data between the transactions. */ | ||
398 | hp_sdc.wcurr++; | ||
399 | if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; | ||
400 | goto finish; | ||
401 | } | ||
402 | |||
403 | while (act & HP_SDC_ACT_PRECMD) { | ||
404 | if (curr->idx != idx) { | ||
405 | idx++; | ||
406 | act &= ~HP_SDC_ACT_PRECMD; | ||
407 | break; | ||
408 | } | ||
409 | hp_sdc_status_out8(curr->seq[idx]); | ||
410 | curr->idx++; | ||
411 | /* act finished? */ | ||
412 | if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD) | ||
413 | goto actdone; | ||
414 | /* skip quantity field if data-out sequence follows. */ | ||
415 | if (act & HP_SDC_ACT_DATAOUT) curr->idx++; | ||
416 | goto finish; | ||
417 | } | ||
418 | if (act & HP_SDC_ACT_DATAOUT) { | ||
419 | int qty; | ||
420 | |||
421 | qty = curr->seq[idx]; | ||
422 | idx++; | ||
423 | if (curr->idx - idx < qty) { | ||
424 | hp_sdc_data_out8(curr->seq[curr->idx]); | ||
425 | curr->idx++; | ||
426 | /* act finished? */ | ||
427 | if ((curr->idx - idx >= qty) && | ||
428 | ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)) | ||
429 | goto actdone; | ||
430 | goto finish; | ||
431 | } | ||
432 | idx += qty; | ||
433 | act &= ~HP_SDC_ACT_DATAOUT; | ||
434 | } | ||
435 | else while (act & HP_SDC_ACT_DATAREG) { | ||
436 | int mask; | ||
437 | uint8_t w7[4]; | ||
438 | |||
439 | mask = curr->seq[idx]; | ||
440 | if (idx != curr->idx) { | ||
441 | idx++; | ||
442 | idx += !!(mask & 1); | ||
443 | idx += !!(mask & 2); | ||
444 | idx += !!(mask & 4); | ||
445 | idx += !!(mask & 8); | ||
446 | act &= ~HP_SDC_ACT_DATAREG; | ||
447 | break; | ||
448 | } | ||
449 | |||
450 | w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0]; | ||
451 | w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1]; | ||
452 | w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2]; | ||
453 | w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3]; | ||
454 | |||
455 | if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 || | ||
456 | w7[hp_sdc.wi-0x70] == hp_sdc.r7[hp_sdc.wi-0x70]) { | ||
457 | int i = 0; | ||
458 | |||
459 | /* Need to point the write index register */ | ||
460 | while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++; | ||
461 | if (i < 4) { | ||
462 | hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i); | ||
463 | hp_sdc.wi = 0x70 + i; | ||
464 | goto finish; | ||
465 | } | ||
466 | idx++; | ||
467 | if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG) | ||
468 | goto actdone; | ||
469 | curr->idx = idx; | ||
470 | act &= ~HP_SDC_ACT_DATAREG; | ||
471 | break; | ||
472 | } | ||
473 | |||
474 | hp_sdc_data_out8(w7[hp_sdc.wi - 0x70]); | ||
475 | hp_sdc.r7[hp_sdc.wi - 0x70] = w7[hp_sdc.wi - 0x70]; | ||
476 | hp_sdc.wi++; /* write index register autoincrements */ | ||
477 | { | ||
478 | int i = 0; | ||
479 | |||
480 | while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++; | ||
481 | if (i >= 4) { | ||
482 | curr->idx = idx + 1; | ||
483 | if ((act & HP_SDC_ACT_DURING) == | ||
484 | HP_SDC_ACT_DATAREG) | ||
485 | goto actdone; | ||
486 | } | ||
487 | } | ||
488 | goto finish; | ||
489 | } | ||
490 | /* We don't go any further in the command if there is a pending read, | ||
491 | because we don't want interleaved results. */ | ||
492 | read_lock_irq(&hp_sdc.rtq_lock); | ||
493 | if (hp_sdc.rcurr >= 0) { | ||
494 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
495 | goto finish; | ||
496 | } | ||
497 | read_unlock_irq(&hp_sdc.rtq_lock); | ||
498 | |||
499 | |||
500 | if (act & HP_SDC_ACT_POSTCMD) { | ||
501 | uint8_t postcmd; | ||
502 | |||
503 | /* curr->idx should == idx at this point. */ | ||
504 | postcmd = curr->seq[idx]; | ||
505 | curr->idx++; | ||
506 | if (act & HP_SDC_ACT_DATAIN) { | ||
507 | |||
508 | /* Start a new read */ | ||
509 | hp_sdc.rqty = curr->seq[curr->idx]; | ||
510 | do_gettimeofday(&hp_sdc.rtv); | ||
511 | curr->idx++; | ||
512 | /* Still need to lock here in case of spurious irq. */ | ||
513 | write_lock_irq(&hp_sdc.rtq_lock); | ||
514 | hp_sdc.rcurr = curridx; | ||
515 | write_unlock_irq(&hp_sdc.rtq_lock); | ||
516 | hp_sdc_status_out8(postcmd); | ||
517 | goto finish; | ||
518 | } | ||
519 | hp_sdc_status_out8(postcmd); | ||
520 | goto actdone; | ||
521 | } | ||
522 | |||
523 | actdone: | ||
524 | if (act & HP_SDC_ACT_SEMAPHORE) { | ||
525 | up(curr->act.semaphore); | ||
526 | } | ||
527 | else if (act & HP_SDC_ACT_CALLBACK) { | ||
528 | curr->act.irqhook(0,0,0,0); | ||
529 | } | ||
530 | if (curr->idx >= curr->endidx) { /* This transaction is over. */ | ||
531 | if (act & HP_SDC_ACT_DEALLOC) kfree(curr); | ||
532 | hp_sdc.tq[curridx] = NULL; | ||
533 | } | ||
534 | else { | ||
535 | curr->actidx = idx + 1; | ||
536 | curr->idx = idx + 2; | ||
537 | } | ||
538 | /* Interleave outbound data between the transactions. */ | ||
539 | hp_sdc.wcurr++; | ||
540 | if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; | ||
541 | |||
542 | finish: | ||
543 | /* If by some quirk IBF has cleared and our ISR has run to | ||
544 | see that that has happened, do it all again. */ | ||
545 | if (!hp_sdc.ibf && limit++ < 20) goto anew; | ||
546 | |||
547 | done: | ||
548 | if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task); | ||
549 | write_unlock(&hp_sdc.lock); | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | /******* Functions called in either user or kernel context ****/ | ||
554 | int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) { | ||
555 | unsigned long flags; | ||
556 | int i; | ||
557 | |||
558 | if (this == NULL) { | ||
559 | tasklet_schedule(&hp_sdc.task); | ||
560 | return -EINVAL; | ||
561 | }; | ||
562 | |||
563 | write_lock_irqsave(&hp_sdc.lock, flags); | ||
564 | |||
565 | /* Can't have same transaction on queue twice */ | ||
566 | for (i=0; i < HP_SDC_QUEUE_LEN; i++) | ||
567 | if (hp_sdc.tq[i] == this) goto fail; | ||
568 | |||
569 | this->actidx = 0; | ||
570 | this->idx = 1; | ||
571 | |||
572 | /* Search for empty slot */ | ||
573 | for (i=0; i < HP_SDC_QUEUE_LEN; i++) { | ||
574 | if (hp_sdc.tq[i] == NULL) { | ||
575 | hp_sdc.tq[i] = this; | ||
576 | write_unlock_irqrestore(&hp_sdc.lock, flags); | ||
577 | tasklet_schedule(&hp_sdc.task); | ||
578 | return 0; | ||
579 | } | ||
580 | } | ||
581 | write_unlock_irqrestore(&hp_sdc.lock, flags); | ||
582 | printk(KERN_WARNING PREFIX "No free slot to add transaction.\n"); | ||
583 | return -EBUSY; | ||
584 | |||
585 | fail: | ||
586 | write_unlock_irqrestore(&hp_sdc.lock,flags); | ||
587 | printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n"); | ||
588 | return -EINVAL; | ||
589 | } | ||
590 | |||
591 | int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) { | ||
592 | unsigned long flags; | ||
593 | int i; | ||
594 | |||
595 | write_lock_irqsave(&hp_sdc.lock, flags); | ||
596 | |||
597 | /* TODO: don't remove it if it's not done. */ | ||
598 | |||
599 | for (i=0; i < HP_SDC_QUEUE_LEN; i++) | ||
600 | if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL; | ||
601 | |||
602 | write_unlock_irqrestore(&hp_sdc.lock, flags); | ||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | |||
607 | |||
608 | /********************** User context functions **************************/ | ||
609 | int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) { | ||
610 | |||
611 | if (callback == NULL || hp_sdc.dev == NULL) { | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | write_lock_irq(&hp_sdc.hook_lock); | ||
615 | if (hp_sdc.timer != NULL) { | ||
616 | write_unlock_irq(&hp_sdc.hook_lock); | ||
617 | return -EBUSY; | ||
618 | } | ||
619 | |||
620 | hp_sdc.timer = callback; | ||
621 | /* Enable interrupts from the timers */ | ||
622 | hp_sdc.im &= ~HP_SDC_IM_FH; | ||
623 | hp_sdc.im &= ~HP_SDC_IM_PT; | ||
624 | hp_sdc.im &= ~HP_SDC_IM_TIMERS; | ||
625 | hp_sdc.set_im = 1; | ||
626 | write_unlock_irq(&hp_sdc.hook_lock); | ||
627 | |||
628 | tasklet_schedule(&hp_sdc.task); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) { | ||
634 | |||
635 | if (callback == NULL || hp_sdc.dev == NULL) { | ||
636 | return -EINVAL; | ||
637 | } | ||
638 | write_lock_irq(&hp_sdc.hook_lock); | ||
639 | if (hp_sdc.hil != NULL) { | ||
640 | write_unlock_irq(&hp_sdc.hook_lock); | ||
641 | return -EBUSY; | ||
642 | } | ||
643 | |||
644 | hp_sdc.hil = callback; | ||
645 | hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET); | ||
646 | hp_sdc.set_im = 1; | ||
647 | write_unlock_irq(&hp_sdc.hook_lock); | ||
648 | |||
649 | tasklet_schedule(&hp_sdc.task); | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) { | ||
655 | |||
656 | if (callback == NULL || hp_sdc.dev == NULL) { | ||
657 | return -EINVAL; | ||
658 | } | ||
659 | write_lock_irq(&hp_sdc.hook_lock); | ||
660 | if (hp_sdc.cooked != NULL) { | ||
661 | write_unlock_irq(&hp_sdc.hook_lock); | ||
662 | return -EBUSY; | ||
663 | } | ||
664 | |||
665 | /* Enable interrupts from the HIL MLC */ | ||
666 | hp_sdc.cooked = callback; | ||
667 | hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET); | ||
668 | hp_sdc.set_im = 1; | ||
669 | write_unlock_irq(&hp_sdc.hook_lock); | ||
670 | |||
671 | tasklet_schedule(&hp_sdc.task); | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) { | ||
677 | |||
678 | |||
679 | write_lock_irq(&hp_sdc.hook_lock); | ||
680 | if ((callback != hp_sdc.timer) || | ||
681 | (hp_sdc.timer == NULL)) { | ||
682 | write_unlock_irq(&hp_sdc.hook_lock); | ||
683 | return -EINVAL; | ||
684 | } | ||
685 | |||
686 | /* Disable interrupts from the timers */ | ||
687 | hp_sdc.timer = NULL; | ||
688 | hp_sdc.im |= HP_SDC_IM_TIMERS; | ||
689 | hp_sdc.im |= HP_SDC_IM_FH; | ||
690 | hp_sdc.im |= HP_SDC_IM_PT; | ||
691 | hp_sdc.set_im = 1; | ||
692 | write_unlock_irq(&hp_sdc.hook_lock); | ||
693 | tasklet_schedule(&hp_sdc.task); | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) { | ||
699 | |||
700 | write_lock_irq(&hp_sdc.hook_lock); | ||
701 | if ((callback != hp_sdc.hil) || | ||
702 | (hp_sdc.hil == NULL)) { | ||
703 | write_unlock_irq(&hp_sdc.hook_lock); | ||
704 | return -EINVAL; | ||
705 | } | ||
706 | |||
707 | hp_sdc.hil = NULL; | ||
708 | /* Disable interrupts from HIL only if there is no cooked driver. */ | ||
709 | if(hp_sdc.cooked == NULL) { | ||
710 | hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET); | ||
711 | hp_sdc.set_im = 1; | ||
712 | } | ||
713 | write_unlock_irq(&hp_sdc.hook_lock); | ||
714 | tasklet_schedule(&hp_sdc.task); | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) { | ||
720 | |||
721 | write_lock_irq(&hp_sdc.hook_lock); | ||
722 | if ((callback != hp_sdc.cooked) || | ||
723 | (hp_sdc.cooked == NULL)) { | ||
724 | write_unlock_irq(&hp_sdc.hook_lock); | ||
725 | return -EINVAL; | ||
726 | } | ||
727 | |||
728 | hp_sdc.cooked = NULL; | ||
729 | /* Disable interrupts from HIL only if there is no raw HIL driver. */ | ||
730 | if(hp_sdc.hil == NULL) { | ||
731 | hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET); | ||
732 | hp_sdc.set_im = 1; | ||
733 | } | ||
734 | write_unlock_irq(&hp_sdc.hook_lock); | ||
735 | tasklet_schedule(&hp_sdc.task); | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | /************************* Keepalive timer task *********************/ | ||
741 | |||
742 | void hp_sdc_kicker (unsigned long data) { | ||
743 | tasklet_schedule(&hp_sdc.task); | ||
744 | /* Re-insert the periodic task. */ | ||
745 | mod_timer(&hp_sdc.kicker, jiffies + HZ); | ||
746 | } | ||
747 | |||
748 | /************************** Module Initialization ***************************/ | ||
749 | |||
750 | #if defined(__hppa__) | ||
751 | |||
752 | static struct parisc_device_id hp_sdc_tbl[] = { | ||
753 | { | ||
754 | .hw_type = HPHW_FIO, | ||
755 | .hversion_rev = HVERSION_REV_ANY_ID, | ||
756 | .hversion = HVERSION_ANY_ID, | ||
757 | .sversion = 0x73, | ||
758 | }, | ||
759 | { 0, } | ||
760 | }; | ||
761 | |||
762 | MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl); | ||
763 | |||
764 | static int __init hp_sdc_init_hppa(struct parisc_device *d); | ||
765 | |||
766 | static struct parisc_driver hp_sdc_driver = { | ||
767 | .name = "HP SDC", | ||
768 | .id_table = hp_sdc_tbl, | ||
769 | .probe = hp_sdc_init_hppa, | ||
770 | }; | ||
771 | |||
772 | #endif /* __hppa__ */ | ||
773 | |||
774 | static int __init hp_sdc_init(void) | ||
775 | { | ||
776 | int i; | ||
777 | char *errstr; | ||
778 | hp_sdc_transaction t_sync; | ||
779 | uint8_t ts_sync[6]; | ||
780 | struct semaphore s_sync; | ||
781 | |||
782 | rwlock_init(&hp_sdc.lock); | ||
783 | rwlock_init(&hp_sdc.ibf_lock); | ||
784 | rwlock_init(&hp_sdc.rtq_lock); | ||
785 | rwlock_init(&hp_sdc.hook_lock); | ||
786 | |||
787 | hp_sdc.timer = NULL; | ||
788 | hp_sdc.hil = NULL; | ||
789 | hp_sdc.pup = NULL; | ||
790 | hp_sdc.cooked = NULL; | ||
791 | hp_sdc.im = HP_SDC_IM_MASK; /* Mask maskable irqs */ | ||
792 | hp_sdc.set_im = 1; | ||
793 | hp_sdc.wi = 0xff; | ||
794 | hp_sdc.r7[0] = 0xff; | ||
795 | hp_sdc.r7[1] = 0xff; | ||
796 | hp_sdc.r7[2] = 0xff; | ||
797 | hp_sdc.r7[3] = 0xff; | ||
798 | hp_sdc.ibf = 1; | ||
799 | |||
800 | for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL; | ||
801 | hp_sdc.wcurr = -1; | ||
802 | hp_sdc.rcurr = -1; | ||
803 | hp_sdc.rqty = 0; | ||
804 | |||
805 | hp_sdc.dev_err = -ENODEV; | ||
806 | |||
807 | errstr = "IO not found for"; | ||
808 | if (!hp_sdc.base_io) goto err0; | ||
809 | |||
810 | errstr = "IRQ not found for"; | ||
811 | if (!hp_sdc.irq) goto err0; | ||
812 | |||
813 | hp_sdc.dev_err = -EBUSY; | ||
814 | |||
815 | #if defined(__hppa__) | ||
816 | errstr = "IO not available for"; | ||
817 | if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0; | ||
818 | #endif | ||
819 | |||
820 | errstr = "IRQ not available for"; | ||
821 | if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC", | ||
822 | (void *) hp_sdc.base_io)) goto err1; | ||
823 | |||
824 | errstr = "NMI not available for"; | ||
825 | if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI", | ||
826 | (void *) hp_sdc.base_io)) goto err2; | ||
827 | |||
828 | printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", | ||
829 | (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); | ||
830 | |||
831 | hp_sdc_status_in8(); | ||
832 | hp_sdc_data_in8(); | ||
833 | |||
834 | tasklet_init(&hp_sdc.task, hp_sdc_tasklet, 0); | ||
835 | |||
836 | /* Sync the output buffer registers, thus scheduling hp_sdc_tasklet. */ | ||
837 | t_sync.actidx = 0; | ||
838 | t_sync.idx = 1; | ||
839 | t_sync.endidx = 6; | ||
840 | t_sync.seq = ts_sync; | ||
841 | ts_sync[0] = HP_SDC_ACT_DATAREG | HP_SDC_ACT_SEMAPHORE; | ||
842 | ts_sync[1] = 0x0f; | ||
843 | ts_sync[2] = ts_sync[3] = ts_sync[4] = ts_sync[5] = 0; | ||
844 | t_sync.act.semaphore = &s_sync; | ||
845 | init_MUTEX_LOCKED(&s_sync); | ||
846 | hp_sdc_enqueue_transaction(&t_sync); | ||
847 | down(&s_sync); /* Wait for t_sync to complete */ | ||
848 | |||
849 | /* Create the keepalive task */ | ||
850 | init_timer(&hp_sdc.kicker); | ||
851 | hp_sdc.kicker.expires = jiffies + HZ; | ||
852 | hp_sdc.kicker.function = &hp_sdc_kicker; | ||
853 | add_timer(&hp_sdc.kicker); | ||
854 | |||
855 | hp_sdc.dev_err = 0; | ||
856 | return 0; | ||
857 | err2: | ||
858 | free_irq(hp_sdc.irq, NULL); | ||
859 | err1: | ||
860 | release_region(hp_sdc.data_io, 2); | ||
861 | err0: | ||
862 | printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n", | ||
863 | errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); | ||
864 | hp_sdc.dev = NULL; | ||
865 | return hp_sdc.dev_err; | ||
866 | } | ||
867 | |||
868 | #if defined(__hppa__) | ||
869 | |||
870 | static int __init hp_sdc_init_hppa(struct parisc_device *d) | ||
871 | { | ||
872 | if (!d) return 1; | ||
873 | if (hp_sdc.dev != NULL) return 1; /* We only expect one SDC */ | ||
874 | |||
875 | hp_sdc.dev = d; | ||
876 | hp_sdc.irq = d->irq; | ||
877 | hp_sdc.nmi = d->aux_irq; | ||
878 | hp_sdc.base_io = d->hpa; | ||
879 | hp_sdc.data_io = d->hpa + 0x800; | ||
880 | hp_sdc.status_io = d->hpa + 0x801; | ||
881 | |||
882 | return hp_sdc_init(); | ||
883 | } | ||
884 | |||
885 | #endif /* __hppa__ */ | ||
886 | |||
887 | #if !defined(__mc68000__) /* Link error on m68k! */ | ||
888 | static void __exit hp_sdc_exit(void) | ||
889 | #else | ||
890 | static void hp_sdc_exit(void) | ||
891 | #endif | ||
892 | { | ||
893 | write_lock_irq(&hp_sdc.lock); | ||
894 | |||
895 | /* Turn off all maskable "sub-function" irq's. */ | ||
896 | hp_sdc_spin_ibf(); | ||
897 | sdc_writeb(HP_SDC_CMD_SET_IM | HP_SDC_IM_MASK, hp_sdc.status_io); | ||
898 | |||
899 | /* Wait until we know this has been processed by the i8042 */ | ||
900 | hp_sdc_spin_ibf(); | ||
901 | |||
902 | free_irq(hp_sdc.nmi, NULL); | ||
903 | free_irq(hp_sdc.irq, NULL); | ||
904 | write_unlock_irq(&hp_sdc.lock); | ||
905 | |||
906 | del_timer(&hp_sdc.kicker); | ||
907 | |||
908 | tasklet_kill(&hp_sdc.task); | ||
909 | |||
910 | /* release_region(hp_sdc.data_io, 2); */ | ||
911 | |||
912 | #if defined(__hppa__) | ||
913 | if (unregister_parisc_driver(&hp_sdc_driver)) | ||
914 | printk(KERN_WARNING PREFIX "Error unregistering HP SDC"); | ||
915 | #endif | ||
916 | } | ||
917 | |||
918 | static int __init hp_sdc_register(void) | ||
919 | { | ||
920 | hp_sdc_transaction tq_init; | ||
921 | uint8_t tq_init_seq[5]; | ||
922 | struct semaphore tq_init_sem; | ||
923 | #if defined(__mc68000__) | ||
924 | mm_segment_t fs; | ||
925 | unsigned char i; | ||
926 | #endif | ||
927 | |||
928 | hp_sdc.dev = NULL; | ||
929 | hp_sdc.dev_err = 0; | ||
930 | #if defined(__hppa__) | ||
931 | if (register_parisc_driver(&hp_sdc_driver)) { | ||
932 | printk(KERN_WARNING PREFIX "Error registering SDC with system bus tree.\n"); | ||
933 | return -ENODEV; | ||
934 | } | ||
935 | #elif defined(__mc68000__) | ||
936 | if (!MACH_IS_HP300) | ||
937 | return -ENODEV; | ||
938 | |||
939 | hp_sdc.irq = 1; | ||
940 | hp_sdc.nmi = 7; | ||
941 | hp_sdc.base_io = (unsigned long) 0xf0428000; | ||
942 | hp_sdc.data_io = (unsigned long) hp_sdc.base_io + 1; | ||
943 | hp_sdc.status_io = (unsigned long) hp_sdc.base_io + 3; | ||
944 | fs = get_fs(); | ||
945 | set_fs(KERNEL_DS); | ||
946 | if (!get_user(i, (unsigned char *)hp_sdc.data_io)) | ||
947 | hp_sdc.dev = (void *)1; | ||
948 | set_fs(fs); | ||
949 | hp_sdc.dev_err = hp_sdc_init(); | ||
950 | #endif | ||
951 | if (hp_sdc.dev == NULL) { | ||
952 | printk(KERN_WARNING PREFIX "No SDC found.\n"); | ||
953 | return hp_sdc.dev_err; | ||
954 | } | ||
955 | |||
956 | init_MUTEX_LOCKED(&tq_init_sem); | ||
957 | |||
958 | tq_init.actidx = 0; | ||
959 | tq_init.idx = 1; | ||
960 | tq_init.endidx = 5; | ||
961 | tq_init.seq = tq_init_seq; | ||
962 | tq_init.act.semaphore = &tq_init_sem; | ||
963 | |||
964 | tq_init_seq[0] = | ||
965 | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; | ||
966 | tq_init_seq[1] = HP_SDC_CMD_READ_KCC; | ||
967 | tq_init_seq[2] = 1; | ||
968 | tq_init_seq[3] = 0; | ||
969 | tq_init_seq[4] = 0; | ||
970 | |||
971 | hp_sdc_enqueue_transaction(&tq_init); | ||
972 | |||
973 | down(&tq_init_sem); | ||
974 | up(&tq_init_sem); | ||
975 | |||
976 | if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) { | ||
977 | printk(KERN_WARNING PREFIX "Error reading config byte.\n"); | ||
978 | hp_sdc_exit(); | ||
979 | return -ENODEV; | ||
980 | } | ||
981 | hp_sdc.r11 = tq_init_seq[4]; | ||
982 | if (hp_sdc.r11 & HP_SDC_CFG_NEW) { | ||
983 | char *str; | ||
984 | printk(KERN_INFO PREFIX "New style SDC\n"); | ||
985 | tq_init_seq[1] = HP_SDC_CMD_READ_XTD; | ||
986 | tq_init.actidx = 0; | ||
987 | tq_init.idx = 1; | ||
988 | down(&tq_init_sem); | ||
989 | hp_sdc_enqueue_transaction(&tq_init); | ||
990 | down(&tq_init_sem); | ||
991 | up(&tq_init_sem); | ||
992 | if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) { | ||
993 | printk(KERN_WARNING PREFIX "Error reading extended config byte.\n"); | ||
994 | return -ENODEV; | ||
995 | } | ||
996 | hp_sdc.r7e = tq_init_seq[4]; | ||
997 | HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str) | ||
998 | printk(KERN_INFO PREFIX "Revision: %s\n", str); | ||
999 | if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) { | ||
1000 | printk(KERN_INFO PREFIX "TI SN76494 beeper present\n"); | ||
1001 | } | ||
1002 | if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) { | ||
1003 | printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n"); | ||
1004 | } | ||
1005 | printk(KERN_INFO PREFIX "Spunking the self test register to force PUP " | ||
1006 | "on next firmware reset.\n"); | ||
1007 | tq_init_seq[0] = HP_SDC_ACT_PRECMD | | ||
1008 | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; | ||
1009 | tq_init_seq[1] = HP_SDC_CMD_SET_STR; | ||
1010 | tq_init_seq[2] = 1; | ||
1011 | tq_init_seq[3] = 0; | ||
1012 | tq_init.actidx = 0; | ||
1013 | tq_init.idx = 1; | ||
1014 | tq_init.endidx = 4; | ||
1015 | down(&tq_init_sem); | ||
1016 | hp_sdc_enqueue_transaction(&tq_init); | ||
1017 | down(&tq_init_sem); | ||
1018 | up(&tq_init_sem); | ||
1019 | } | ||
1020 | else { | ||
1021 | printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n", | ||
1022 | (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087"); | ||
1023 | } | ||
1024 | |||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | module_init(hp_sdc_register); | ||
1029 | module_exit(hp_sdc_exit); | ||
1030 | |||
1031 | /* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64) | ||
1032 | * cycles cycles-adj time | ||
1033 | * between two consecutive mfctl(16)'s: 4 n/a 63ns | ||
1034 | * hp_sdc_spin_ibf when idle: 119 115 1.7us | ||
1035 | * gsc_writeb status register: 83 79 1.2us | ||
1036 | * IBF to clear after sending SET_IM: 6204 6006 93us | ||
1037 | * IBF to clear after sending LOAD_RT: 4467 4352 68us | ||
1038 | * IBF to clear after sending two LOAD_RTs: 18974 18859 295us | ||
1039 | * READ_T1, read status/data, IRQ, call handler: 35564 n/a 556us | ||
1040 | * cmd to ~IBF READ_T1 2nd time right after: 5158403 n/a 81ms | ||
1041 | * between IRQ received and ~IBF for above: 2578877 n/a 40ms | ||
1042 | * | ||
1043 | * Performance stats after a run of this module configuring HIL and | ||
1044 | * receiving a few mouse events: | ||
1045 | * | ||
1046 | * status in8 282508 cycles 7128 calls | ||
1047 | * status out8 8404 cycles 341 calls | ||
1048 | * data out8 1734 cycles 78 calls | ||
1049 | * isr 174324 cycles 617 calls (includes take) | ||
1050 | * take 1241 cycles 2 calls | ||
1051 | * put 1411504 cycles 6937 calls | ||
1052 | * task 1655209 cycles 6937 calls (includes put) | ||
1053 | * | ||
1054 | */ | ||
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c new file mode 100644 index 000000000000..e3c44ffae674 --- /dev/null +++ b/drivers/input/serio/hp_sdc_mlc.c | |||
@@ -0,0 +1,358 @@ | |||
1 | /* | ||
2 | * Access to HP-HIL MLC through HP System Device Controller. | ||
3 | * | ||
4 | * Copyright (c) 2001 Brian S. Julin | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * | ||
29 | * References: | ||
30 | * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A | ||
31 | * System Device Controller Microprocessor Firmware Theory of Operation | ||
32 | * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <linux/hil_mlc.h> | ||
37 | #include <linux/hp_sdc.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/string.h> | ||
43 | |||
44 | #define PREFIX "HP SDC MLC: " | ||
45 | |||
46 | static hil_mlc hp_sdc_mlc; | ||
47 | |||
48 | MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); | ||
49 | MODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines"); | ||
50 | MODULE_LICENSE("Dual BSD/GPL"); | ||
51 | |||
52 | struct hp_sdc_mlc_priv_s { | ||
53 | int emtestmode; | ||
54 | hp_sdc_transaction trans; | ||
55 | u8 tseq[16]; | ||
56 | int got5x; | ||
57 | } hp_sdc_mlc_priv; | ||
58 | |||
59 | /************************* Interrupt context ******************************/ | ||
60 | static void hp_sdc_mlc_isr (int irq, void *dev_id, | ||
61 | uint8_t status, uint8_t data) { | ||
62 | int idx; | ||
63 | hil_mlc *mlc = &hp_sdc_mlc; | ||
64 | |||
65 | write_lock(&(mlc->lock)); | ||
66 | if (mlc->icount < 0) { | ||
67 | printk(KERN_WARNING PREFIX "HIL Overflow!\n"); | ||
68 | up(&mlc->isem); | ||
69 | goto out; | ||
70 | } | ||
71 | idx = 15 - mlc->icount; | ||
72 | if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) { | ||
73 | mlc->ipacket[idx] |= data | HIL_ERR_INT; | ||
74 | mlc->icount--; | ||
75 | if (hp_sdc_mlc_priv.got5x) goto check; | ||
76 | if (!idx) goto check; | ||
77 | if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) != | ||
78 | (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) { | ||
79 | mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK; | ||
80 | mlc->ipacket[idx] |= (mlc->ipacket[idx-1] | ||
81 | & HIL_PKT_ADDR_MASK); | ||
82 | } | ||
83 | goto check; | ||
84 | } | ||
85 | /* We know status is 5X */ | ||
86 | if (data & HP_SDC_HIL_ISERR) goto err; | ||
87 | mlc->ipacket[idx] = | ||
88 | (data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT; | ||
89 | hp_sdc_mlc_priv.got5x = 1; | ||
90 | goto out; | ||
91 | |||
92 | check: | ||
93 | hp_sdc_mlc_priv.got5x = 0; | ||
94 | if (mlc->imatch == 0) goto done; | ||
95 | if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) | ||
96 | && (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done; | ||
97 | if (mlc->ipacket[idx] == mlc->imatch) goto done; | ||
98 | goto out; | ||
99 | |||
100 | err: | ||
101 | printk(KERN_DEBUG PREFIX "err code %x\n", data); | ||
102 | switch (data) { | ||
103 | case HP_SDC_HIL_RC_DONE: | ||
104 | printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n"); | ||
105 | break; | ||
106 | case HP_SDC_HIL_ERR: | ||
107 | mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | | ||
108 | HIL_ERR_FERR | HIL_ERR_FOF; | ||
109 | break; | ||
110 | case HP_SDC_HIL_TO: | ||
111 | mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR; | ||
112 | break; | ||
113 | case HP_SDC_HIL_RC: | ||
114 | printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n"); | ||
115 | break; | ||
116 | default: | ||
117 | printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data); | ||
118 | break; | ||
119 | } | ||
120 | /* No more data will be coming due to an error. */ | ||
121 | done: | ||
122 | tasklet_schedule(mlc->tasklet); | ||
123 | up(&(mlc->isem)); | ||
124 | out: | ||
125 | write_unlock(&(mlc->lock)); | ||
126 | } | ||
127 | |||
128 | |||
129 | /******************** Tasklet or userspace context functions ****************/ | ||
130 | |||
131 | static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) { | ||
132 | unsigned long flags; | ||
133 | struct hp_sdc_mlc_priv_s *priv; | ||
134 | int rc = 2; | ||
135 | |||
136 | priv = mlc->priv; | ||
137 | |||
138 | write_lock_irqsave(&(mlc->lock), flags); | ||
139 | |||
140 | /* Try to down the semaphore */ | ||
141 | if (down_trylock(&(mlc->isem))) { | ||
142 | struct timeval tv; | ||
143 | if (priv->emtestmode) { | ||
144 | mlc->ipacket[0] = | ||
145 | HIL_ERR_INT | (mlc->opacket & | ||
146 | (HIL_PKT_CMD | | ||
147 | HIL_PKT_ADDR_MASK | | ||
148 | HIL_PKT_DATA_MASK)); | ||
149 | mlc->icount = 14; | ||
150 | /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */ | ||
151 | goto wasup; | ||
152 | } | ||
153 | do_gettimeofday(&tv); | ||
154 | tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec); | ||
155 | if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) { | ||
156 | /* printk("!%i %i", | ||
157 | tv.tv_usec - mlc->instart.tv_usec, | ||
158 | mlc->intimeout); | ||
159 | */ | ||
160 | rc = 1; | ||
161 | up(&(mlc->isem)); | ||
162 | } | ||
163 | goto done; | ||
164 | } | ||
165 | wasup: | ||
166 | up(&(mlc->isem)); | ||
167 | rc = 0; | ||
168 | goto done; | ||
169 | done: | ||
170 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
171 | return rc; | ||
172 | } | ||
173 | |||
174 | static int hp_sdc_mlc_cts (hil_mlc *mlc) { | ||
175 | struct hp_sdc_mlc_priv_s *priv; | ||
176 | unsigned long flags; | ||
177 | |||
178 | priv = mlc->priv; | ||
179 | |||
180 | write_lock_irqsave(&(mlc->lock), flags); | ||
181 | |||
182 | /* Try to down the semaphores -- they should be up. */ | ||
183 | if (down_trylock(&(mlc->isem))) { | ||
184 | BUG(); | ||
185 | goto busy; | ||
186 | } | ||
187 | if (down_trylock(&(mlc->osem))) { | ||
188 | BUG(); | ||
189 | up(&(mlc->isem)); | ||
190 | goto busy; | ||
191 | } | ||
192 | up(&(mlc->isem)); | ||
193 | up(&(mlc->osem)); | ||
194 | |||
195 | if (down_trylock(&(mlc->csem))) { | ||
196 | if (priv->trans.act.semaphore != &(mlc->csem)) goto poll; | ||
197 | goto busy; | ||
198 | } | ||
199 | if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done; | ||
200 | |||
201 | poll: | ||
202 | priv->trans.act.semaphore = &(mlc->csem); | ||
203 | priv->trans.actidx = 0; | ||
204 | priv->trans.idx = 1; | ||
205 | priv->trans.endidx = 5; | ||
206 | priv->tseq[0] = | ||
207 | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; | ||
208 | priv->tseq[1] = HP_SDC_CMD_READ_USE; | ||
209 | priv->tseq[2] = 1; | ||
210 | priv->tseq[3] = 0; | ||
211 | priv->tseq[4] = 0; | ||
212 | hp_sdc_enqueue_transaction(&(priv->trans)); | ||
213 | busy: | ||
214 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
215 | return 1; | ||
216 | done: | ||
217 | priv->trans.act.semaphore = &(mlc->osem); | ||
218 | up(&(mlc->csem)); | ||
219 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static void hp_sdc_mlc_out (hil_mlc *mlc) { | ||
224 | struct hp_sdc_mlc_priv_s *priv; | ||
225 | unsigned long flags; | ||
226 | |||
227 | priv = mlc->priv; | ||
228 | |||
229 | write_lock_irqsave(&(mlc->lock), flags); | ||
230 | |||
231 | /* Try to down the semaphore -- it should be up. */ | ||
232 | if (down_trylock(&(mlc->osem))) { | ||
233 | BUG(); | ||
234 | goto done; | ||
235 | } | ||
236 | |||
237 | if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control; | ||
238 | |||
239 | do_data: | ||
240 | if (priv->emtestmode) { | ||
241 | up(&(mlc->osem)); | ||
242 | goto done; | ||
243 | } | ||
244 | /* Shouldn't be sending commands when loop may be busy */ | ||
245 | if (down_trylock(&(mlc->csem))) { | ||
246 | BUG(); | ||
247 | goto done; | ||
248 | } | ||
249 | up(&(mlc->csem)); | ||
250 | |||
251 | priv->trans.actidx = 0; | ||
252 | priv->trans.idx = 1; | ||
253 | priv->trans.act.semaphore = &(mlc->osem); | ||
254 | priv->trans.endidx = 6; | ||
255 | priv->tseq[0] = | ||
256 | HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE; | ||
257 | priv->tseq[1] = 0x7; | ||
258 | priv->tseq[2] = | ||
259 | (mlc->opacket & | ||
260 | (HIL_PKT_ADDR_MASK | HIL_PKT_CMD)) | ||
261 | >> HIL_PKT_ADDR_SHIFT; | ||
262 | priv->tseq[3] = | ||
263 | (mlc->opacket & HIL_PKT_DATA_MASK) | ||
264 | >> HIL_PKT_DATA_SHIFT; | ||
265 | priv->tseq[4] = 0; /* No timeout */ | ||
266 | if (priv->tseq[3] == HIL_CMD_DHR) priv->tseq[4] = 1; | ||
267 | priv->tseq[5] = HP_SDC_CMD_DO_HIL; | ||
268 | goto enqueue; | ||
269 | |||
270 | do_control: | ||
271 | priv->emtestmode = mlc->opacket & HIL_CTRL_TEST; | ||
272 | if ((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE) { | ||
273 | BUG(); /* we cannot emulate this, it should not be used. */ | ||
274 | } | ||
275 | if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only; | ||
276 | if (mlc->opacket & HIL_CTRL_APE) { | ||
277 | BUG(); /* Should not send command/data after engaging APE */ | ||
278 | goto done; | ||
279 | } | ||
280 | /* Disengaging APE this way would not be valid either since | ||
281 | * the loop must be allowed to idle. | ||
282 | * | ||
283 | * So, it works out that we really never actually send control | ||
284 | * and data when using SDC, we just send the data. | ||
285 | */ | ||
286 | goto do_data; | ||
287 | |||
288 | control_only: | ||
289 | priv->trans.actidx = 0; | ||
290 | priv->trans.idx = 1; | ||
291 | priv->trans.act.semaphore = &(mlc->osem); | ||
292 | priv->trans.endidx = 4; | ||
293 | priv->tseq[0] = | ||
294 | HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; | ||
295 | priv->tseq[1] = HP_SDC_CMD_SET_LPC; | ||
296 | priv->tseq[2] = 1; | ||
297 | // priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; | ||
298 | priv->tseq[3] = 0; | ||
299 | if (mlc->opacket & HIL_CTRL_APE) { | ||
300 | priv->tseq[3] |= HP_SDC_LPC_APE_IPF; | ||
301 | down_trylock(&(mlc->csem)); | ||
302 | } | ||
303 | enqueue: | ||
304 | hp_sdc_enqueue_transaction(&(priv->trans)); | ||
305 | done: | ||
306 | write_unlock_irqrestore(&(mlc->lock), flags); | ||
307 | } | ||
308 | |||
309 | static int __init hp_sdc_mlc_init(void) | ||
310 | { | ||
311 | hil_mlc *mlc = &hp_sdc_mlc; | ||
312 | |||
313 | printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n"); | ||
314 | |||
315 | hp_sdc_mlc_priv.emtestmode = 0; | ||
316 | hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq; | ||
317 | hp_sdc_mlc_priv.trans.act.semaphore = &(mlc->osem); | ||
318 | hp_sdc_mlc_priv.got5x = 0; | ||
319 | |||
320 | mlc->cts = &hp_sdc_mlc_cts; | ||
321 | mlc->in = &hp_sdc_mlc_in; | ||
322 | mlc->out = &hp_sdc_mlc_out; | ||
323 | |||
324 | if (hil_mlc_register(mlc)) { | ||
325 | printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n"); | ||
326 | goto err0; | ||
327 | } | ||
328 | mlc->priv = &hp_sdc_mlc_priv; | ||
329 | |||
330 | if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) { | ||
331 | printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n"); | ||
332 | goto err1; | ||
333 | } | ||
334 | return 0; | ||
335 | err1: | ||
336 | if (hil_mlc_unregister(mlc)) { | ||
337 | printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" | ||
338 | "This is bad. Could cause an oops.\n"); | ||
339 | } | ||
340 | err0: | ||
341 | return -EBUSY; | ||
342 | } | ||
343 | |||
344 | static void __exit hp_sdc_mlc_exit(void) | ||
345 | { | ||
346 | hil_mlc *mlc = &hp_sdc_mlc; | ||
347 | if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) { | ||
348 | printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n" | ||
349 | "This is bad. Could cause an oops.\n"); | ||
350 | } | ||
351 | if (hil_mlc_unregister(mlc)) { | ||
352 | printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" | ||
353 | "This is bad. Could cause an oops.\n"); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | module_init(hp_sdc_mlc_init); | ||
358 | module_exit(hp_sdc_mlc_exit); | ||
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h new file mode 100644 index 000000000000..c9e633d21d90 --- /dev/null +++ b/drivers/input/serio/i8042-io.h | |||
@@ -0,0 +1,93 @@ | |||
1 | #ifndef _I8042_IO_H | ||
2 | #define _I8042_IO_H | ||
3 | |||
4 | /* | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Names. | ||
12 | */ | ||
13 | |||
14 | #define I8042_KBD_PHYS_DESC "isa0060/serio0" | ||
15 | #define I8042_AUX_PHYS_DESC "isa0060/serio1" | ||
16 | #define I8042_MUX_PHYS_DESC "isa0060/serio%d" | ||
17 | |||
18 | /* | ||
19 | * IRQs. | ||
20 | */ | ||
21 | |||
22 | #ifdef __alpha__ | ||
23 | # define I8042_KBD_IRQ 1 | ||
24 | # define I8042_AUX_IRQ (RTC_PORT(0) == 0x170 ? 9 : 12) /* Jensen is special */ | ||
25 | #elif defined(__arm__) | ||
26 | /* defined in include/asm-arm/arch-xxx/irqs.h */ | ||
27 | #include <asm/irq.h> | ||
28 | #elif defined(CONFIG_SUPERH64) | ||
29 | #include <asm/irq.h> | ||
30 | #else | ||
31 | # define I8042_KBD_IRQ 1 | ||
32 | # define I8042_AUX_IRQ 12 | ||
33 | #endif | ||
34 | |||
35 | |||
36 | /* | ||
37 | * Register numbers. | ||
38 | */ | ||
39 | |||
40 | #define I8042_COMMAND_REG 0x64 | ||
41 | #define I8042_STATUS_REG 0x64 | ||
42 | #define I8042_DATA_REG 0x60 | ||
43 | |||
44 | static inline int i8042_read_data(void) | ||
45 | { | ||
46 | return inb(I8042_DATA_REG); | ||
47 | } | ||
48 | |||
49 | static inline int i8042_read_status(void) | ||
50 | { | ||
51 | return inb(I8042_STATUS_REG); | ||
52 | } | ||
53 | |||
54 | static inline void i8042_write_data(int val) | ||
55 | { | ||
56 | outb(val, I8042_DATA_REG); | ||
57 | } | ||
58 | |||
59 | static inline void i8042_write_command(int val) | ||
60 | { | ||
61 | outb(val, I8042_COMMAND_REG); | ||
62 | } | ||
63 | |||
64 | static inline int i8042_platform_init(void) | ||
65 | { | ||
66 | /* | ||
67 | * On some platforms touching the i8042 data register region can do really | ||
68 | * bad things. Because of this the region is always reserved on such boxes. | ||
69 | */ | ||
70 | #if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64) | ||
71 | if (!request_region(I8042_DATA_REG, 16, "i8042")) | ||
72 | return -1; | ||
73 | #endif | ||
74 | |||
75 | i8042_reset = 1; | ||
76 | |||
77 | #if defined(CONFIG_PPC64) | ||
78 | if (check_legacy_ioport(I8042_DATA_REG)) | ||
79 | return -1; | ||
80 | if (!request_region(I8042_DATA_REG, 16, "i8042")) | ||
81 | return -1; | ||
82 | #endif | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static inline void i8042_platform_exit(void) | ||
87 | { | ||
88 | #if !defined(__sh__) && !defined(__alpha__) && !defined(CONFIG_PPC64) | ||
89 | release_region(I8042_DATA_REG, 16); | ||
90 | #endif | ||
91 | } | ||
92 | |||
93 | #endif /* _I8042_IO_H */ | ||
diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h new file mode 100644 index 000000000000..863b9c95fbb8 --- /dev/null +++ b/drivers/input/serio/i8042-ip22io.h | |||
@@ -0,0 +1,76 @@ | |||
1 | #ifndef _I8042_IP22_H | ||
2 | #define _I8042_IP22_H | ||
3 | |||
4 | #include <asm/sgi/ioc.h> | ||
5 | #include <asm/sgi/ip22.h> | ||
6 | |||
7 | /* | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * Names. | ||
15 | */ | ||
16 | |||
17 | #define I8042_KBD_PHYS_DESC "hpc3ps2/serio0" | ||
18 | #define I8042_AUX_PHYS_DESC "hpc3ps2/serio1" | ||
19 | #define I8042_MUX_PHYS_DESC "hpc3ps2/serio%d" | ||
20 | |||
21 | /* | ||
22 | * IRQs. | ||
23 | */ | ||
24 | |||
25 | #define I8042_KBD_IRQ SGI_KEYBD_IRQ | ||
26 | #define I8042_AUX_IRQ SGI_KEYBD_IRQ | ||
27 | |||
28 | /* | ||
29 | * Register numbers. | ||
30 | */ | ||
31 | |||
32 | #define I8042_COMMAND_REG ((unsigned long)&sgioc->kbdmouse.command) | ||
33 | #define I8042_STATUS_REG ((unsigned long)&sgioc->kbdmouse.command) | ||
34 | #define I8042_DATA_REG ((unsigned long)&sgioc->kbdmouse.data) | ||
35 | |||
36 | static inline int i8042_read_data(void) | ||
37 | { | ||
38 | return sgioc->kbdmouse.data; | ||
39 | } | ||
40 | |||
41 | static inline int i8042_read_status(void) | ||
42 | { | ||
43 | return sgioc->kbdmouse.command; | ||
44 | } | ||
45 | |||
46 | static inline void i8042_write_data(int val) | ||
47 | { | ||
48 | sgioc->kbdmouse.data = val; | ||
49 | } | ||
50 | |||
51 | static inline void i8042_write_command(int val) | ||
52 | { | ||
53 | sgioc->kbdmouse.command = val; | ||
54 | } | ||
55 | |||
56 | static inline int i8042_platform_init(void) | ||
57 | { | ||
58 | #if 0 | ||
59 | /* XXX sgi_kh is a virtual address */ | ||
60 | if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042")) | ||
61 | return 1; | ||
62 | #endif | ||
63 | |||
64 | i8042_reset = 1; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static inline void i8042_platform_exit(void) | ||
70 | { | ||
71 | #if 0 | ||
72 | release_mem_region(JAZZ_KEYBOARD_ADDRESS, sizeof(struct hpc_keyb)); | ||
73 | #endif | ||
74 | } | ||
75 | |||
76 | #endif /* _I8042_IP22_H */ | ||
diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h new file mode 100644 index 000000000000..5c20ab131488 --- /dev/null +++ b/drivers/input/serio/i8042-jazzio.h | |||
@@ -0,0 +1,69 @@ | |||
1 | #ifndef _I8042_JAZZ_H | ||
2 | #define _I8042_JAZZ_H | ||
3 | |||
4 | #include <asm/jazz.h> | ||
5 | |||
6 | /* | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * Names. | ||
14 | */ | ||
15 | |||
16 | #define I8042_KBD_PHYS_DESC "R4030/serio0" | ||
17 | #define I8042_AUX_PHYS_DESC "R4030/serio1" | ||
18 | #define I8042_MUX_PHYS_DESC "R4030/serio%d" | ||
19 | |||
20 | /* | ||
21 | * IRQs. | ||
22 | */ | ||
23 | |||
24 | #define I8042_KBD_IRQ JAZZ_KEYBOARD_IRQ | ||
25 | #define I8042_AUX_IRQ JAZZ_MOUSE_IRQ | ||
26 | |||
27 | #define I8042_COMMAND_REG ((unsigned long)&jazz_kh->command) | ||
28 | #define I8042_STATUS_REG ((unsigned long)&jazz_kh->command) | ||
29 | #define I8042_DATA_REG ((unsigned long)&jazz_kh->data) | ||
30 | |||
31 | static inline int i8042_read_data(void) | ||
32 | { | ||
33 | return jazz_kh->data; | ||
34 | } | ||
35 | |||
36 | static inline int i8042_read_status(void) | ||
37 | { | ||
38 | return jazz_kh->command; | ||
39 | } | ||
40 | |||
41 | static inline void i8042_write_data(int val) | ||
42 | { | ||
43 | jazz_kh->data = val; | ||
44 | } | ||
45 | |||
46 | static inline void i8042_write_command(int val) | ||
47 | { | ||
48 | jazz_kh->command = val; | ||
49 | } | ||
50 | |||
51 | static inline int i8042_platform_init(void) | ||
52 | { | ||
53 | #if 0 | ||
54 | /* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */ | ||
55 | if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042")) | ||
56 | return 1; | ||
57 | #endif | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static inline void i8042_platform_exit(void) | ||
63 | { | ||
64 | #if 0 | ||
65 | release_mem_region(JAZZ_KEYBOARD_ADDRESS, 2); | ||
66 | #endif | ||
67 | } | ||
68 | |||
69 | #endif /* _I8042_JAZZ_H */ | ||
diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h new file mode 100644 index 000000000000..2906e1b60c04 --- /dev/null +++ b/drivers/input/serio/i8042-ppcio.h | |||
@@ -0,0 +1,136 @@ | |||
1 | #ifndef _I8042_PPCIO_H | ||
2 | #define _I8042_PPCIO_H | ||
3 | |||
4 | /* | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #if defined(CONFIG_WALNUT) | ||
11 | |||
12 | #define I8042_KBD_IRQ 25 | ||
13 | #define I8042_AUX_IRQ 26 | ||
14 | |||
15 | #define I8042_KBD_PHYS_DESC "walnutps2/serio0" | ||
16 | #define I8042_AUX_PHYS_DESC "walnutps2/serio1" | ||
17 | #define I8042_MUX_PHYS_DESC "walnutps2/serio%d" | ||
18 | |||
19 | extern void *kb_cs; | ||
20 | extern void *kb_data; | ||
21 | |||
22 | #define I8042_COMMAND_REG (*(int *)kb_cs) | ||
23 | #define I8042_DATA_REG (*(int *)kb_data) | ||
24 | |||
25 | static inline int i8042_read_data(void) | ||
26 | { | ||
27 | return readb(kb_data); | ||
28 | } | ||
29 | |||
30 | static inline int i8042_read_status(void) | ||
31 | { | ||
32 | return readb(kb_cs); | ||
33 | } | ||
34 | |||
35 | static inline void i8042_write_data(int val) | ||
36 | { | ||
37 | writeb(val, kb_data); | ||
38 | } | ||
39 | |||
40 | static inline void i8042_write_command(int val) | ||
41 | { | ||
42 | writeb(val, kb_cs); | ||
43 | } | ||
44 | |||
45 | static inline int i8042_platform_init(void) | ||
46 | { | ||
47 | i8042_reset = 1; | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static inline void i8042_platform_exit(void) | ||
52 | { | ||
53 | } | ||
54 | |||
55 | #elif defined(CONFIG_SPRUCE) | ||
56 | |||
57 | #define I8042_KBD_IRQ 22 | ||
58 | #define I8042_AUX_IRQ 21 | ||
59 | |||
60 | #define I8042_KBD_PHYS_DESC "spruceps2/serio0" | ||
61 | #define I8042_AUX_PHYS_DESC "spruceps2/serio1" | ||
62 | #define I8042_MUX_PHYS_DESC "spruceps2/serio%d" | ||
63 | |||
64 | #define I8042_COMMAND_REG 0xff810000 | ||
65 | #define I8042_DATA_REG 0xff810001 | ||
66 | |||
67 | static inline int i8042_read_data(void) | ||
68 | { | ||
69 | unsigned long kbd_data; | ||
70 | |||
71 | __raw_writel(0x00000088, 0xff500008); | ||
72 | eieio(); | ||
73 | |||
74 | __raw_writel(0x03000000, 0xff50000c); | ||
75 | eieio(); | ||
76 | |||
77 | asm volatile("lis 7,0xff88 \n\ | ||
78 | lswi 6,7,0x8 \n\ | ||
79 | mr %0,6" | ||
80 | : "=r" (kbd_data) :: "6", "7"); | ||
81 | |||
82 | __raw_writel(0x00000000, 0xff50000c); | ||
83 | eieio(); | ||
84 | |||
85 | return (unsigned char)(kbd_data >> 24); | ||
86 | } | ||
87 | |||
88 | static inline int i8042_read_status(void) | ||
89 | { | ||
90 | unsigned long kbd_status; | ||
91 | |||
92 | __raw_writel(0x00000088, 0xff500008); | ||
93 | eieio(); | ||
94 | |||
95 | __raw_writel(0x03000000, 0xff50000c); | ||
96 | eieio(); | ||
97 | |||
98 | asm volatile("lis 7,0xff88 \n\ | ||
99 | ori 7,7,0x8 \n\ | ||
100 | lswi 6,7,0x8 \n\ | ||
101 | mr %0,6" | ||
102 | : "=r" (kbd_status) :: "6", "7"); | ||
103 | |||
104 | __raw_writel(0x00000000, 0xff50000c); | ||
105 | eieio(); | ||
106 | |||
107 | return (unsigned char)(kbd_status >> 24); | ||
108 | } | ||
109 | |||
110 | static inline void i8042_write_data(int val) | ||
111 | { | ||
112 | *((unsigned char *)0xff810000) = (char)val; | ||
113 | } | ||
114 | |||
115 | static inline void i8042_write_command(int val) | ||
116 | { | ||
117 | *((unsigned char *)0xff810001) = (char)val; | ||
118 | } | ||
119 | |||
120 | static inline int i8042_platform_init(void) | ||
121 | { | ||
122 | i8042_reset = 1; | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static inline void i8042_platform_exit(void) | ||
127 | { | ||
128 | } | ||
129 | |||
130 | #else | ||
131 | |||
132 | #include "i8042-io.h" | ||
133 | |||
134 | #endif | ||
135 | |||
136 | #endif /* _I8042_PPCIO_H */ | ||
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h new file mode 100644 index 000000000000..da2a19812485 --- /dev/null +++ b/drivers/input/serio/i8042-sparcio.h | |||
@@ -0,0 +1,116 @@ | |||
1 | #ifndef _I8042_SPARCIO_H | ||
2 | #define _I8042_SPARCIO_H | ||
3 | |||
4 | #include <linux/config.h> | ||
5 | #include <asm/io.h> | ||
6 | |||
7 | #ifdef CONFIG_PCI | ||
8 | #include <asm/oplib.h> | ||
9 | #include <asm/ebus.h> | ||
10 | #endif | ||
11 | |||
12 | static int i8042_kbd_irq = -1; | ||
13 | static int i8042_aux_irq = -1; | ||
14 | #define I8042_KBD_IRQ i8042_kbd_irq | ||
15 | #define I8042_AUX_IRQ i8042_aux_irq | ||
16 | |||
17 | #define I8042_KBD_PHYS_DESC "sparcps2/serio0" | ||
18 | #define I8042_AUX_PHYS_DESC "sparcps2/serio1" | ||
19 | #define I8042_MUX_PHYS_DESC "sparcps2/serio%d" | ||
20 | |||
21 | static void __iomem *kbd_iobase; | ||
22 | |||
23 | #define I8042_COMMAND_REG (kbd_iobase + 0x64UL) | ||
24 | #define I8042_DATA_REG (kbd_iobase + 0x60UL) | ||
25 | |||
26 | static inline int i8042_read_data(void) | ||
27 | { | ||
28 | return readb(kbd_iobase + 0x60UL); | ||
29 | } | ||
30 | |||
31 | static inline int i8042_read_status(void) | ||
32 | { | ||
33 | return readb(kbd_iobase + 0x64UL); | ||
34 | } | ||
35 | |||
36 | static inline void i8042_write_data(int val) | ||
37 | { | ||
38 | writeb(val, kbd_iobase + 0x60UL); | ||
39 | } | ||
40 | |||
41 | static inline void i8042_write_command(int val) | ||
42 | { | ||
43 | writeb(val, kbd_iobase + 0x64UL); | ||
44 | } | ||
45 | |||
46 | #define OBP_PS2KBD_NAME1 "kb_ps2" | ||
47 | #define OBP_PS2KBD_NAME2 "keyboard" | ||
48 | #define OBP_PS2MS_NAME1 "kdmouse" | ||
49 | #define OBP_PS2MS_NAME2 "mouse" | ||
50 | |||
51 | static int i8042_platform_init(void) | ||
52 | { | ||
53 | #ifndef CONFIG_PCI | ||
54 | return -1; | ||
55 | #else | ||
56 | char prop[128]; | ||
57 | int len; | ||
58 | |||
59 | len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); | ||
60 | if (len < 0) { | ||
61 | printk("i8042: Cannot get name property of root OBP node.\n"); | ||
62 | return -1; | ||
63 | } | ||
64 | if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { | ||
65 | /* Hardcoded values for MrCoffee. */ | ||
66 | i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; | ||
67 | kbd_iobase = ioremap(0x71300060, 8); | ||
68 | if (!kbd_iobase) | ||
69 | return -1; | ||
70 | } else { | ||
71 | struct linux_ebus *ebus; | ||
72 | struct linux_ebus_device *edev; | ||
73 | struct linux_ebus_child *child; | ||
74 | |||
75 | for_each_ebus(ebus) { | ||
76 | for_each_ebusdev(edev, ebus) { | ||
77 | if (!strcmp(edev->prom_name, "8042")) | ||
78 | goto edev_found; | ||
79 | } | ||
80 | } | ||
81 | return -1; | ||
82 | |||
83 | edev_found: | ||
84 | for_each_edevchild(edev, child) { | ||
85 | if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) || | ||
86 | !strcmp(child->prom_name, OBP_PS2KBD_NAME2)) { | ||
87 | i8042_kbd_irq = child->irqs[0]; | ||
88 | kbd_iobase = | ||
89 | ioremap(child->resource[0].start, 8); | ||
90 | } | ||
91 | if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) || | ||
92 | !strcmp(child->prom_name, OBP_PS2MS_NAME2)) | ||
93 | i8042_aux_irq = child->irqs[0]; | ||
94 | } | ||
95 | if (i8042_kbd_irq == -1 || | ||
96 | i8042_aux_irq == -1) { | ||
97 | printk("i8042: Error, 8042 device lacks both kbd and " | ||
98 | "mouse nodes.\n"); | ||
99 | return -1; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | i8042_reset = 1; | ||
104 | |||
105 | return 0; | ||
106 | #endif /* CONFIG_PCI */ | ||
107 | } | ||
108 | |||
109 | static inline void i8042_platform_exit(void) | ||
110 | { | ||
111 | #ifdef CONFIG_PCI | ||
112 | iounmap(kbd_iobase); | ||
113 | #endif | ||
114 | } | ||
115 | |||
116 | #endif /* _I8042_SPARCIO_H */ | ||
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h new file mode 100644 index 000000000000..f64867808fea --- /dev/null +++ b/drivers/input/serio/i8042-x86ia64io.h | |||
@@ -0,0 +1,333 @@ | |||
1 | #ifndef _I8042_X86IA64IO_H | ||
2 | #define _I8042_X86IA64IO_H | ||
3 | |||
4 | /* | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Names. | ||
12 | */ | ||
13 | |||
14 | #define I8042_KBD_PHYS_DESC "isa0060/serio0" | ||
15 | #define I8042_AUX_PHYS_DESC "isa0060/serio1" | ||
16 | #define I8042_MUX_PHYS_DESC "isa0060/serio%d" | ||
17 | |||
18 | /* | ||
19 | * IRQs. | ||
20 | */ | ||
21 | |||
22 | #if defined(__ia64__) | ||
23 | # define I8042_MAP_IRQ(x) isa_irq_to_vector((x)) | ||
24 | #else | ||
25 | # define I8042_MAP_IRQ(x) (x) | ||
26 | #endif | ||
27 | |||
28 | #define I8042_KBD_IRQ i8042_kbd_irq | ||
29 | #define I8042_AUX_IRQ i8042_aux_irq | ||
30 | |||
31 | static int i8042_kbd_irq; | ||
32 | static int i8042_aux_irq; | ||
33 | |||
34 | /* | ||
35 | * Register numbers. | ||
36 | */ | ||
37 | |||
38 | #define I8042_COMMAND_REG i8042_command_reg | ||
39 | #define I8042_STATUS_REG i8042_command_reg | ||
40 | #define I8042_DATA_REG i8042_data_reg | ||
41 | |||
42 | static int i8042_command_reg = 0x64; | ||
43 | static int i8042_data_reg = 0x60; | ||
44 | |||
45 | |||
46 | static inline int i8042_read_data(void) | ||
47 | { | ||
48 | return inb(I8042_DATA_REG); | ||
49 | } | ||
50 | |||
51 | static inline int i8042_read_status(void) | ||
52 | { | ||
53 | return inb(I8042_STATUS_REG); | ||
54 | } | ||
55 | |||
56 | static inline void i8042_write_data(int val) | ||
57 | { | ||
58 | outb(val, I8042_DATA_REG); | ||
59 | } | ||
60 | |||
61 | static inline void i8042_write_command(int val) | ||
62 | { | ||
63 | outb(val, I8042_COMMAND_REG); | ||
64 | } | ||
65 | |||
66 | #if defined(__i386__) | ||
67 | |||
68 | #include <linux/dmi.h> | ||
69 | |||
70 | static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { | ||
71 | { | ||
72 | .ident = "Compaq Proliant 8500", | ||
73 | .matches = { | ||
74 | DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), | ||
75 | DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), | ||
76 | DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), | ||
77 | }, | ||
78 | }, | ||
79 | { | ||
80 | .ident = "Compaq Proliant DL760", | ||
81 | .matches = { | ||
82 | DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), | ||
83 | DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), | ||
84 | DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), | ||
85 | }, | ||
86 | }, | ||
87 | { } | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * Some Fujitsu notebooks are ahving trouble with touhcpads if | ||
92 | * active multiplexing mode is activated. Luckily they don't have | ||
93 | * external PS/2 ports so we can safely disable it. | ||
94 | */ | ||
95 | static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { | ||
96 | { | ||
97 | .ident = "Fujitsu Lifebook P7010/P7010D", | ||
98 | .matches = { | ||
99 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
100 | DMI_MATCH(DMI_PRODUCT_NAME, "P7010"), | ||
101 | }, | ||
102 | }, | ||
103 | { | ||
104 | .ident = "Fujitsu Lifebook P5020D", | ||
105 | .matches = { | ||
106 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
107 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"), | ||
108 | }, | ||
109 | }, | ||
110 | { | ||
111 | .ident = "Fujitsu Lifebook S2000", | ||
112 | .matches = { | ||
113 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
114 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), | ||
115 | }, | ||
116 | }, | ||
117 | { | ||
118 | .ident = "Fujitsu T70H", | ||
119 | .matches = { | ||
120 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
121 | DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), | ||
122 | }, | ||
123 | }, | ||
124 | { } | ||
125 | }; | ||
126 | |||
127 | |||
128 | |||
129 | #endif | ||
130 | |||
131 | |||
132 | #ifdef CONFIG_PNP | ||
133 | #include <linux/pnp.h> | ||
134 | |||
135 | static int i8042_pnp_kbd_registered; | ||
136 | static int i8042_pnp_aux_registered; | ||
137 | |||
138 | static int i8042_pnp_command_reg; | ||
139 | static int i8042_pnp_data_reg; | ||
140 | static int i8042_pnp_kbd_irq; | ||
141 | static int i8042_pnp_aux_irq; | ||
142 | |||
143 | static char i8042_pnp_kbd_name[32]; | ||
144 | static char i8042_pnp_aux_name[32]; | ||
145 | |||
146 | static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *did) | ||
147 | { | ||
148 | if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1) | ||
149 | i8042_pnp_data_reg = pnp_port_start(dev,0); | ||
150 | |||
151 | if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1) | ||
152 | i8042_pnp_command_reg = pnp_port_start(dev, 1); | ||
153 | |||
154 | if (pnp_irq_valid(dev,0)) | ||
155 | i8042_pnp_kbd_irq = pnp_irq(dev, 0); | ||
156 | |||
157 | strncpy(i8042_pnp_kbd_name, did->id, sizeof(i8042_pnp_kbd_name)); | ||
158 | if (strlen(pnp_dev_name(dev))) { | ||
159 | strncat(i8042_pnp_kbd_name, ":", sizeof(i8042_pnp_kbd_name)); | ||
160 | strncat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name)); | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *did) | ||
167 | { | ||
168 | if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1) | ||
169 | i8042_pnp_data_reg = pnp_port_start(dev,0); | ||
170 | |||
171 | if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1) | ||
172 | i8042_pnp_command_reg = pnp_port_start(dev, 1); | ||
173 | |||
174 | if (pnp_irq_valid(dev, 0)) | ||
175 | i8042_pnp_aux_irq = pnp_irq(dev, 0); | ||
176 | |||
177 | strncpy(i8042_pnp_aux_name, did->id, sizeof(i8042_pnp_aux_name)); | ||
178 | if (strlen(pnp_dev_name(dev))) { | ||
179 | strncat(i8042_pnp_aux_name, ":", sizeof(i8042_pnp_aux_name)); | ||
180 | strncat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name)); | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static struct pnp_device_id pnp_kbd_devids[] = { | ||
187 | { .id = "PNP0303", .driver_data = 0 }, | ||
188 | { .id = "PNP030b", .driver_data = 0 }, | ||
189 | { .id = "", }, | ||
190 | }; | ||
191 | |||
192 | static struct pnp_driver i8042_pnp_kbd_driver = { | ||
193 | .name = "i8042 kbd", | ||
194 | .id_table = pnp_kbd_devids, | ||
195 | .probe = i8042_pnp_kbd_probe, | ||
196 | }; | ||
197 | |||
198 | static struct pnp_device_id pnp_aux_devids[] = { | ||
199 | { .id = "PNP0f03", .driver_data = 0 }, | ||
200 | { .id = "PNP0f0b", .driver_data = 0 }, | ||
201 | { .id = "PNP0f0e", .driver_data = 0 }, | ||
202 | { .id = "PNP0f12", .driver_data = 0 }, | ||
203 | { .id = "PNP0f13", .driver_data = 0 }, | ||
204 | { .id = "PNP0f19", .driver_data = 0 }, | ||
205 | { .id = "PNP0f1c", .driver_data = 0 }, | ||
206 | { .id = "SYN0801", .driver_data = 0 }, | ||
207 | { .id = "", }, | ||
208 | }; | ||
209 | |||
210 | static struct pnp_driver i8042_pnp_aux_driver = { | ||
211 | .name = "i8042 aux", | ||
212 | .id_table = pnp_aux_devids, | ||
213 | .probe = i8042_pnp_aux_probe, | ||
214 | }; | ||
215 | |||
216 | static void i8042_pnp_exit(void) | ||
217 | { | ||
218 | if (i8042_pnp_kbd_registered) | ||
219 | pnp_unregister_driver(&i8042_pnp_kbd_driver); | ||
220 | |||
221 | if (i8042_pnp_aux_registered) | ||
222 | pnp_unregister_driver(&i8042_pnp_aux_driver); | ||
223 | } | ||
224 | |||
225 | static int i8042_pnp_init(void) | ||
226 | { | ||
227 | int result_kbd, result_aux; | ||
228 | |||
229 | if (i8042_nopnp) { | ||
230 | printk("i8042: PNP detection disabled\n"); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0) | ||
235 | i8042_pnp_kbd_registered = 1; | ||
236 | if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0) | ||
237 | i8042_pnp_aux_registered = 1; | ||
238 | |||
239 | if (result_kbd <= 0 && result_aux <= 0) { | ||
240 | i8042_pnp_exit(); | ||
241 | #if defined(__ia64__) | ||
242 | return -ENODEV; | ||
243 | #else | ||
244 | printk(KERN_WARNING "PNP: No PS/2 controller found. Probing ports directly.\n"); | ||
245 | return 0; | ||
246 | #endif | ||
247 | } | ||
248 | |||
249 | if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) && | ||
250 | i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) { | ||
251 | printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n", | ||
252 | i8042_pnp_data_reg, i8042_data_reg); | ||
253 | i8042_pnp_data_reg = i8042_data_reg; | ||
254 | } | ||
255 | |||
256 | if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) && | ||
257 | i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) { | ||
258 | printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n", | ||
259 | i8042_pnp_command_reg, i8042_command_reg); | ||
260 | i8042_pnp_command_reg = i8042_command_reg; | ||
261 | } | ||
262 | |||
263 | if (!i8042_pnp_kbd_irq) { | ||
264 | printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %#x\n", i8042_kbd_irq); | ||
265 | i8042_pnp_kbd_irq = i8042_kbd_irq; | ||
266 | } | ||
267 | |||
268 | if (result_aux > 0 && !i8042_pnp_aux_irq) { | ||
269 | printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq); | ||
270 | i8042_pnp_aux_irq = i8042_aux_irq; | ||
271 | } | ||
272 | |||
273 | #if defined(__ia64__) | ||
274 | if (result_aux <= 0) | ||
275 | i8042_noaux = 1; | ||
276 | #endif | ||
277 | |||
278 | i8042_data_reg = i8042_pnp_data_reg; | ||
279 | i8042_command_reg = i8042_pnp_command_reg; | ||
280 | i8042_kbd_irq = i8042_pnp_kbd_irq; | ||
281 | i8042_aux_irq = i8042_pnp_aux_irq; | ||
282 | |||
283 | printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %d%s%d\n", | ||
284 | i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", i8042_pnp_aux_name, | ||
285 | i8042_data_reg, i8042_command_reg, i8042_kbd_irq, | ||
286 | (result_aux > 0) ? "," : "", i8042_aux_irq); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | #endif | ||
292 | |||
293 | static inline int i8042_platform_init(void) | ||
294 | { | ||
295 | /* | ||
296 | * On ix86 platforms touching the i8042 data register region can do really | ||
297 | * bad things. Because of this the region is always reserved on ix86 boxes. | ||
298 | * | ||
299 | * if (!request_region(I8042_DATA_REG, 16, "i8042")) | ||
300 | * return -1; | ||
301 | */ | ||
302 | |||
303 | i8042_kbd_irq = I8042_MAP_IRQ(1); | ||
304 | i8042_aux_irq = I8042_MAP_IRQ(12); | ||
305 | |||
306 | #ifdef CONFIG_PNP | ||
307 | if (i8042_pnp_init()) | ||
308 | return -1; | ||
309 | #endif | ||
310 | |||
311 | #if defined(__ia64__) | ||
312 | i8042_reset = 1; | ||
313 | #endif | ||
314 | |||
315 | #if defined(__i386__) | ||
316 | if (dmi_check_system(i8042_dmi_noloop_table)) | ||
317 | i8042_noloop = 1; | ||
318 | |||
319 | if (dmi_check_system(i8042_dmi_nomux_table)) | ||
320 | i8042_nomux = 1; | ||
321 | #endif | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static inline void i8042_platform_exit(void) | ||
327 | { | ||
328 | #ifdef CONFIG_PNP | ||
329 | i8042_pnp_exit(); | ||
330 | #endif | ||
331 | } | ||
332 | |||
333 | #endif /* _I8042_X86IA64IO_H */ | ||
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c new file mode 100644 index 000000000000..8e63e464d361 --- /dev/null +++ b/drivers/input/serio/i8042.c | |||
@@ -0,0 +1,1116 @@ | |||
1 | /* | ||
2 | * i8042 keyboard and mouse controller driver for Linux | ||
3 | * | ||
4 | * Copyright (c) 1999-2004 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/serio.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/rcupdate.h> | ||
23 | |||
24 | #include <asm/io.h> | ||
25 | |||
26 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | ||
27 | MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | static unsigned int i8042_noaux; | ||
31 | module_param_named(noaux, i8042_noaux, bool, 0); | ||
32 | MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); | ||
33 | |||
34 | static unsigned int i8042_nomux; | ||
35 | module_param_named(nomux, i8042_nomux, bool, 0); | ||
36 | MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present."); | ||
37 | |||
38 | static unsigned int i8042_unlock; | ||
39 | module_param_named(unlock, i8042_unlock, bool, 0); | ||
40 | MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); | ||
41 | |||
42 | static unsigned int i8042_reset; | ||
43 | module_param_named(reset, i8042_reset, bool, 0); | ||
44 | MODULE_PARM_DESC(reset, "Reset controller during init and cleanup."); | ||
45 | |||
46 | static unsigned int i8042_direct; | ||
47 | module_param_named(direct, i8042_direct, bool, 0); | ||
48 | MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode."); | ||
49 | |||
50 | static unsigned int i8042_dumbkbd; | ||
51 | module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); | ||
52 | MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); | ||
53 | |||
54 | static unsigned int i8042_noloop; | ||
55 | module_param_named(noloop, i8042_noloop, bool, 0); | ||
56 | MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); | ||
57 | |||
58 | static unsigned int i8042_blink_frequency = 500; | ||
59 | module_param_named(panicblink, i8042_blink_frequency, uint, 0600); | ||
60 | MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); | ||
61 | |||
62 | #ifdef CONFIG_PNP | ||
63 | static int i8042_nopnp; | ||
64 | module_param_named(nopnp, i8042_nopnp, bool, 0); | ||
65 | MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); | ||
66 | #endif | ||
67 | |||
68 | #define DEBUG | ||
69 | #ifdef DEBUG | ||
70 | static int i8042_debug; | ||
71 | module_param_named(debug, i8042_debug, bool, 0600); | ||
72 | MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); | ||
73 | #endif | ||
74 | |||
75 | __obsolete_setup("i8042_noaux"); | ||
76 | __obsolete_setup("i8042_nomux"); | ||
77 | __obsolete_setup("i8042_unlock"); | ||
78 | __obsolete_setup("i8042_reset"); | ||
79 | __obsolete_setup("i8042_direct"); | ||
80 | __obsolete_setup("i8042_dumbkbd"); | ||
81 | |||
82 | #include "i8042.h" | ||
83 | |||
84 | static DEFINE_SPINLOCK(i8042_lock); | ||
85 | |||
86 | struct i8042_port { | ||
87 | struct serio *serio; | ||
88 | int irq; | ||
89 | unsigned char disable; | ||
90 | unsigned char irqen; | ||
91 | unsigned char exists; | ||
92 | signed char mux; | ||
93 | char name[8]; | ||
94 | }; | ||
95 | |||
96 | #define I8042_KBD_PORT_NO 0 | ||
97 | #define I8042_AUX_PORT_NO 1 | ||
98 | #define I8042_MUX_PORT_NO 2 | ||
99 | #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) | ||
100 | static struct i8042_port i8042_ports[I8042_NUM_PORTS] = { | ||
101 | { | ||
102 | .disable = I8042_CTR_KBDDIS, | ||
103 | .irqen = I8042_CTR_KBDINT, | ||
104 | .mux = -1, | ||
105 | .name = "KBD", | ||
106 | }, | ||
107 | { | ||
108 | .disable = I8042_CTR_AUXDIS, | ||
109 | .irqen = I8042_CTR_AUXINT, | ||
110 | .mux = -1, | ||
111 | .name = "AUX", | ||
112 | } | ||
113 | }; | ||
114 | |||
115 | static unsigned char i8042_initial_ctr; | ||
116 | static unsigned char i8042_ctr; | ||
117 | static unsigned char i8042_mux_open; | ||
118 | static unsigned char i8042_mux_present; | ||
119 | static struct timer_list i8042_timer; | ||
120 | static struct platform_device *i8042_platform_device; | ||
121 | |||
122 | |||
123 | /* | ||
124 | * Shared IRQ's require a device pointer, but this driver doesn't support | ||
125 | * multiple devices | ||
126 | */ | ||
127 | #define i8042_request_irq_cookie (&i8042_timer) | ||
128 | |||
129 | static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); | ||
130 | |||
131 | /* | ||
132 | * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to | ||
133 | * be ready for reading values from it / writing values to it. | ||
134 | * Called always with i8042_lock held. | ||
135 | */ | ||
136 | |||
137 | static int i8042_wait_read(void) | ||
138 | { | ||
139 | int i = 0; | ||
140 | while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { | ||
141 | udelay(50); | ||
142 | i++; | ||
143 | } | ||
144 | return -(i == I8042_CTL_TIMEOUT); | ||
145 | } | ||
146 | |||
147 | static int i8042_wait_write(void) | ||
148 | { | ||
149 | int i = 0; | ||
150 | while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { | ||
151 | udelay(50); | ||
152 | i++; | ||
153 | } | ||
154 | return -(i == I8042_CTL_TIMEOUT); | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * i8042_flush() flushes all data that may be in the keyboard and mouse buffers | ||
159 | * of the i8042 down the toilet. | ||
160 | */ | ||
161 | |||
162 | static int i8042_flush(void) | ||
163 | { | ||
164 | unsigned long flags; | ||
165 | unsigned char data, str; | ||
166 | int i = 0; | ||
167 | |||
168 | spin_lock_irqsave(&i8042_lock, flags); | ||
169 | |||
170 | while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) { | ||
171 | udelay(50); | ||
172 | data = i8042_read_data(); | ||
173 | i++; | ||
174 | dbg("%02x <- i8042 (flush, %s)", data, | ||
175 | str & I8042_STR_AUXDATA ? "aux" : "kbd"); | ||
176 | } | ||
177 | |||
178 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
179 | |||
180 | return i; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * i8042_command() executes a command on the i8042. It also sends the input | ||
185 | * parameter(s) of the commands to it, and receives the output value(s). The | ||
186 | * parameters are to be stored in the param array, and the output is placed | ||
187 | * into the same array. The number of the parameters and output values is | ||
188 | * encoded in bits 8-11 of the command number. | ||
189 | */ | ||
190 | |||
191 | static int i8042_command(unsigned char *param, int command) | ||
192 | { | ||
193 | unsigned long flags; | ||
194 | int retval = 0, i = 0; | ||
195 | |||
196 | if (i8042_noloop && command == I8042_CMD_AUX_LOOP) | ||
197 | return -1; | ||
198 | |||
199 | spin_lock_irqsave(&i8042_lock, flags); | ||
200 | |||
201 | retval = i8042_wait_write(); | ||
202 | if (!retval) { | ||
203 | dbg("%02x -> i8042 (command)", command & 0xff); | ||
204 | i8042_write_command(command & 0xff); | ||
205 | } | ||
206 | |||
207 | if (!retval) | ||
208 | for (i = 0; i < ((command >> 12) & 0xf); i++) { | ||
209 | if ((retval = i8042_wait_write())) break; | ||
210 | dbg("%02x -> i8042 (parameter)", param[i]); | ||
211 | i8042_write_data(param[i]); | ||
212 | } | ||
213 | |||
214 | if (!retval) | ||
215 | for (i = 0; i < ((command >> 8) & 0xf); i++) { | ||
216 | if ((retval = i8042_wait_read())) break; | ||
217 | if (i8042_read_status() & I8042_STR_AUXDATA) | ||
218 | param[i] = ~i8042_read_data(); | ||
219 | else | ||
220 | param[i] = i8042_read_data(); | ||
221 | dbg("%02x <- i8042 (return)", param[i]); | ||
222 | } | ||
223 | |||
224 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
225 | |||
226 | if (retval) | ||
227 | dbg(" -- i8042 (timeout)"); | ||
228 | |||
229 | return retval; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * i8042_kbd_write() sends a byte out through the keyboard interface. | ||
234 | */ | ||
235 | |||
236 | static int i8042_kbd_write(struct serio *port, unsigned char c) | ||
237 | { | ||
238 | unsigned long flags; | ||
239 | int retval = 0; | ||
240 | |||
241 | spin_lock_irqsave(&i8042_lock, flags); | ||
242 | |||
243 | if(!(retval = i8042_wait_write())) { | ||
244 | dbg("%02x -> i8042 (kbd-data)", c); | ||
245 | i8042_write_data(c); | ||
246 | } | ||
247 | |||
248 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
249 | |||
250 | return retval; | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * i8042_aux_write() sends a byte out through the aux interface. | ||
255 | */ | ||
256 | |||
257 | static int i8042_aux_write(struct serio *serio, unsigned char c) | ||
258 | { | ||
259 | struct i8042_port *port = serio->port_data; | ||
260 | int retval; | ||
261 | |||
262 | /* | ||
263 | * Send the byte out. | ||
264 | */ | ||
265 | |||
266 | if (port->mux == -1) | ||
267 | retval = i8042_command(&c, I8042_CMD_AUX_SEND); | ||
268 | else | ||
269 | retval = i8042_command(&c, I8042_CMD_MUX_SEND + port->mux); | ||
270 | |||
271 | /* | ||
272 | * Make sure the interrupt happens and the character is received even | ||
273 | * in the case the IRQ isn't wired, so that we can receive further | ||
274 | * characters later. | ||
275 | */ | ||
276 | |||
277 | i8042_interrupt(0, NULL, NULL); | ||
278 | return retval; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * i8042_activate_port() enables port on a chip. | ||
283 | */ | ||
284 | |||
285 | static int i8042_activate_port(struct i8042_port *port) | ||
286 | { | ||
287 | if (!port->serio) | ||
288 | return -1; | ||
289 | |||
290 | i8042_flush(); | ||
291 | |||
292 | /* | ||
293 | * Enable port again here because it is disabled if we are | ||
294 | * resuming (normally it is enabled already). | ||
295 | */ | ||
296 | i8042_ctr &= ~port->disable; | ||
297 | |||
298 | i8042_ctr |= port->irqen; | ||
299 | |||
300 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
301 | i8042_ctr &= ~port->irqen; | ||
302 | return -1; | ||
303 | } | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | |||
309 | /* | ||
310 | * i8042_open() is called when a port is open by the higher layer. | ||
311 | * It allocates the interrupt and calls i8042_enable_port. | ||
312 | */ | ||
313 | |||
314 | static int i8042_open(struct serio *serio) | ||
315 | { | ||
316 | struct i8042_port *port = serio->port_data; | ||
317 | |||
318 | if (port->mux != -1) | ||
319 | if (i8042_mux_open++) | ||
320 | return 0; | ||
321 | |||
322 | if (request_irq(port->irq, i8042_interrupt, | ||
323 | SA_SHIRQ, "i8042", i8042_request_irq_cookie)) { | ||
324 | printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name); | ||
325 | goto irq_fail; | ||
326 | } | ||
327 | |||
328 | if (i8042_activate_port(port)) { | ||
329 | printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", port->name); | ||
330 | goto activate_fail; | ||
331 | } | ||
332 | |||
333 | i8042_interrupt(0, NULL, NULL); | ||
334 | |||
335 | return 0; | ||
336 | |||
337 | activate_fail: | ||
338 | free_irq(port->irq, i8042_request_irq_cookie); | ||
339 | |||
340 | irq_fail: | ||
341 | serio_unregister_port_delayed(serio); | ||
342 | |||
343 | return -1; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * i8042_close() frees the interrupt, so that it can possibly be used | ||
348 | * by another driver. We never know - if the user doesn't have a mouse, | ||
349 | * the BIOS could have used the AUX interrupt for PCI. | ||
350 | */ | ||
351 | |||
352 | static void i8042_close(struct serio *serio) | ||
353 | { | ||
354 | struct i8042_port *port = serio->port_data; | ||
355 | |||
356 | if (port->mux != -1) | ||
357 | if (--i8042_mux_open) | ||
358 | return; | ||
359 | |||
360 | i8042_ctr &= ~port->irqen; | ||
361 | |||
362 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
363 | printk(KERN_WARNING "i8042.c: Can't write CTR while closing %s.\n", port->name); | ||
364 | /* | ||
365 | * We still want to continue and free IRQ so if more data keeps coming in | ||
366 | * kernel will just ignore the irq. | ||
367 | */ | ||
368 | } | ||
369 | |||
370 | free_irq(port->irq, i8042_request_irq_cookie); | ||
371 | |||
372 | i8042_flush(); | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * i8042_start() is called by serio core when port is about to finish | ||
377 | * registering. It will mark port as existing so i8042_interrupt can | ||
378 | * start sending data through it. | ||
379 | */ | ||
380 | static int i8042_start(struct serio *serio) | ||
381 | { | ||
382 | struct i8042_port *port = serio->port_data; | ||
383 | |||
384 | port->exists = 1; | ||
385 | mb(); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | * i8042_stop() marks serio port as non-existing so i8042_interrupt | ||
391 | * will not try to send data to the port that is about to go away. | ||
392 | * The function is called by serio core as part of unregister procedure. | ||
393 | */ | ||
394 | static void i8042_stop(struct serio *serio) | ||
395 | { | ||
396 | struct i8042_port *port = serio->port_data; | ||
397 | |||
398 | port->exists = 0; | ||
399 | synchronize_kernel(); | ||
400 | port->serio = NULL; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * i8042_interrupt() is the most important function in this driver - | ||
405 | * it handles the interrupts from the i8042, and sends incoming bytes | ||
406 | * to the upper layers. | ||
407 | */ | ||
408 | |||
409 | static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
410 | { | ||
411 | struct i8042_port *port; | ||
412 | unsigned long flags; | ||
413 | unsigned char str, data; | ||
414 | unsigned int dfl; | ||
415 | unsigned int port_no; | ||
416 | int ret; | ||
417 | |||
418 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | ||
419 | |||
420 | spin_lock_irqsave(&i8042_lock, flags); | ||
421 | str = i8042_read_status(); | ||
422 | if (unlikely(~str & I8042_STR_OBF)) { | ||
423 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
424 | if (irq) dbg("Interrupt %d, without any data", irq); | ||
425 | ret = 0; | ||
426 | goto out; | ||
427 | } | ||
428 | data = i8042_read_data(); | ||
429 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
430 | |||
431 | if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { | ||
432 | static unsigned long last_transmit; | ||
433 | static unsigned char last_str; | ||
434 | |||
435 | dfl = 0; | ||
436 | if (str & I8042_STR_MUXERR) { | ||
437 | dbg("MUX error, status is %02x, data is %02x", str, data); | ||
438 | switch (data) { | ||
439 | default: | ||
440 | /* | ||
441 | * When MUXERR condition is signalled the data register can only contain | ||
442 | * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately | ||
443 | * it is not always the case. Some KBC just get confused which port the | ||
444 | * data came from and signal error leaving the data intact. They _do not_ | ||
445 | * revert to legacy mode (actually I've never seen KBC reverting to legacy | ||
446 | * mode yet, when we see one we'll add proper handling). | ||
447 | * Anyway, we will assume that the data came from the same serio last byte | ||
448 | * was transmitted (if transmission happened not too long ago). | ||
449 | */ | ||
450 | if (time_before(jiffies, last_transmit + HZ/10)) { | ||
451 | str = last_str; | ||
452 | break; | ||
453 | } | ||
454 | /* fall through - report timeout */ | ||
455 | case 0xfd: | ||
456 | case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; | ||
457 | case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); | ||
462 | last_str = str; | ||
463 | last_transmit = jiffies; | ||
464 | } else { | ||
465 | |||
466 | dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | | ||
467 | ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); | ||
468 | |||
469 | port_no = (str & I8042_STR_AUXDATA) ? | ||
470 | I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; | ||
471 | } | ||
472 | |||
473 | port = &i8042_ports[port_no]; | ||
474 | |||
475 | dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", | ||
476 | data, port->name, irq, | ||
477 | dfl & SERIO_PARITY ? ", bad parity" : "", | ||
478 | dfl & SERIO_TIMEOUT ? ", timeout" : ""); | ||
479 | |||
480 | if (likely(port->exists)) | ||
481 | serio_interrupt(port->serio, data, dfl, regs); | ||
482 | |||
483 | ret = 1; | ||
484 | out: | ||
485 | return IRQ_RETVAL(ret); | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * i8042_set_mux_mode checks whether the controller has an active | ||
490 | * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode. | ||
491 | */ | ||
492 | |||
493 | static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) | ||
494 | { | ||
495 | |||
496 | unsigned char param; | ||
497 | /* | ||
498 | * Get rid of bytes in the queue. | ||
499 | */ | ||
500 | |||
501 | i8042_flush(); | ||
502 | |||
503 | /* | ||
504 | * Internal loopback test - send three bytes, they should come back from the | ||
505 | * mouse interface, the last should be version. Note that we negate mouseport | ||
506 | * command responses for the i8042_check_aux() routine. | ||
507 | */ | ||
508 | |||
509 | param = 0xf0; | ||
510 | if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0x0f) | ||
511 | return -1; | ||
512 | param = mode ? 0x56 : 0xf6; | ||
513 | if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0xa9 : 0x09)) | ||
514 | return -1; | ||
515 | param = mode ? 0xa4 : 0xa5; | ||
516 | if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0x5b : 0x5a)) | ||
517 | return -1; | ||
518 | |||
519 | if (mux_version) | ||
520 | *mux_version = ~param; | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | |||
526 | /* | ||
527 | * i8042_enable_mux_ports enables 4 individual AUX ports after | ||
528 | * the controller has been switched into Multiplexed mode | ||
529 | */ | ||
530 | |||
531 | static int i8042_enable_mux_ports(void) | ||
532 | { | ||
533 | unsigned char param; | ||
534 | int i; | ||
535 | /* | ||
536 | * Disable all muxed ports by disabling AUX. | ||
537 | */ | ||
538 | |||
539 | i8042_ctr |= I8042_CTR_AUXDIS; | ||
540 | i8042_ctr &= ~I8042_CTR_AUXINT; | ||
541 | |||
542 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
543 | printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); | ||
544 | return -1; | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Enable all muxed ports. | ||
549 | */ | ||
550 | |||
551 | for (i = 0; i < 4; i++) { | ||
552 | i8042_command(¶m, I8042_CMD_MUX_PFX + i); | ||
553 | i8042_command(¶m, I8042_CMD_AUX_ENABLE); | ||
554 | } | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | |||
560 | /* | ||
561 | * i8042_check_mux() checks whether the controller supports the PS/2 Active | ||
562 | * Multiplexing specification by Synaptics, Phoenix, Insyde and | ||
563 | * LCS/Telegraphics. | ||
564 | */ | ||
565 | |||
566 | static int __init i8042_check_mux(void) | ||
567 | { | ||
568 | unsigned char mux_version; | ||
569 | |||
570 | if (i8042_set_mux_mode(1, &mux_version)) | ||
571 | return -1; | ||
572 | |||
573 | /* Workaround for interference with USB Legacy emulation */ | ||
574 | /* that causes a v10.12 MUX to be found. */ | ||
575 | if (mux_version == 0xAC) | ||
576 | return -1; | ||
577 | |||
578 | printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", | ||
579 | (mux_version >> 4) & 0xf, mux_version & 0xf); | ||
580 | |||
581 | if (i8042_enable_mux_ports()) | ||
582 | return -1; | ||
583 | |||
584 | i8042_mux_present = 1; | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | |||
589 | /* | ||
590 | * i8042_check_aux() applies as much paranoia as it can at detecting | ||
591 | * the presence of an AUX interface. | ||
592 | */ | ||
593 | |||
594 | static int __init i8042_check_aux(void) | ||
595 | { | ||
596 | unsigned char param; | ||
597 | static int i8042_check_aux_cookie; | ||
598 | |||
599 | /* | ||
600 | * Check if AUX irq is available. If it isn't, then there is no point | ||
601 | * in trying to detect AUX presence. | ||
602 | */ | ||
603 | |||
604 | if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt, | ||
605 | SA_SHIRQ, "i8042", &i8042_check_aux_cookie)) | ||
606 | return -1; | ||
607 | free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie); | ||
608 | |||
609 | /* | ||
610 | * Get rid of bytes in the queue. | ||
611 | */ | ||
612 | |||
613 | i8042_flush(); | ||
614 | |||
615 | /* | ||
616 | * Internal loopback test - filters out AT-type i8042's. Unfortunately | ||
617 | * SiS screwed up and their 5597 doesn't support the LOOP command even | ||
618 | * though it has an AUX port. | ||
619 | */ | ||
620 | |||
621 | param = 0x5a; | ||
622 | if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa5) { | ||
623 | |||
624 | /* | ||
625 | * External connection test - filters out AT-soldered PS/2 i8042's | ||
626 | * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error | ||
627 | * 0xfa - no error on some notebooks which ignore the spec | ||
628 | * Because it's common for chipsets to return error on perfectly functioning | ||
629 | * AUX ports, we test for this only when the LOOP command failed. | ||
630 | */ | ||
631 | |||
632 | if (i8042_command(¶m, I8042_CMD_AUX_TEST) | ||
633 | || (param && param != 0xfa && param != 0xff)) | ||
634 | return -1; | ||
635 | } | ||
636 | |||
637 | /* | ||
638 | * Bit assignment test - filters out PS/2 i8042's in AT mode | ||
639 | */ | ||
640 | |||
641 | if (i8042_command(¶m, I8042_CMD_AUX_DISABLE)) | ||
642 | return -1; | ||
643 | if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) { | ||
644 | printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); | ||
645 | printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); | ||
646 | } | ||
647 | |||
648 | if (i8042_command(¶m, I8042_CMD_AUX_ENABLE)) | ||
649 | return -1; | ||
650 | if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS)) | ||
651 | return -1; | ||
652 | |||
653 | /* | ||
654 | * Disable the interface. | ||
655 | */ | ||
656 | |||
657 | i8042_ctr |= I8042_CTR_AUXDIS; | ||
658 | i8042_ctr &= ~I8042_CTR_AUXINT; | ||
659 | |||
660 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) | ||
661 | return -1; | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | |||
667 | /* | ||
668 | * i8042_port_register() marks the device as existing, | ||
669 | * registers it, and reports to the user. | ||
670 | */ | ||
671 | |||
672 | static int __init i8042_port_register(struct i8042_port *port) | ||
673 | { | ||
674 | i8042_ctr &= ~port->disable; | ||
675 | |||
676 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
677 | printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n"); | ||
678 | kfree(port->serio); | ||
679 | port->serio = NULL; | ||
680 | i8042_ctr |= port->disable; | ||
681 | return -1; | ||
682 | } | ||
683 | |||
684 | printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", | ||
685 | port->name, | ||
686 | (unsigned long) I8042_DATA_REG, | ||
687 | (unsigned long) I8042_COMMAND_REG, | ||
688 | port->irq); | ||
689 | |||
690 | serio_register_port(port->serio); | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | |||
696 | static void i8042_timer_func(unsigned long data) | ||
697 | { | ||
698 | i8042_interrupt(0, NULL, NULL); | ||
699 | } | ||
700 | |||
701 | |||
702 | /* | ||
703 | * i8042_controller init initializes the i8042 controller, and, | ||
704 | * most importantly, sets it into non-xlated mode if that's | ||
705 | * desired. | ||
706 | */ | ||
707 | |||
708 | static int i8042_controller_init(void) | ||
709 | { | ||
710 | unsigned long flags; | ||
711 | |||
712 | /* | ||
713 | * Test the i8042. We need to know if it thinks it's working correctly | ||
714 | * before doing anything else. | ||
715 | */ | ||
716 | |||
717 | if (i8042_flush() == I8042_BUFFER_SIZE) { | ||
718 | printk(KERN_ERR "i8042.c: No controller found.\n"); | ||
719 | return -1; | ||
720 | } | ||
721 | |||
722 | if (i8042_reset) { | ||
723 | |||
724 | unsigned char param; | ||
725 | |||
726 | if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { | ||
727 | printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); | ||
728 | return -1; | ||
729 | } | ||
730 | |||
731 | if (param != I8042_RET_CTL_TEST) { | ||
732 | printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", | ||
733 | param, I8042_RET_CTL_TEST); | ||
734 | return -1; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * Save the CTR for restoral on unload / reboot. | ||
740 | */ | ||
741 | |||
742 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { | ||
743 | printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); | ||
744 | return -1; | ||
745 | } | ||
746 | |||
747 | i8042_initial_ctr = i8042_ctr; | ||
748 | |||
749 | /* | ||
750 | * Disable the keyboard interface and interrupt. | ||
751 | */ | ||
752 | |||
753 | i8042_ctr |= I8042_CTR_KBDDIS; | ||
754 | i8042_ctr &= ~I8042_CTR_KBDINT; | ||
755 | |||
756 | /* | ||
757 | * Handle keylock. | ||
758 | */ | ||
759 | |||
760 | spin_lock_irqsave(&i8042_lock, flags); | ||
761 | if (~i8042_read_status() & I8042_STR_KEYLOCK) { | ||
762 | if (i8042_unlock) | ||
763 | i8042_ctr |= I8042_CTR_IGNKEYLOCK; | ||
764 | else | ||
765 | printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); | ||
766 | } | ||
767 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
768 | |||
769 | /* | ||
770 | * If the chip is configured into nontranslated mode by the BIOS, don't | ||
771 | * bother enabling translating and be happy. | ||
772 | */ | ||
773 | |||
774 | if (~i8042_ctr & I8042_CTR_XLATE) | ||
775 | i8042_direct = 1; | ||
776 | |||
777 | /* | ||
778 | * Set nontranslated mode for the kbd interface if requested by an option. | ||
779 | * After this the kbd interface becomes a simple serial in/out, like the aux | ||
780 | * interface is. We don't do this by default, since it can confuse notebook | ||
781 | * BIOSes. | ||
782 | */ | ||
783 | |||
784 | if (i8042_direct) | ||
785 | i8042_ctr &= ~I8042_CTR_XLATE; | ||
786 | |||
787 | /* | ||
788 | * Write CTR back. | ||
789 | */ | ||
790 | |||
791 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
792 | printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); | ||
793 | return -1; | ||
794 | } | ||
795 | |||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | |||
800 | /* | ||
801 | * Reset the controller. | ||
802 | */ | ||
803 | static void i8042_controller_reset(void) | ||
804 | { | ||
805 | unsigned char param; | ||
806 | |||
807 | /* | ||
808 | * Reset the controller if requested. | ||
809 | */ | ||
810 | |||
811 | if (i8042_reset) | ||
812 | if (i8042_command(¶m, I8042_CMD_CTL_TEST)) | ||
813 | printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n"); | ||
814 | |||
815 | /* | ||
816 | * Disable MUX mode if present. | ||
817 | */ | ||
818 | |||
819 | if (i8042_mux_present) | ||
820 | i8042_set_mux_mode(0, NULL); | ||
821 | |||
822 | /* | ||
823 | * Restore the original control register setting. | ||
824 | */ | ||
825 | |||
826 | i8042_ctr = i8042_initial_ctr; | ||
827 | |||
828 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) | ||
829 | printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); | ||
830 | } | ||
831 | |||
832 | |||
833 | /* | ||
834 | * Here we try to reset everything back to a state in which the BIOS will be | ||
835 | * able to talk to the hardware when rebooting. | ||
836 | */ | ||
837 | |||
838 | static void i8042_controller_cleanup(void) | ||
839 | { | ||
840 | int i; | ||
841 | |||
842 | i8042_flush(); | ||
843 | |||
844 | /* | ||
845 | * Reset anything that is connected to the ports. | ||
846 | */ | ||
847 | |||
848 | for (i = 0; i < I8042_NUM_PORTS; i++) | ||
849 | if (i8042_ports[i].exists) | ||
850 | serio_cleanup(i8042_ports[i].serio); | ||
851 | |||
852 | i8042_controller_reset(); | ||
853 | } | ||
854 | |||
855 | |||
856 | /* | ||
857 | * i8042_panic_blink() will flash the keyboard LEDs and is called when | ||
858 | * kernel panics. Flashing LEDs is useful for users running X who may | ||
859 | * not see the console and will help distingushing panics from "real" | ||
860 | * lockups. | ||
861 | * | ||
862 | * Note that DELAY has a limit of 10ms so we will not get stuck here | ||
863 | * waiting for KBC to free up even if KBD interrupt is off | ||
864 | */ | ||
865 | |||
866 | #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) | ||
867 | |||
868 | static long i8042_panic_blink(long count) | ||
869 | { | ||
870 | long delay = 0; | ||
871 | static long last_blink; | ||
872 | static char led; | ||
873 | |||
874 | /* | ||
875 | * We expect frequency to be about 1/2s. KDB uses about 1s. | ||
876 | * Make sure they are different. | ||
877 | */ | ||
878 | if (!i8042_blink_frequency) | ||
879 | return 0; | ||
880 | if (count - last_blink < i8042_blink_frequency) | ||
881 | return 0; | ||
882 | |||
883 | led ^= 0x01 | 0x04; | ||
884 | while (i8042_read_status() & I8042_STR_IBF) | ||
885 | DELAY; | ||
886 | i8042_write_data(0xed); /* set leds */ | ||
887 | DELAY; | ||
888 | while (i8042_read_status() & I8042_STR_IBF) | ||
889 | DELAY; | ||
890 | DELAY; | ||
891 | i8042_write_data(led); | ||
892 | DELAY; | ||
893 | last_blink = count; | ||
894 | return delay; | ||
895 | } | ||
896 | |||
897 | #undef DELAY | ||
898 | |||
899 | /* | ||
900 | * Here we try to restore the original BIOS settings | ||
901 | */ | ||
902 | |||
903 | static int i8042_suspend(struct device *dev, pm_message_t state, u32 level) | ||
904 | { | ||
905 | if (level == SUSPEND_DISABLE) { | ||
906 | del_timer_sync(&i8042_timer); | ||
907 | i8042_controller_reset(); | ||
908 | } | ||
909 | |||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | |||
914 | /* | ||
915 | * Here we try to reset everything back to a state in which suspended | ||
916 | */ | ||
917 | |||
918 | static int i8042_resume(struct device *dev, u32 level) | ||
919 | { | ||
920 | int i; | ||
921 | |||
922 | if (level != RESUME_ENABLE) | ||
923 | return 0; | ||
924 | |||
925 | if (i8042_controller_init()) { | ||
926 | printk(KERN_ERR "i8042: resume failed\n"); | ||
927 | return -1; | ||
928 | } | ||
929 | |||
930 | if (i8042_mux_present) | ||
931 | if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) | ||
932 | printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n"); | ||
933 | |||
934 | /* | ||
935 | * Activate all ports. | ||
936 | */ | ||
937 | |||
938 | for (i = 0; i < I8042_NUM_PORTS; i++) | ||
939 | i8042_activate_port(&i8042_ports[i]); | ||
940 | |||
941 | /* | ||
942 | * Restart timer (for polling "stuck" data) | ||
943 | */ | ||
944 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | ||
945 | |||
946 | panic_blink = i8042_panic_blink; | ||
947 | |||
948 | return 0; | ||
949 | |||
950 | } | ||
951 | |||
952 | /* | ||
953 | * We need to reset the 8042 back to original mode on system shutdown, | ||
954 | * because otherwise BIOSes will be confused. | ||
955 | */ | ||
956 | |||
957 | static void i8042_shutdown(struct device *dev) | ||
958 | { | ||
959 | i8042_controller_cleanup(); | ||
960 | } | ||
961 | |||
962 | static struct device_driver i8042_driver = { | ||
963 | .name = "i8042", | ||
964 | .bus = &platform_bus_type, | ||
965 | .suspend = i8042_suspend, | ||
966 | .resume = i8042_resume, | ||
967 | .shutdown = i8042_shutdown, | ||
968 | }; | ||
969 | |||
970 | static void __init i8042_create_kbd_port(void) | ||
971 | { | ||
972 | struct serio *serio; | ||
973 | struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; | ||
974 | |||
975 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
976 | if (serio) { | ||
977 | memset(serio, 0, sizeof(struct serio)); | ||
978 | serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; | ||
979 | serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; | ||
980 | serio->open = i8042_open; | ||
981 | serio->close = i8042_close; | ||
982 | serio->start = i8042_start; | ||
983 | serio->stop = i8042_stop; | ||
984 | serio->port_data = port; | ||
985 | serio->dev.parent = &i8042_platform_device->dev; | ||
986 | strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); | ||
987 | strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); | ||
988 | |||
989 | port->serio = serio; | ||
990 | i8042_port_register(port); | ||
991 | } | ||
992 | } | ||
993 | |||
994 | static void __init i8042_create_aux_port(void) | ||
995 | { | ||
996 | struct serio *serio; | ||
997 | struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO]; | ||
998 | |||
999 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
1000 | if (serio) { | ||
1001 | memset(serio, 0, sizeof(struct serio)); | ||
1002 | serio->id.type = SERIO_8042; | ||
1003 | serio->write = i8042_aux_write; | ||
1004 | serio->open = i8042_open; | ||
1005 | serio->close = i8042_close; | ||
1006 | serio->start = i8042_start; | ||
1007 | serio->stop = i8042_stop; | ||
1008 | serio->port_data = port; | ||
1009 | serio->dev.parent = &i8042_platform_device->dev; | ||
1010 | strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); | ||
1011 | strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); | ||
1012 | |||
1013 | port->serio = serio; | ||
1014 | i8042_port_register(port); | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | static void __init i8042_create_mux_port(int index) | ||
1019 | { | ||
1020 | struct serio *serio; | ||
1021 | struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index]; | ||
1022 | |||
1023 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
1024 | if (serio) { | ||
1025 | memset(serio, 0, sizeof(struct serio)); | ||
1026 | serio->id.type = SERIO_8042; | ||
1027 | serio->write = i8042_aux_write; | ||
1028 | serio->open = i8042_open; | ||
1029 | serio->close = i8042_close; | ||
1030 | serio->start = i8042_start; | ||
1031 | serio->stop = i8042_stop; | ||
1032 | serio->port_data = port; | ||
1033 | serio->dev.parent = &i8042_platform_device->dev; | ||
1034 | snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); | ||
1035 | snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); | ||
1036 | |||
1037 | *port = i8042_ports[I8042_AUX_PORT_NO]; | ||
1038 | port->exists = 0; | ||
1039 | snprintf(port->name, sizeof(port->name), "AUX%d", index); | ||
1040 | port->mux = index; | ||
1041 | port->serio = serio; | ||
1042 | i8042_port_register(port); | ||
1043 | } | ||
1044 | } | ||
1045 | |||
1046 | static int __init i8042_init(void) | ||
1047 | { | ||
1048 | int i; | ||
1049 | int err; | ||
1050 | |||
1051 | dbg_init(); | ||
1052 | |||
1053 | init_timer(&i8042_timer); | ||
1054 | i8042_timer.function = i8042_timer_func; | ||
1055 | |||
1056 | if (i8042_platform_init()) | ||
1057 | return -EBUSY; | ||
1058 | |||
1059 | i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ; | ||
1060 | i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ; | ||
1061 | |||
1062 | if (i8042_controller_init()) { | ||
1063 | i8042_platform_exit(); | ||
1064 | return -ENODEV; | ||
1065 | } | ||
1066 | |||
1067 | err = driver_register(&i8042_driver); | ||
1068 | if (err) { | ||
1069 | i8042_platform_exit(); | ||
1070 | return err; | ||
1071 | } | ||
1072 | |||
1073 | i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0); | ||
1074 | if (IS_ERR(i8042_platform_device)) { | ||
1075 | driver_unregister(&i8042_driver); | ||
1076 | i8042_platform_exit(); | ||
1077 | return PTR_ERR(i8042_platform_device); | ||
1078 | } | ||
1079 | |||
1080 | if (!i8042_noaux && !i8042_check_aux()) { | ||
1081 | if (!i8042_nomux && !i8042_check_mux()) | ||
1082 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) | ||
1083 | i8042_create_mux_port(i); | ||
1084 | else | ||
1085 | i8042_create_aux_port(); | ||
1086 | } | ||
1087 | |||
1088 | i8042_create_kbd_port(); | ||
1089 | |||
1090 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | ||
1091 | |||
1092 | return 0; | ||
1093 | } | ||
1094 | |||
1095 | static void __exit i8042_exit(void) | ||
1096 | { | ||
1097 | int i; | ||
1098 | |||
1099 | i8042_controller_cleanup(); | ||
1100 | |||
1101 | for (i = 0; i < I8042_NUM_PORTS; i++) | ||
1102 | if (i8042_ports[i].exists) | ||
1103 | serio_unregister_port(i8042_ports[i].serio); | ||
1104 | |||
1105 | del_timer_sync(&i8042_timer); | ||
1106 | |||
1107 | platform_device_unregister(i8042_platform_device); | ||
1108 | driver_unregister(&i8042_driver); | ||
1109 | |||
1110 | i8042_platform_exit(); | ||
1111 | |||
1112 | panic_blink = NULL; | ||
1113 | } | ||
1114 | |||
1115 | module_init(i8042_init); | ||
1116 | module_exit(i8042_exit); | ||
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h new file mode 100644 index 000000000000..13835039a2a7 --- /dev/null +++ b/drivers/input/serio/i8042.h | |||
@@ -0,0 +1,133 @@ | |||
1 | #ifndef _I8042_H | ||
2 | #define _I8042_H | ||
3 | |||
4 | #include <linux/config.h> | ||
5 | |||
6 | /* | ||
7 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * Arch-dependent inline functions and defines. | ||
16 | */ | ||
17 | |||
18 | #if defined(CONFIG_MACH_JAZZ) | ||
19 | #include "i8042-jazzio.h" | ||
20 | #elif defined(CONFIG_SGI_IP22) | ||
21 | #include "i8042-ip22io.h" | ||
22 | #elif defined(CONFIG_PPC) | ||
23 | #include "i8042-ppcio.h" | ||
24 | #elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) | ||
25 | #include "i8042-sparcio.h" | ||
26 | #elif defined(CONFIG_X86) || defined(CONFIG_IA64) | ||
27 | #include "i8042-x86ia64io.h" | ||
28 | #else | ||
29 | #include "i8042-io.h" | ||
30 | #endif | ||
31 | |||
32 | /* | ||
33 | * This is in 50us units, the time we wait for the i8042 to react. This | ||
34 | * has to be long enough for the i8042 itself to timeout on sending a byte | ||
35 | * to a non-existent mouse. | ||
36 | */ | ||
37 | |||
38 | #define I8042_CTL_TIMEOUT 10000 | ||
39 | |||
40 | /* | ||
41 | * When the device isn't opened and it's interrupts aren't used, we poll it at | ||
42 | * regular intervals to see if any characters arrived. If yes, we can start | ||
43 | * probing for any mouse / keyboard connected. This is the period of the | ||
44 | * polling. | ||
45 | */ | ||
46 | |||
47 | #define I8042_POLL_PERIOD HZ/20 | ||
48 | |||
49 | /* | ||
50 | * Status register bits. | ||
51 | */ | ||
52 | |||
53 | #define I8042_STR_PARITY 0x80 | ||
54 | #define I8042_STR_TIMEOUT 0x40 | ||
55 | #define I8042_STR_AUXDATA 0x20 | ||
56 | #define I8042_STR_KEYLOCK 0x10 | ||
57 | #define I8042_STR_CMDDAT 0x08 | ||
58 | #define I8042_STR_MUXERR 0x04 | ||
59 | #define I8042_STR_IBF 0x02 | ||
60 | #define I8042_STR_OBF 0x01 | ||
61 | |||
62 | /* | ||
63 | * Control register bits. | ||
64 | */ | ||
65 | |||
66 | #define I8042_CTR_KBDINT 0x01 | ||
67 | #define I8042_CTR_AUXINT 0x02 | ||
68 | #define I8042_CTR_IGNKEYLOCK 0x08 | ||
69 | #define I8042_CTR_KBDDIS 0x10 | ||
70 | #define I8042_CTR_AUXDIS 0x20 | ||
71 | #define I8042_CTR_XLATE 0x40 | ||
72 | |||
73 | /* | ||
74 | * Commands. | ||
75 | */ | ||
76 | |||
77 | #define I8042_CMD_CTL_RCTR 0x0120 | ||
78 | #define I8042_CMD_CTL_WCTR 0x1060 | ||
79 | #define I8042_CMD_CTL_TEST 0x01aa | ||
80 | |||
81 | #define I8042_CMD_KBD_DISABLE 0x00ad | ||
82 | #define I8042_CMD_KBD_ENABLE 0x00ae | ||
83 | #define I8042_CMD_KBD_TEST 0x01ab | ||
84 | #define I8042_CMD_KBD_LOOP 0x11d2 | ||
85 | |||
86 | #define I8042_CMD_AUX_DISABLE 0x00a7 | ||
87 | #define I8042_CMD_AUX_ENABLE 0x00a8 | ||
88 | #define I8042_CMD_AUX_TEST 0x01a9 | ||
89 | #define I8042_CMD_AUX_SEND 0x10d4 | ||
90 | #define I8042_CMD_AUX_LOOP 0x11d3 | ||
91 | |||
92 | #define I8042_CMD_MUX_PFX 0x0090 | ||
93 | #define I8042_CMD_MUX_SEND 0x1090 | ||
94 | |||
95 | /* | ||
96 | * Return codes. | ||
97 | */ | ||
98 | |||
99 | #define I8042_RET_CTL_TEST 0x55 | ||
100 | |||
101 | /* | ||
102 | * Expected maximum internal i8042 buffer size. This is used for flushing | ||
103 | * the i8042 buffers. | ||
104 | */ | ||
105 | |||
106 | #define I8042_BUFFER_SIZE 16 | ||
107 | |||
108 | /* | ||
109 | * Number of AUX ports on controllers supporting active multiplexing | ||
110 | * specification | ||
111 | */ | ||
112 | |||
113 | #define I8042_NUM_MUX_PORTS 4 | ||
114 | |||
115 | /* | ||
116 | * Debug. | ||
117 | */ | ||
118 | |||
119 | #ifdef DEBUG | ||
120 | static unsigned long i8042_start_time; | ||
121 | #define dbg_init() do { i8042_start_time = jiffies; } while (0) | ||
122 | #define dbg(format, arg...) \ | ||
123 | do { \ | ||
124 | if (i8042_debug) \ | ||
125 | printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" , \ | ||
126 | ## arg, (int) (jiffies - i8042_start_time)); \ | ||
127 | } while (0) | ||
128 | #else | ||
129 | #define dbg_init() do { } while (0) | ||
130 | #define dbg(format, arg...) do {} while (0) | ||
131 | #endif | ||
132 | |||
133 | #endif /* _I8042_H */ | ||
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c new file mode 100644 index 000000000000..c978657068c5 --- /dev/null +++ b/drivers/input/serio/libps2.c | |||
@@ -0,0 +1,305 @@ | |||
1 | /* | ||
2 | * PS/2 driver library | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | * Copyright (c) 2004 Dmitry Torokhov | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/serio.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/libps2.h> | ||
23 | |||
24 | #define DRIVER_DESC "PS/2 driver library" | ||
25 | |||
26 | MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); | ||
27 | MODULE_DESCRIPTION("PS/2 driver library"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | EXPORT_SYMBOL(ps2_init); | ||
31 | EXPORT_SYMBOL(ps2_sendbyte); | ||
32 | EXPORT_SYMBOL(ps2_command); | ||
33 | EXPORT_SYMBOL(ps2_schedule_command); | ||
34 | EXPORT_SYMBOL(ps2_handle_ack); | ||
35 | EXPORT_SYMBOL(ps2_handle_response); | ||
36 | EXPORT_SYMBOL(ps2_cmd_aborted); | ||
37 | |||
38 | /* Work structure to schedule execution of a command */ | ||
39 | struct ps2work { | ||
40 | struct work_struct work; | ||
41 | struct ps2dev *ps2dev; | ||
42 | int command; | ||
43 | unsigned char param[0]; | ||
44 | }; | ||
45 | |||
46 | |||
47 | /* | ||
48 | * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge. | ||
49 | * It doesn't handle retransmission, though it could - because when there would | ||
50 | * be need for retransmissions, the mouse has to be replaced anyway. | ||
51 | * | ||
52 | * ps2_sendbyte() can only be called from a process context | ||
53 | */ | ||
54 | |||
55 | int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) | ||
56 | { | ||
57 | serio_pause_rx(ps2dev->serio); | ||
58 | ps2dev->nak = 1; | ||
59 | ps2dev->flags |= PS2_FLAG_ACK; | ||
60 | serio_continue_rx(ps2dev->serio); | ||
61 | |||
62 | if (serio_write(ps2dev->serio, byte) == 0) | ||
63 | wait_event_timeout(ps2dev->wait, | ||
64 | !(ps2dev->flags & PS2_FLAG_ACK), | ||
65 | msecs_to_jiffies(timeout)); | ||
66 | |||
67 | serio_pause_rx(ps2dev->serio); | ||
68 | ps2dev->flags &= ~PS2_FLAG_ACK; | ||
69 | serio_continue_rx(ps2dev->serio); | ||
70 | |||
71 | return -ps2dev->nak; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * ps2_command() sends a command and its parameters to the mouse, | ||
76 | * then waits for the response and puts it in the param array. | ||
77 | * | ||
78 | * ps2_command() can only be called from a process context | ||
79 | */ | ||
80 | |||
81 | int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | ||
82 | { | ||
83 | int timeout; | ||
84 | int send = (command >> 12) & 0xf; | ||
85 | int receive = (command >> 8) & 0xf; | ||
86 | int rc = -1; | ||
87 | int i; | ||
88 | |||
89 | down(&ps2dev->cmd_sem); | ||
90 | |||
91 | serio_pause_rx(ps2dev->serio); | ||
92 | ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; | ||
93 | ps2dev->cmdcnt = receive; | ||
94 | if (receive && param) | ||
95 | for (i = 0; i < receive; i++) | ||
96 | ps2dev->cmdbuf[(receive - 1) - i] = param[i]; | ||
97 | serio_continue_rx(ps2dev->serio); | ||
98 | |||
99 | /* | ||
100 | * Some devices (Synaptics) peform the reset before | ||
101 | * ACKing the reset command, and so it can take a long | ||
102 | * time before the ACK arrrives. | ||
103 | */ | ||
104 | if (command & 0xff) | ||
105 | if (ps2_sendbyte(ps2dev, command & 0xff, | ||
106 | command == PS2_CMD_RESET_BAT ? 1000 : 200)) | ||
107 | goto out; | ||
108 | |||
109 | for (i = 0; i < send; i++) | ||
110 | if (ps2_sendbyte(ps2dev, param[i], 200)) | ||
111 | goto out; | ||
112 | |||
113 | /* | ||
114 | * The reset command takes a long time to execute. | ||
115 | */ | ||
116 | timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500); | ||
117 | |||
118 | timeout = wait_event_timeout(ps2dev->wait, | ||
119 | !(ps2dev->flags & PS2_FLAG_CMD1), timeout); | ||
120 | |||
121 | if (ps2dev->cmdcnt && timeout > 0) { | ||
122 | |||
123 | if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) { | ||
124 | /* | ||
125 | * Device has sent the first response byte | ||
126 | * after a reset command, reset is thus done, | ||
127 | * shorten the timeout. The next byte will come | ||
128 | * soon (keyboard) or not at all (mouse). | ||
129 | */ | ||
130 | timeout = msecs_to_jiffies(100); | ||
131 | } | ||
132 | |||
133 | if (command == PS2_CMD_GETID && | ||
134 | ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */ | ||
135 | ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */ | ||
136 | ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */ | ||
137 | ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */ | ||
138 | ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */ | ||
139 | ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */ | ||
140 | /* | ||
141 | * Device behind the port is not a keyboard | ||
142 | * so we don't need to wait for the 2nd byte | ||
143 | * of ID response. | ||
144 | */ | ||
145 | serio_pause_rx(ps2dev->serio); | ||
146 | ps2dev->flags = ps2dev->cmdcnt = 0; | ||
147 | serio_continue_rx(ps2dev->serio); | ||
148 | } | ||
149 | |||
150 | wait_event_timeout(ps2dev->wait, | ||
151 | !(ps2dev->flags & PS2_FLAG_CMD), timeout); | ||
152 | } | ||
153 | |||
154 | if (param) | ||
155 | for (i = 0; i < receive; i++) | ||
156 | param[i] = ps2dev->cmdbuf[(receive - 1) - i]; | ||
157 | |||
158 | if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) | ||
159 | goto out; | ||
160 | |||
161 | rc = 0; | ||
162 | |||
163 | out: | ||
164 | serio_pause_rx(ps2dev->serio); | ||
165 | ps2dev->flags = 0; | ||
166 | serio_continue_rx(ps2dev->serio); | ||
167 | |||
168 | up(&ps2dev->cmd_sem); | ||
169 | return rc; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * ps2_execute_scheduled_command() sends a command, previously scheduled by | ||
174 | * ps2_schedule_command(), to a PS/2 device (keyboard, mouse, etc.) | ||
175 | */ | ||
176 | |||
177 | static void ps2_execute_scheduled_command(void *data) | ||
178 | { | ||
179 | struct ps2work *ps2work = data; | ||
180 | |||
181 | ps2_command(ps2work->ps2dev, ps2work->param, ps2work->command); | ||
182 | kfree(ps2work); | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * ps2_schedule_command() allows to schedule delayed execution of a PS/2 | ||
187 | * command and can be used to issue a command from an interrupt or softirq | ||
188 | * context. | ||
189 | */ | ||
190 | |||
191 | int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command) | ||
192 | { | ||
193 | struct ps2work *ps2work; | ||
194 | int send = (command >> 12) & 0xf; | ||
195 | int receive = (command >> 8) & 0xf; | ||
196 | |||
197 | if (!(ps2work = kmalloc(sizeof(struct ps2work) + max(send, receive), GFP_ATOMIC))) | ||
198 | return -1; | ||
199 | |||
200 | memset(ps2work, 0, sizeof(struct ps2work)); | ||
201 | ps2work->ps2dev = ps2dev; | ||
202 | ps2work->command = command; | ||
203 | memcpy(ps2work->param, param, send); | ||
204 | INIT_WORK(&ps2work->work, ps2_execute_scheduled_command, ps2work); | ||
205 | |||
206 | if (!schedule_work(&ps2work->work)) { | ||
207 | kfree(ps2work); | ||
208 | return -1; | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * ps2_init() initializes ps2dev structure | ||
216 | */ | ||
217 | |||
218 | void ps2_init(struct ps2dev *ps2dev, struct serio *serio) | ||
219 | { | ||
220 | init_MUTEX(&ps2dev->cmd_sem); | ||
221 | init_waitqueue_head(&ps2dev->wait); | ||
222 | ps2dev->serio = serio; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * ps2_handle_ack() is supposed to be used in interrupt handler | ||
227 | * to properly process ACK/NAK of a command from a PS/2 device. | ||
228 | */ | ||
229 | |||
230 | int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data) | ||
231 | { | ||
232 | switch (data) { | ||
233 | case PS2_RET_ACK: | ||
234 | ps2dev->nak = 0; | ||
235 | break; | ||
236 | |||
237 | case PS2_RET_NAK: | ||
238 | ps2dev->nak = 1; | ||
239 | break; | ||
240 | |||
241 | /* | ||
242 | * Workaround for mice which don't ACK the Get ID command. | ||
243 | * These are valid mouse IDs that we recognize. | ||
244 | */ | ||
245 | case 0x00: | ||
246 | case 0x03: | ||
247 | case 0x04: | ||
248 | if (ps2dev->flags & PS2_FLAG_WAITID) { | ||
249 | ps2dev->nak = 0; | ||
250 | break; | ||
251 | } | ||
252 | /* Fall through */ | ||
253 | default: | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | |||
258 | if (!ps2dev->nak && ps2dev->cmdcnt) | ||
259 | ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1; | ||
260 | |||
261 | ps2dev->flags &= ~PS2_FLAG_ACK; | ||
262 | wake_up(&ps2dev->wait); | ||
263 | |||
264 | if (data != PS2_RET_ACK) | ||
265 | ps2_handle_response(ps2dev, data); | ||
266 | |||
267 | return 1; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * ps2_handle_response() is supposed to be used in interrupt handler | ||
272 | * to properly store device's response to a command and notify process | ||
273 | * waiting for completion of the command. | ||
274 | */ | ||
275 | |||
276 | int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data) | ||
277 | { | ||
278 | if (ps2dev->cmdcnt) | ||
279 | ps2dev->cmdbuf[--ps2dev->cmdcnt] = data; | ||
280 | |||
281 | if (ps2dev->flags & PS2_FLAG_CMD1) { | ||
282 | ps2dev->flags &= ~PS2_FLAG_CMD1; | ||
283 | if (ps2dev->cmdcnt) | ||
284 | wake_up(&ps2dev->wait); | ||
285 | } | ||
286 | |||
287 | if (!ps2dev->cmdcnt) { | ||
288 | ps2dev->flags &= ~PS2_FLAG_CMD; | ||
289 | wake_up(&ps2dev->wait); | ||
290 | } | ||
291 | |||
292 | return 1; | ||
293 | } | ||
294 | |||
295 | void ps2_cmd_aborted(struct ps2dev *ps2dev) | ||
296 | { | ||
297 | if (ps2dev->flags & PS2_FLAG_ACK) | ||
298 | ps2dev->nak = 1; | ||
299 | |||
300 | if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) | ||
301 | wake_up(&ps2dev->wait); | ||
302 | |||
303 | ps2dev->flags = 0; | ||
304 | } | ||
305 | |||
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c new file mode 100644 index 000000000000..9880fc145d90 --- /dev/null +++ b/drivers/input/serio/maceps2.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * SGI O2 MACE PS2 controller driver for linux | ||
3 | * | ||
4 | * Copyright (C) 2002 Vivien Chappelier | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation | ||
9 | */ | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/serio.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include <linux/err.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include <asm/irq.h> | ||
24 | #include <asm/system.h> | ||
25 | #include <asm/ip32/mace.h> | ||
26 | #include <asm/ip32/ip32_ints.h> | ||
27 | |||
28 | MODULE_AUTHOR("Vivien Chappelier <vivien.chappelier@linux-mips.org"); | ||
29 | MODULE_DESCRIPTION("SGI O2 MACE PS2 controller driver"); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | #define MACE_PS2_TIMEOUT 10000 /* in 50us unit */ | ||
33 | |||
34 | #define PS2_STATUS_CLOCK_SIGNAL BIT(0) /* external clock signal */ | ||
35 | #define PS2_STATUS_CLOCK_INHIBIT BIT(1) /* clken output signal */ | ||
36 | #define PS2_STATUS_TX_INPROGRESS BIT(2) /* transmission in progress */ | ||
37 | #define PS2_STATUS_TX_EMPTY BIT(3) /* empty transmit buffer */ | ||
38 | #define PS2_STATUS_RX_FULL BIT(4) /* full receive buffer */ | ||
39 | #define PS2_STATUS_RX_INPROGRESS BIT(5) /* reception in progress */ | ||
40 | #define PS2_STATUS_ERROR_PARITY BIT(6) /* parity error */ | ||
41 | #define PS2_STATUS_ERROR_FRAMING BIT(7) /* framing error */ | ||
42 | |||
43 | #define PS2_CONTROL_TX_CLOCK_DISABLE BIT(0) /* inhibit clock signal after TX */ | ||
44 | #define PS2_CONTROL_TX_ENABLE BIT(1) /* transmit enable */ | ||
45 | #define PS2_CONTROL_TX_INT_ENABLE BIT(2) /* enable transmit interrupt */ | ||
46 | #define PS2_CONTROL_RX_INT_ENABLE BIT(3) /* enable receive interrupt */ | ||
47 | #define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */ | ||
48 | #define PS2_CONTROL_RESET BIT(5) /* reset */ | ||
49 | |||
50 | struct maceps2_data { | ||
51 | struct mace_ps2port *port; | ||
52 | int irq; | ||
53 | }; | ||
54 | |||
55 | static struct maceps2_data port_data[2]; | ||
56 | static struct serio *maceps2_port[2]; | ||
57 | static struct platform_device *maceps2_device; | ||
58 | |||
59 | static int maceps2_write(struct serio *dev, unsigned char val) | ||
60 | { | ||
61 | struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; | ||
62 | unsigned int timeout = MACE_PS2_TIMEOUT; | ||
63 | |||
64 | do { | ||
65 | if (port->status & PS2_STATUS_TX_EMPTY) { | ||
66 | port->tx = val; | ||
67 | return 0; | ||
68 | } | ||
69 | udelay(50); | ||
70 | } while (timeout--); | ||
71 | |||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | static irqreturn_t maceps2_interrupt(int irq, void *dev_id, | ||
76 | struct pt_regs *regs) | ||
77 | { | ||
78 | struct serio *dev = dev_id; | ||
79 | struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; | ||
80 | unsigned long byte; | ||
81 | |||
82 | if (port->status & PS2_STATUS_RX_FULL) { | ||
83 | byte = port->rx; | ||
84 | serio_interrupt(dev, byte & 0xff, 0, regs); | ||
85 | } | ||
86 | |||
87 | return IRQ_HANDLED; | ||
88 | } | ||
89 | |||
90 | static int maceps2_open(struct serio *dev) | ||
91 | { | ||
92 | struct maceps2_data *data = (struct maceps2_data *)dev->port_data; | ||
93 | |||
94 | if (request_irq(data->irq, maceps2_interrupt, 0, "PS2 port", dev)) { | ||
95 | printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); | ||
96 | return -EBUSY; | ||
97 | } | ||
98 | |||
99 | /* Reset port */ | ||
100 | data->port->control = PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET; | ||
101 | udelay(100); | ||
102 | |||
103 | /* Enable interrupts */ | ||
104 | data->port->control = PS2_CONTROL_RX_CLOCK_ENABLE | | ||
105 | PS2_CONTROL_TX_ENABLE | | ||
106 | PS2_CONTROL_RX_INT_ENABLE; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static void maceps2_close(struct serio *dev) | ||
112 | { | ||
113 | struct maceps2_data *data = (struct maceps2_data *)dev->port_data; | ||
114 | |||
115 | data->port->control = PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET; | ||
116 | udelay(100); | ||
117 | free_irq(data->irq, dev); | ||
118 | } | ||
119 | |||
120 | |||
121 | static struct serio * __init maceps2_allocate_port(int idx) | ||
122 | { | ||
123 | struct serio *serio; | ||
124 | |||
125 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
126 | if (serio) { | ||
127 | memset(serio, 0, sizeof(struct serio)); | ||
128 | serio->id.type = SERIO_8042; | ||
129 | serio->write = maceps2_write; | ||
130 | serio->open = maceps2_open; | ||
131 | serio->close = maceps2_close; | ||
132 | snprintf(serio->name, sizeof(serio->name), "MACE PS/2 port%d", idx); | ||
133 | snprintf(serio->phys, sizeof(serio->phys), "mace/serio%d", idx); | ||
134 | serio->port_data = &port_data[idx]; | ||
135 | serio->dev.parent = &maceps2_device->dev; | ||
136 | } | ||
137 | |||
138 | return serio; | ||
139 | } | ||
140 | |||
141 | |||
142 | static int __init maceps2_init(void) | ||
143 | { | ||
144 | maceps2_device = platform_device_register_simple("maceps2", -1, NULL, 0); | ||
145 | if (IS_ERR(maceps2_device)) | ||
146 | return PTR_ERR(maceps2_device); | ||
147 | |||
148 | port_data[0].port = &mace->perif.ps2.keyb; | ||
149 | port_data[0].irq = MACEISA_KEYB_IRQ; | ||
150 | port_data[1].port = &mace->perif.ps2.mouse; | ||
151 | port_data[1].irq = MACEISA_MOUSE_IRQ; | ||
152 | |||
153 | maceps2_port[0] = maceps2_allocate_port(0); | ||
154 | maceps2_port[1] = maceps2_allocate_port(1); | ||
155 | if (!maceps2_port[0] || !maceps2_port[1]) { | ||
156 | kfree(maceps2_port[0]); | ||
157 | kfree(maceps2_port[1]); | ||
158 | platform_device_unregister(maceps2_device); | ||
159 | return -ENOMEM; | ||
160 | } | ||
161 | |||
162 | serio_register_port(maceps2_port[0]); | ||
163 | serio_register_port(maceps2_port[1]); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static void __exit maceps2_exit(void) | ||
169 | { | ||
170 | serio_unregister_port(maceps2_port[0]); | ||
171 | serio_unregister_port(maceps2_port[1]); | ||
172 | platform_device_unregister(maceps2_device); | ||
173 | } | ||
174 | |||
175 | module_init(maceps2_init); | ||
176 | module_exit(maceps2_exit); | ||
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c new file mode 100644 index 000000000000..1d15c2819818 --- /dev/null +++ b/drivers/input/serio/parkbd.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * Parallel port to Keyboard port adapter driver for Linux | ||
3 | * | ||
4 | * Copyright (c) 1999-2004 Vojtech Pavlik | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * To connect an AT or XT keyboard to the parallel port, a fairly simple adapter | ||
15 | * can be made: | ||
16 | * | ||
17 | * Parallel port Keyboard port | ||
18 | * | ||
19 | * +5V --------------------- +5V (4) | ||
20 | * | ||
21 | * ______ | ||
22 | * +5V -------|______|--. | ||
23 | * | | ||
24 | * ACK (10) ------------| | ||
25 | * |--- KBD CLOCK (5) | ||
26 | * STROBE (1) ---|<|----' | ||
27 | * | ||
28 | * ______ | ||
29 | * +5V -------|______|--. | ||
30 | * | | ||
31 | * BUSY (11) -----------| | ||
32 | * |--- KBD DATA (1) | ||
33 | * AUTOFD (14) --|<|----' | ||
34 | * | ||
35 | * GND (18-25) ------------- GND (3) | ||
36 | * | ||
37 | * The diodes can be fairly any type, and the resistors should be somewhere | ||
38 | * around 5 kOhm, but the adapter will likely work without the resistors, | ||
39 | * too. | ||
40 | * | ||
41 | * The +5V source can be taken either from USB, from mouse or keyboard ports, | ||
42 | * or from a joystick port. Unfortunately, the parallel port of a PC doesn't | ||
43 | * have a +5V pin, and feeding the keyboard from signal pins is out of question | ||
44 | * with 300 mA power reqirement of a typical AT keyboard. | ||
45 | */ | ||
46 | |||
47 | #include <linux/module.h> | ||
48 | #include <linux/parport.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/serio.h> | ||
51 | |||
52 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
53 | MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver"); | ||
54 | MODULE_LICENSE("GPL"); | ||
55 | |||
56 | static unsigned int parkbd_pp_no; | ||
57 | module_param_named(port, parkbd_pp_no, int, 0); | ||
58 | MODULE_PARM_DESC(port, "Parallel port the adapter is connected to (default is 0)"); | ||
59 | |||
60 | static unsigned int parkbd_mode = SERIO_8042; | ||
61 | module_param_named(mode, parkbd_mode, uint, 0); | ||
62 | MODULE_PARM_DESC(mode, "Mode of operation: XT = 0/AT = 1 (default)"); | ||
63 | |||
64 | #define PARKBD_CLOCK 0x01 /* Strobe & Ack */ | ||
65 | #define PARKBD_DATA 0x02 /* AutoFd & Busy */ | ||
66 | |||
67 | static int parkbd_buffer; | ||
68 | static int parkbd_counter; | ||
69 | static unsigned long parkbd_last; | ||
70 | static int parkbd_writing; | ||
71 | static unsigned long parkbd_start; | ||
72 | |||
73 | static struct pardevice *parkbd_dev; | ||
74 | static struct serio *parkbd_port; | ||
75 | |||
76 | static int parkbd_readlines(void) | ||
77 | { | ||
78 | return (parport_read_status(parkbd_dev->port) >> 6) ^ 2; | ||
79 | } | ||
80 | |||
81 | static void parkbd_writelines(int data) | ||
82 | { | ||
83 | parport_write_control(parkbd_dev->port, (~data & 3) | 0x10); | ||
84 | } | ||
85 | |||
86 | static int parkbd_write(struct serio *port, unsigned char c) | ||
87 | { | ||
88 | unsigned char p; | ||
89 | |||
90 | if (!parkbd_mode) return -1; | ||
91 | |||
92 | p = c ^ (c >> 4); | ||
93 | p = p ^ (p >> 2); | ||
94 | p = p ^ (p >> 1); | ||
95 | |||
96 | parkbd_counter = 0; | ||
97 | parkbd_writing = 1; | ||
98 | parkbd_buffer = c | (((int) (~p & 1)) << 8) | 0x600; | ||
99 | |||
100 | parkbd_writelines(2); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
106 | { | ||
107 | |||
108 | if (parkbd_writing) { | ||
109 | |||
110 | if (parkbd_counter && ((parkbd_counter == 11) || time_after(jiffies, parkbd_last + HZ/100))) { | ||
111 | parkbd_counter = 0; | ||
112 | parkbd_buffer = 0; | ||
113 | parkbd_writing = 0; | ||
114 | parkbd_writelines(3); | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2); | ||
119 | |||
120 | if (parkbd_counter == 11) { | ||
121 | parkbd_counter = 0; | ||
122 | parkbd_buffer = 0; | ||
123 | parkbd_writing = 0; | ||
124 | parkbd_writelines(3); | ||
125 | } | ||
126 | |||
127 | } else { | ||
128 | |||
129 | if ((parkbd_counter == parkbd_mode + 10) || time_after(jiffies, parkbd_last + HZ/100)) { | ||
130 | parkbd_counter = 0; | ||
131 | parkbd_buffer = 0; | ||
132 | } | ||
133 | |||
134 | parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; | ||
135 | |||
136 | if (parkbd_counter == parkbd_mode + 10) | ||
137 | serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); | ||
138 | } | ||
139 | |||
140 | parkbd_last = jiffies; | ||
141 | } | ||
142 | |||
143 | static int parkbd_getport(void) | ||
144 | { | ||
145 | struct parport *pp; | ||
146 | |||
147 | pp = parport_find_number(parkbd_pp_no); | ||
148 | |||
149 | if (pp == NULL) { | ||
150 | printk(KERN_ERR "parkbd: no such parport\n"); | ||
151 | return -ENODEV; | ||
152 | } | ||
153 | |||
154 | parkbd_dev = parport_register_device(pp, "parkbd", NULL, NULL, parkbd_interrupt, PARPORT_DEV_EXCL, NULL); | ||
155 | parport_put_port(pp); | ||
156 | |||
157 | if (!parkbd_dev) | ||
158 | return -ENODEV; | ||
159 | |||
160 | if (parport_claim(parkbd_dev)) { | ||
161 | parport_unregister_device(parkbd_dev); | ||
162 | return -EBUSY; | ||
163 | } | ||
164 | |||
165 | parkbd_start = jiffies; | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static struct serio * __init parkbd_allocate_serio(void) | ||
171 | { | ||
172 | struct serio *serio; | ||
173 | |||
174 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
175 | if (serio) { | ||
176 | memset(serio, 0, sizeof(struct serio)); | ||
177 | serio->id.type = parkbd_mode; | ||
178 | serio->write = parkbd_write, | ||
179 | strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name)); | ||
180 | snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name); | ||
181 | } | ||
182 | |||
183 | return serio; | ||
184 | } | ||
185 | |||
186 | static int __init parkbd_init(void) | ||
187 | { | ||
188 | int err; | ||
189 | |||
190 | err = parkbd_getport(); | ||
191 | if (err) | ||
192 | return err; | ||
193 | |||
194 | parkbd_port = parkbd_allocate_serio(); | ||
195 | if (!parkbd_port) { | ||
196 | parport_release(parkbd_dev); | ||
197 | return -ENOMEM; | ||
198 | } | ||
199 | |||
200 | parkbd_writelines(3); | ||
201 | |||
202 | serio_register_port(parkbd_port); | ||
203 | |||
204 | printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", | ||
205 | parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static void __exit parkbd_exit(void) | ||
211 | { | ||
212 | parport_release(parkbd_dev); | ||
213 | serio_unregister_port(parkbd_port); | ||
214 | parport_unregister_device(parkbd_dev); | ||
215 | } | ||
216 | |||
217 | module_init(parkbd_init); | ||
218 | module_exit(parkbd_exit); | ||
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c new file mode 100644 index 000000000000..1e139c5e59de --- /dev/null +++ b/drivers/input/serio/pcips2.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * linux/drivers/input/serio/pcips2.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Russell King, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License. | ||
9 | * | ||
10 | * I'm not sure if this is a generic PS/2 PCI interface or specific to | ||
11 | * the Mobility Electronics docking station. | ||
12 | */ | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/input.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/serio.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | #define PS2_CTRL (0) | ||
24 | #define PS2_STATUS (1) | ||
25 | #define PS2_DATA (2) | ||
26 | |||
27 | #define PS2_CTRL_CLK (1<<0) | ||
28 | #define PS2_CTRL_DAT (1<<1) | ||
29 | #define PS2_CTRL_TXIRQ (1<<2) | ||
30 | #define PS2_CTRL_ENABLE (1<<3) | ||
31 | #define PS2_CTRL_RXIRQ (1<<4) | ||
32 | |||
33 | #define PS2_STAT_CLK (1<<0) | ||
34 | #define PS2_STAT_DAT (1<<1) | ||
35 | #define PS2_STAT_PARITY (1<<2) | ||
36 | #define PS2_STAT_RXFULL (1<<5) | ||
37 | #define PS2_STAT_TXBUSY (1<<6) | ||
38 | #define PS2_STAT_TXEMPTY (1<<7) | ||
39 | |||
40 | struct pcips2_data { | ||
41 | struct serio *io; | ||
42 | unsigned int base; | ||
43 | struct pci_dev *dev; | ||
44 | }; | ||
45 | |||
46 | static int pcips2_write(struct serio *io, unsigned char val) | ||
47 | { | ||
48 | struct pcips2_data *ps2if = io->port_data; | ||
49 | unsigned int stat; | ||
50 | |||
51 | do { | ||
52 | stat = inb(ps2if->base + PS2_STATUS); | ||
53 | cpu_relax(); | ||
54 | } while (!(stat & PS2_STAT_TXEMPTY)); | ||
55 | |||
56 | outb(val, ps2if->base + PS2_DATA); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs) | ||
62 | { | ||
63 | struct pcips2_data *ps2if = devid; | ||
64 | unsigned char status, scancode; | ||
65 | int handled = 0; | ||
66 | |||
67 | do { | ||
68 | unsigned int flag; | ||
69 | |||
70 | status = inb(ps2if->base + PS2_STATUS); | ||
71 | if (!(status & PS2_STAT_RXFULL)) | ||
72 | break; | ||
73 | handled = 1; | ||
74 | scancode = inb(ps2if->base + PS2_DATA); | ||
75 | if (status == 0xff && scancode == 0xff) | ||
76 | break; | ||
77 | |||
78 | flag = (status & PS2_STAT_PARITY) ? 0 : SERIO_PARITY; | ||
79 | |||
80 | if (hweight8(scancode) & 1) | ||
81 | flag ^= SERIO_PARITY; | ||
82 | |||
83 | serio_interrupt(ps2if->io, scancode, flag, regs); | ||
84 | } while (1); | ||
85 | return IRQ_RETVAL(handled); | ||
86 | } | ||
87 | |||
88 | static void pcips2_flush_input(struct pcips2_data *ps2if) | ||
89 | { | ||
90 | unsigned char status, scancode; | ||
91 | |||
92 | do { | ||
93 | status = inb(ps2if->base + PS2_STATUS); | ||
94 | if (!(status & PS2_STAT_RXFULL)) | ||
95 | break; | ||
96 | scancode = inb(ps2if->base + PS2_DATA); | ||
97 | if (status == 0xff && scancode == 0xff) | ||
98 | break; | ||
99 | } while (1); | ||
100 | } | ||
101 | |||
102 | static int pcips2_open(struct serio *io) | ||
103 | { | ||
104 | struct pcips2_data *ps2if = io->port_data; | ||
105 | int ret, val = 0; | ||
106 | |||
107 | outb(PS2_CTRL_ENABLE, ps2if->base); | ||
108 | pcips2_flush_input(ps2if); | ||
109 | |||
110 | ret = request_irq(ps2if->dev->irq, pcips2_interrupt, SA_SHIRQ, | ||
111 | "pcips2", ps2if); | ||
112 | if (ret == 0) | ||
113 | val = PS2_CTRL_ENABLE | PS2_CTRL_RXIRQ; | ||
114 | |||
115 | outb(val, ps2if->base); | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static void pcips2_close(struct serio *io) | ||
121 | { | ||
122 | struct pcips2_data *ps2if = io->port_data; | ||
123 | |||
124 | outb(0, ps2if->base); | ||
125 | |||
126 | free_irq(ps2if->dev->irq, ps2if); | ||
127 | } | ||
128 | |||
129 | static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
130 | { | ||
131 | struct pcips2_data *ps2if; | ||
132 | struct serio *serio; | ||
133 | int ret; | ||
134 | |||
135 | ret = pci_enable_device(dev); | ||
136 | if (ret) | ||
137 | goto out; | ||
138 | |||
139 | ret = pci_request_regions(dev, "pcips2"); | ||
140 | if (ret) | ||
141 | goto disable; | ||
142 | |||
143 | ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL); | ||
144 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
145 | if (!ps2if || !serio) { | ||
146 | ret = -ENOMEM; | ||
147 | goto release; | ||
148 | } | ||
149 | |||
150 | memset(ps2if, 0, sizeof(struct pcips2_data)); | ||
151 | memset(serio, 0, sizeof(struct serio)); | ||
152 | |||
153 | serio->id.type = SERIO_8042; | ||
154 | serio->write = pcips2_write; | ||
155 | serio->open = pcips2_open; | ||
156 | serio->close = pcips2_close; | ||
157 | strlcpy(serio->name, pci_name(dev), sizeof(serio->name)); | ||
158 | strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); | ||
159 | serio->port_data = ps2if; | ||
160 | serio->dev.parent = &dev->dev; | ||
161 | ps2if->io = serio; | ||
162 | ps2if->dev = dev; | ||
163 | ps2if->base = pci_resource_start(dev, 0); | ||
164 | |||
165 | pci_set_drvdata(dev, ps2if); | ||
166 | |||
167 | serio_register_port(ps2if->io); | ||
168 | return 0; | ||
169 | |||
170 | release: | ||
171 | kfree(ps2if); | ||
172 | kfree(serio); | ||
173 | pci_release_regions(dev); | ||
174 | disable: | ||
175 | pci_disable_device(dev); | ||
176 | out: | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static void __devexit pcips2_remove(struct pci_dev *dev) | ||
181 | { | ||
182 | struct pcips2_data *ps2if = pci_get_drvdata(dev); | ||
183 | |||
184 | serio_unregister_port(ps2if->io); | ||
185 | pci_set_drvdata(dev, NULL); | ||
186 | kfree(ps2if); | ||
187 | pci_release_regions(dev); | ||
188 | pci_disable_device(dev); | ||
189 | } | ||
190 | |||
191 | static struct pci_device_id pcips2_ids[] = { | ||
192 | { | ||
193 | .vendor = 0x14f2, /* MOBILITY */ | ||
194 | .device = 0x0123, /* Keyboard */ | ||
195 | .subvendor = PCI_ANY_ID, | ||
196 | .subdevice = PCI_ANY_ID, | ||
197 | .class = PCI_CLASS_INPUT_KEYBOARD << 8, | ||
198 | .class_mask = 0xffff00, | ||
199 | }, | ||
200 | { | ||
201 | .vendor = 0x14f2, /* MOBILITY */ | ||
202 | .device = 0x0124, /* Mouse */ | ||
203 | .subvendor = PCI_ANY_ID, | ||
204 | .subdevice = PCI_ANY_ID, | ||
205 | .class = PCI_CLASS_INPUT_MOUSE << 8, | ||
206 | .class_mask = 0xffff00, | ||
207 | }, | ||
208 | { 0, } | ||
209 | }; | ||
210 | |||
211 | static struct pci_driver pcips2_driver = { | ||
212 | .name = "pcips2", | ||
213 | .id_table = pcips2_ids, | ||
214 | .probe = pcips2_probe, | ||
215 | .remove = __devexit_p(pcips2_remove), | ||
216 | }; | ||
217 | |||
218 | static int __init pcips2_init(void) | ||
219 | { | ||
220 | return pci_register_driver(&pcips2_driver); | ||
221 | } | ||
222 | |||
223 | static void __exit pcips2_exit(void) | ||
224 | { | ||
225 | pci_unregister_driver(&pcips2_driver); | ||
226 | } | ||
227 | |||
228 | module_init(pcips2_init); | ||
229 | module_exit(pcips2_exit); | ||
230 | |||
231 | MODULE_LICENSE("GPL"); | ||
232 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); | ||
233 | MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver"); | ||
234 | MODULE_DEVICE_TABLE(pci, pcips2_ids); | ||
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c new file mode 100644 index 000000000000..46093c507988 --- /dev/null +++ b/drivers/input/serio/q40kbd.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * $Id: q40kbd.c,v 1.12 2002/02/02 22:26:44 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
5 | * | ||
6 | * Based on the work of: | ||
7 | * Richard Zidlicky <Richard.Zidlicky@stud.informatik.uni-erlangen.de> | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Q40 PS/2 keyboard controller driver for Linux/m68k | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | * Should you need to contact me, the author, you can do so either by | ||
30 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
31 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/serio.h> | ||
37 | #include <linux/interrupt.h> | ||
38 | #include <linux/err.h> | ||
39 | #include <linux/bitops.h> | ||
40 | |||
41 | #include <asm/io.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <asm/q40_master.h> | ||
44 | #include <asm/irq.h> | ||
45 | #include <asm/q40ints.h> | ||
46 | |||
47 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
48 | MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); | ||
49 | MODULE_LICENSE("GPL"); | ||
50 | |||
51 | DEFINE_SPINLOCK(q40kbd_lock); | ||
52 | static struct serio *q40kbd_port; | ||
53 | static struct platform_device *q40kbd_device; | ||
54 | |||
55 | static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
56 | { | ||
57 | unsigned long flags; | ||
58 | |||
59 | spin_lock_irqsave(&q40kbd_lock, flags); | ||
60 | |||
61 | if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) | ||
62 | serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs); | ||
63 | |||
64 | master_outb(-1, KEYBOARD_UNLOCK_REG); | ||
65 | |||
66 | spin_unlock_irqrestore(&q40kbd_lock, flags); | ||
67 | |||
68 | return IRQ_HANDLED; | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * q40kbd_flush() flushes all data that may be in the keyboard buffers | ||
73 | */ | ||
74 | |||
75 | static void q40kbd_flush(void) | ||
76 | { | ||
77 | int maxread = 100; | ||
78 | unsigned long flags; | ||
79 | |||
80 | spin_lock_irqsave(&q40kbd_lock, flags); | ||
81 | |||
82 | while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) | ||
83 | master_inb(KEYCODE_REG); | ||
84 | |||
85 | spin_unlock_irqrestore(&q40kbd_lock, flags); | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * q40kbd_open() is called when a port is open by the higher layer. | ||
90 | * It allocates the interrupt and enables in in the chip. | ||
91 | */ | ||
92 | |||
93 | static int q40kbd_open(struct serio *port) | ||
94 | { | ||
95 | q40kbd_flush(); | ||
96 | |||
97 | if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) { | ||
98 | printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD); | ||
99 | return -1; | ||
100 | } | ||
101 | |||
102 | /* off we go */ | ||
103 | master_outb(-1, KEYBOARD_UNLOCK_REG); | ||
104 | master_outb(1, KEY_IRQ_ENABLE_REG); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void q40kbd_close(struct serio *port) | ||
110 | { | ||
111 | master_outb(0, KEY_IRQ_ENABLE_REG); | ||
112 | master_outb(-1, KEYBOARD_UNLOCK_REG); | ||
113 | free_irq(Q40_IRQ_KEYBOARD, NULL); | ||
114 | |||
115 | q40kbd_flush(); | ||
116 | } | ||
117 | |||
118 | static struct serio * __init q40kbd_allocate_port(void) | ||
119 | { | ||
120 | struct serio *serio; | ||
121 | |||
122 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
123 | if (serio) { | ||
124 | memset(serio, 0, sizeof(struct serio)); | ||
125 | serio->id.type = SERIO_8042; | ||
126 | serio->open = q40kbd_open; | ||
127 | serio->close = q40kbd_close; | ||
128 | serio->dev.parent = &q40kbd_device->dev; | ||
129 | strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name)); | ||
130 | strlcpy(serio->phys, "Q40", sizeof(serio->phys)); | ||
131 | } | ||
132 | |||
133 | return serio; | ||
134 | } | ||
135 | |||
136 | static int __init q40kbd_init(void) | ||
137 | { | ||
138 | if (!MACH_IS_Q40) | ||
139 | return -EIO; | ||
140 | |||
141 | q40kbd_device = platform_device_register_simple("q40kbd", -1, NULL, 0); | ||
142 | if (IS_ERR(q40kbd_device)) | ||
143 | return PTR_ERR(q40kbd_device); | ||
144 | |||
145 | if (!(q40kbd_port = q40kbd_allocate_port())) { | ||
146 | platform_device_unregister(q40kbd_device); | ||
147 | return -ENOMEM; | ||
148 | } | ||
149 | |||
150 | serio_register_port(q40kbd_port); | ||
151 | printk(KERN_INFO "serio: Q40 kbd registered\n"); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static void __exit q40kbd_exit(void) | ||
157 | { | ||
158 | serio_unregister_port(q40kbd_port); | ||
159 | platform_device_unregister(q40kbd_device); | ||
160 | } | ||
161 | |||
162 | module_init(q40kbd_init); | ||
163 | module_exit(q40kbd_exit); | ||
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c new file mode 100644 index 000000000000..106f5eefd89a --- /dev/null +++ b/drivers/input/serio/rpckbd.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * $Id: rpckbd.c,v 1.7 2001/09/25 10:12:07 vojtech Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
5 | * Copyright (c) 2002 Russell King | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | * Should you need to contact me, the author, you can do so either by | ||
28 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
30 | */ | ||
31 | |||
32 | #include <linux/module.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/serio.h> | ||
36 | #include <linux/err.h> | ||
37 | |||
38 | #include <asm/irq.h> | ||
39 | #include <asm/hardware.h> | ||
40 | #include <asm/io.h> | ||
41 | #include <asm/hardware/iomd.h> | ||
42 | #include <asm/system.h> | ||
43 | |||
44 | MODULE_AUTHOR("Vojtech Pavlik, Russell King"); | ||
45 | MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | |||
48 | static int rpckbd_write(struct serio *port, unsigned char val) | ||
49 | { | ||
50 | while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) | ||
51 | cpu_relax(); | ||
52 | |||
53 | iomd_writeb(val, IOMD_KARTTX); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static irqreturn_t rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs) | ||
59 | { | ||
60 | struct serio *port = dev_id; | ||
61 | unsigned int byte; | ||
62 | int handled = IRQ_NONE; | ||
63 | |||
64 | while (iomd_readb(IOMD_KCTRL) & (1 << 5)) { | ||
65 | byte = iomd_readb(IOMD_KARTRX); | ||
66 | |||
67 | serio_interrupt(port, byte, 0, regs); | ||
68 | handled = IRQ_HANDLED; | ||
69 | } | ||
70 | return handled; | ||
71 | } | ||
72 | |||
73 | static irqreturn_t rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs) | ||
74 | { | ||
75 | return IRQ_HANDLED; | ||
76 | } | ||
77 | |||
78 | static int rpckbd_open(struct serio *port) | ||
79 | { | ||
80 | /* Reset the keyboard state machine. */ | ||
81 | iomd_writeb(0, IOMD_KCTRL); | ||
82 | iomd_writeb(8, IOMD_KCTRL); | ||
83 | iomd_readb(IOMD_KARTRX); | ||
84 | |||
85 | if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", port) != 0) { | ||
86 | printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n"); | ||
87 | return -EBUSY; | ||
88 | } | ||
89 | |||
90 | if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) { | ||
91 | printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n"); | ||
92 | free_irq(IRQ_KEYBOARDRX, NULL); | ||
93 | return -EBUSY; | ||
94 | } | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static void rpckbd_close(struct serio *port) | ||
100 | { | ||
101 | free_irq(IRQ_KEYBOARDRX, port); | ||
102 | free_irq(IRQ_KEYBOARDTX, port); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Allocate and initialize serio structure for subsequent registration | ||
107 | * with serio core. | ||
108 | */ | ||
109 | static int __devinit rpckbd_probe(struct device *dev) | ||
110 | { | ||
111 | struct serio *serio; | ||
112 | |||
113 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
114 | if (!serio) | ||
115 | return -ENOMEM; | ||
116 | |||
117 | memset(serio, 0, sizeof(struct serio)); | ||
118 | serio->id.type = SERIO_8042; | ||
119 | serio->write = rpckbd_write; | ||
120 | serio->open = rpckbd_open; | ||
121 | serio->close = rpckbd_close; | ||
122 | serio->dev.parent = dev; | ||
123 | strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name)); | ||
124 | strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys)); | ||
125 | |||
126 | dev_set_drvdata(dev, serio); | ||
127 | serio_register_port(serio); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int __devexit rpckbd_remove(struct device *dev) | ||
132 | { | ||
133 | struct serio *serio = dev_get_drvdata(dev); | ||
134 | serio_unregister_port(serio); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static struct device_driver rpckbd_driver = { | ||
139 | .name = "kart", | ||
140 | .bus = &platform_bus_type, | ||
141 | .probe = rpckbd_probe, | ||
142 | .remove = __devexit_p(rpckbd_remove), | ||
143 | }; | ||
144 | |||
145 | static int __init rpckbd_init(void) | ||
146 | { | ||
147 | return driver_register(&rpckbd_driver); | ||
148 | } | ||
149 | |||
150 | static void __exit rpckbd_exit(void) | ||
151 | { | ||
152 | driver_unregister(&rpckbd_driver); | ||
153 | } | ||
154 | |||
155 | module_init(rpckbd_init); | ||
156 | module_exit(rpckbd_exit); | ||
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c new file mode 100644 index 000000000000..3f0df3330fb2 --- /dev/null +++ b/drivers/input/serio/sa1111ps2.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /* | ||
2 | * linux/drivers/input/serio/sa1111ps2.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License. | ||
9 | */ | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/input.h> | ||
13 | #include <linux/serio.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/ioport.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include <asm/irq.h> | ||
24 | #include <asm/system.h> | ||
25 | |||
26 | #include <asm/hardware/sa1111.h> | ||
27 | |||
28 | struct ps2if { | ||
29 | struct serio *io; | ||
30 | struct sa1111_dev *dev; | ||
31 | void __iomem *base; | ||
32 | unsigned int open; | ||
33 | spinlock_t lock; | ||
34 | unsigned int head; | ||
35 | unsigned int tail; | ||
36 | unsigned char buf[4]; | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * Read all bytes waiting in the PS2 port. There should be | ||
41 | * at the most one, but we loop for safety. If there was a | ||
42 | * framing error, we have to manually clear the status. | ||
43 | */ | ||
44 | static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs) | ||
45 | { | ||
46 | struct ps2if *ps2if = dev_id; | ||
47 | unsigned int scancode, flag, status; | ||
48 | |||
49 | status = sa1111_readl(ps2if->base + SA1111_PS2STAT); | ||
50 | while (status & PS2STAT_RXF) { | ||
51 | if (status & PS2STAT_STP) | ||
52 | sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT); | ||
53 | |||
54 | flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) | | ||
55 | (status & PS2STAT_RXP ? 0 : SERIO_PARITY); | ||
56 | |||
57 | scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff; | ||
58 | |||
59 | if (hweight8(scancode) & 1) | ||
60 | flag ^= SERIO_PARITY; | ||
61 | |||
62 | serio_interrupt(ps2if->io, scancode, flag, regs); | ||
63 | |||
64 | status = sa1111_readl(ps2if->base + SA1111_PS2STAT); | ||
65 | } | ||
66 | |||
67 | return IRQ_HANDLED; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * Completion of ps2 write | ||
72 | */ | ||
73 | static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs) | ||
74 | { | ||
75 | struct ps2if *ps2if = dev_id; | ||
76 | unsigned int status; | ||
77 | |||
78 | spin_lock(&ps2if->lock); | ||
79 | status = sa1111_readl(ps2if->base + SA1111_PS2STAT); | ||
80 | if (ps2if->head == ps2if->tail) { | ||
81 | disable_irq(irq); | ||
82 | /* done */ | ||
83 | } else if (status & PS2STAT_TXE) { | ||
84 | sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA); | ||
85 | ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1); | ||
86 | } | ||
87 | spin_unlock(&ps2if->lock); | ||
88 | |||
89 | return IRQ_HANDLED; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Write a byte to the PS2 port. We have to wait for the | ||
94 | * port to indicate that the transmitter is empty. | ||
95 | */ | ||
96 | static int ps2_write(struct serio *io, unsigned char val) | ||
97 | { | ||
98 | struct ps2if *ps2if = io->port_data; | ||
99 | unsigned long flags; | ||
100 | unsigned int head; | ||
101 | |||
102 | spin_lock_irqsave(&ps2if->lock, flags); | ||
103 | |||
104 | /* | ||
105 | * If the TX register is empty, we can go straight out. | ||
106 | */ | ||
107 | if (sa1111_readl(ps2if->base + SA1111_PS2STAT) & PS2STAT_TXE) { | ||
108 | sa1111_writel(val, ps2if->base + SA1111_PS2DATA); | ||
109 | } else { | ||
110 | if (ps2if->head == ps2if->tail) | ||
111 | enable_irq(ps2if->dev->irq[1]); | ||
112 | head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1); | ||
113 | if (head != ps2if->tail) { | ||
114 | ps2if->buf[ps2if->head] = val; | ||
115 | ps2if->head = head; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | spin_unlock_irqrestore(&ps2if->lock, flags); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int ps2_open(struct serio *io) | ||
124 | { | ||
125 | struct ps2if *ps2if = io->port_data; | ||
126 | int ret; | ||
127 | |||
128 | sa1111_enable_device(ps2if->dev); | ||
129 | |||
130 | ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0, | ||
131 | SA1111_DRIVER_NAME(ps2if->dev), ps2if); | ||
132 | if (ret) { | ||
133 | printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", | ||
134 | ps2if->dev->irq[0], ret); | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | ret = request_irq(ps2if->dev->irq[1], ps2_txint, 0, | ||
139 | SA1111_DRIVER_NAME(ps2if->dev), ps2if); | ||
140 | if (ret) { | ||
141 | printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", | ||
142 | ps2if->dev->irq[1], ret); | ||
143 | free_irq(ps2if->dev->irq[0], ps2if); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | ps2if->open = 1; | ||
148 | |||
149 | enable_irq_wake(ps2if->dev->irq[0]); | ||
150 | |||
151 | sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static void ps2_close(struct serio *io) | ||
156 | { | ||
157 | struct ps2if *ps2if = io->port_data; | ||
158 | |||
159 | sa1111_writel(0, ps2if->base + SA1111_PS2CR); | ||
160 | |||
161 | disable_irq_wake(ps2if->dev->irq[0]); | ||
162 | |||
163 | ps2if->open = 0; | ||
164 | |||
165 | free_irq(ps2if->dev->irq[1], ps2if); | ||
166 | free_irq(ps2if->dev->irq[0], ps2if); | ||
167 | |||
168 | sa1111_disable_device(ps2if->dev); | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Clear the input buffer. | ||
173 | */ | ||
174 | static void __init ps2_clear_input(struct ps2if *ps2if) | ||
175 | { | ||
176 | int maxread = 100; | ||
177 | |||
178 | while (maxread--) { | ||
179 | if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff) | ||
180 | break; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static inline unsigned int | ||
185 | ps2_test_one(struct ps2if *ps2if, unsigned int mask) | ||
186 | { | ||
187 | unsigned int val; | ||
188 | |||
189 | sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR); | ||
190 | |||
191 | udelay(2); | ||
192 | |||
193 | val = sa1111_readl(ps2if->base + SA1111_PS2STAT); | ||
194 | return val & (PS2STAT_KBC | PS2STAT_KBD); | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Test the keyboard interface. We basically check to make sure that | ||
199 | * we can drive each line to the keyboard independently of each other. | ||
200 | */ | ||
201 | static int __init ps2_test(struct ps2if *ps2if) | ||
202 | { | ||
203 | unsigned int stat; | ||
204 | int ret = 0; | ||
205 | |||
206 | stat = ps2_test_one(ps2if, PS2CR_FKC); | ||
207 | if (stat != PS2STAT_KBD) { | ||
208 | printk("PS/2 interface test failed[1]: %02x\n", stat); | ||
209 | ret = -ENODEV; | ||
210 | } | ||
211 | |||
212 | stat = ps2_test_one(ps2if, 0); | ||
213 | if (stat != (PS2STAT_KBC | PS2STAT_KBD)) { | ||
214 | printk("PS/2 interface test failed[2]: %02x\n", stat); | ||
215 | ret = -ENODEV; | ||
216 | } | ||
217 | |||
218 | stat = ps2_test_one(ps2if, PS2CR_FKD); | ||
219 | if (stat != PS2STAT_KBC) { | ||
220 | printk("PS/2 interface test failed[3]: %02x\n", stat); | ||
221 | ret = -ENODEV; | ||
222 | } | ||
223 | |||
224 | sa1111_writel(0, ps2if->base + SA1111_PS2CR); | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * Add one device to this driver. | ||
231 | */ | ||
232 | static int ps2_probe(struct sa1111_dev *dev) | ||
233 | { | ||
234 | struct ps2if *ps2if; | ||
235 | struct serio *serio; | ||
236 | int ret; | ||
237 | |||
238 | ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); | ||
239 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
240 | if (!ps2if || !serio) { | ||
241 | ret = -ENOMEM; | ||
242 | goto free; | ||
243 | } | ||
244 | |||
245 | memset(ps2if, 0, sizeof(struct ps2if)); | ||
246 | memset(serio, 0, sizeof(struct serio)); | ||
247 | |||
248 | serio->id.type = SERIO_8042; | ||
249 | serio->write = ps2_write; | ||
250 | serio->open = ps2_open; | ||
251 | serio->close = ps2_close; | ||
252 | strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name)); | ||
253 | strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); | ||
254 | serio->port_data = ps2if; | ||
255 | serio->dev.parent = &dev->dev; | ||
256 | ps2if->io = serio; | ||
257 | ps2if->dev = dev; | ||
258 | sa1111_set_drvdata(dev, ps2if); | ||
259 | |||
260 | spin_lock_init(&ps2if->lock); | ||
261 | |||
262 | /* | ||
263 | * Request the physical region for this PS2 port. | ||
264 | */ | ||
265 | if (!request_mem_region(dev->res.start, | ||
266 | dev->res.end - dev->res.start + 1, | ||
267 | SA1111_DRIVER_NAME(dev))) { | ||
268 | ret = -EBUSY; | ||
269 | goto free; | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Our parent device has already mapped the region. | ||
274 | */ | ||
275 | ps2if->base = dev->mapbase; | ||
276 | |||
277 | sa1111_enable_device(ps2if->dev); | ||
278 | |||
279 | /* Incoming clock is 8MHz */ | ||
280 | sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV); | ||
281 | sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT); | ||
282 | |||
283 | /* | ||
284 | * Flush any pending input. | ||
285 | */ | ||
286 | ps2_clear_input(ps2if); | ||
287 | |||
288 | /* | ||
289 | * Test the keyboard interface. | ||
290 | */ | ||
291 | ret = ps2_test(ps2if); | ||
292 | if (ret) | ||
293 | goto out; | ||
294 | |||
295 | /* | ||
296 | * Flush any pending input. | ||
297 | */ | ||
298 | ps2_clear_input(ps2if); | ||
299 | |||
300 | sa1111_disable_device(ps2if->dev); | ||
301 | serio_register_port(ps2if->io); | ||
302 | return 0; | ||
303 | |||
304 | out: | ||
305 | sa1111_disable_device(ps2if->dev); | ||
306 | release_mem_region(dev->res.start, | ||
307 | dev->res.end - dev->res.start + 1); | ||
308 | free: | ||
309 | sa1111_set_drvdata(dev, NULL); | ||
310 | kfree(ps2if); | ||
311 | kfree(serio); | ||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * Remove one device from this driver. | ||
317 | */ | ||
318 | static int ps2_remove(struct sa1111_dev *dev) | ||
319 | { | ||
320 | struct ps2if *ps2if = sa1111_get_drvdata(dev); | ||
321 | |||
322 | serio_unregister_port(ps2if->io); | ||
323 | release_mem_region(dev->res.start, | ||
324 | dev->res.end - dev->res.start + 1); | ||
325 | sa1111_set_drvdata(dev, NULL); | ||
326 | |||
327 | kfree(ps2if); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Our device driver structure | ||
334 | */ | ||
335 | static struct sa1111_driver ps2_driver = { | ||
336 | .drv = { | ||
337 | .name = "sa1111-ps2", | ||
338 | }, | ||
339 | .devid = SA1111_DEVID_PS2, | ||
340 | .probe = ps2_probe, | ||
341 | .remove = ps2_remove, | ||
342 | }; | ||
343 | |||
344 | static int __init ps2_init(void) | ||
345 | { | ||
346 | return sa1111_driver_register(&ps2_driver); | ||
347 | } | ||
348 | |||
349 | static void __exit ps2_exit(void) | ||
350 | { | ||
351 | sa1111_driver_unregister(&ps2_driver); | ||
352 | } | ||
353 | |||
354 | module_init(ps2_init); | ||
355 | module_exit(ps2_exit); | ||
356 | |||
357 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); | ||
358 | MODULE_DESCRIPTION("SA1111 PS2 controller driver"); | ||
359 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c new file mode 100644 index 000000000000..3313e2daeab0 --- /dev/null +++ b/drivers/input/serio/serio.c | |||
@@ -0,0 +1,859 @@ | |||
1 | /* | ||
2 | * The Serio abstraction module | ||
3 | * | ||
4 | * Copyright (c) 1999-2004 Vojtech Pavlik | ||
5 | * Copyright (c) 2004 Dmitry Torokhov | ||
6 | * Copyright (c) 2003 Daniele Bellucci | ||
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 <vojtech@ucw.cz>, or by paper mail: | ||
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
27 | */ | ||
28 | |||
29 | #include <linux/stddef.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/serio.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/wait.h> | ||
34 | #include <linux/completion.h> | ||
35 | #include <linux/sched.h> | ||
36 | #include <linux/smp_lock.h> | ||
37 | #include <linux/slab.h> | ||
38 | |||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
40 | MODULE_DESCRIPTION("Serio abstraction core"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | EXPORT_SYMBOL(serio_interrupt); | ||
44 | EXPORT_SYMBOL(__serio_register_port); | ||
45 | EXPORT_SYMBOL(serio_unregister_port); | ||
46 | EXPORT_SYMBOL(__serio_unregister_port_delayed); | ||
47 | EXPORT_SYMBOL(__serio_register_driver); | ||
48 | EXPORT_SYMBOL(serio_unregister_driver); | ||
49 | EXPORT_SYMBOL(serio_open); | ||
50 | EXPORT_SYMBOL(serio_close); | ||
51 | EXPORT_SYMBOL(serio_rescan); | ||
52 | EXPORT_SYMBOL(serio_reconnect); | ||
53 | |||
54 | /* | ||
55 | * serio_sem protects entire serio subsystem and is taken every time | ||
56 | * serio port or driver registrered or unregistered. | ||
57 | */ | ||
58 | static DECLARE_MUTEX(serio_sem); | ||
59 | |||
60 | static LIST_HEAD(serio_list); | ||
61 | |||
62 | static struct bus_type serio_bus = { | ||
63 | .name = "serio", | ||
64 | }; | ||
65 | |||
66 | static void serio_add_port(struct serio *serio); | ||
67 | static void serio_destroy_port(struct serio *serio); | ||
68 | static void serio_reconnect_port(struct serio *serio); | ||
69 | static void serio_disconnect_port(struct serio *serio); | ||
70 | |||
71 | static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) | ||
72 | { | ||
73 | while (ids->type || ids->proto) { | ||
74 | if ((ids->type == SERIO_ANY || ids->type == serio->id.type) && | ||
75 | (ids->proto == SERIO_ANY || ids->proto == serio->id.proto) && | ||
76 | (ids->extra == SERIO_ANY || ids->extra == serio->id.extra) && | ||
77 | (ids->id == SERIO_ANY || ids->id == serio->id.id)) | ||
78 | return 1; | ||
79 | ids++; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * Basic serio -> driver core mappings | ||
86 | */ | ||
87 | |||
88 | static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) | ||
89 | { | ||
90 | down_write(&serio_bus.subsys.rwsem); | ||
91 | |||
92 | if (serio_match_port(drv->id_table, serio)) { | ||
93 | serio->dev.driver = &drv->driver; | ||
94 | if (drv->connect(serio, drv)) { | ||
95 | serio->dev.driver = NULL; | ||
96 | goto out; | ||
97 | } | ||
98 | device_bind_driver(&serio->dev); | ||
99 | } | ||
100 | out: | ||
101 | up_write(&serio_bus.subsys.rwsem); | ||
102 | } | ||
103 | |||
104 | static void serio_release_driver(struct serio *serio) | ||
105 | { | ||
106 | down_write(&serio_bus.subsys.rwsem); | ||
107 | device_release_driver(&serio->dev); | ||
108 | up_write(&serio_bus.subsys.rwsem); | ||
109 | } | ||
110 | |||
111 | static void serio_find_driver(struct serio *serio) | ||
112 | { | ||
113 | down_write(&serio_bus.subsys.rwsem); | ||
114 | device_attach(&serio->dev); | ||
115 | up_write(&serio_bus.subsys.rwsem); | ||
116 | } | ||
117 | |||
118 | |||
119 | /* | ||
120 | * Serio event processing. | ||
121 | */ | ||
122 | |||
123 | enum serio_event_type { | ||
124 | SERIO_RESCAN, | ||
125 | SERIO_RECONNECT, | ||
126 | SERIO_REGISTER_PORT, | ||
127 | SERIO_UNREGISTER_PORT, | ||
128 | SERIO_REGISTER_DRIVER, | ||
129 | }; | ||
130 | |||
131 | struct serio_event { | ||
132 | enum serio_event_type type; | ||
133 | void *object; | ||
134 | struct module *owner; | ||
135 | struct list_head node; | ||
136 | }; | ||
137 | |||
138 | static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ | ||
139 | static LIST_HEAD(serio_event_list); | ||
140 | static DECLARE_WAIT_QUEUE_HEAD(serio_wait); | ||
141 | static DECLARE_COMPLETION(serio_exited); | ||
142 | static int serio_pid; | ||
143 | |||
144 | static void serio_queue_event(void *object, struct module *owner, | ||
145 | enum serio_event_type event_type) | ||
146 | { | ||
147 | unsigned long flags; | ||
148 | struct serio_event *event; | ||
149 | |||
150 | spin_lock_irqsave(&serio_event_lock, flags); | ||
151 | |||
152 | /* | ||
153 | * Scan event list for the other events for the same serio port, | ||
154 | * starting with the most recent one. If event is the same we | ||
155 | * do not need add new one. If event is of different type we | ||
156 | * need to add this event and should not look further because | ||
157 | * we need to preseve sequence of distinct events. | ||
158 | */ | ||
159 | list_for_each_entry_reverse(event, &serio_event_list, node) { | ||
160 | if (event->object == object) { | ||
161 | if (event->type == event_type) | ||
162 | goto out; | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { | ||
168 | if (!try_module_get(owner)) { | ||
169 | printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type); | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | event->type = event_type; | ||
174 | event->object = object; | ||
175 | event->owner = owner; | ||
176 | |||
177 | list_add_tail(&event->node, &serio_event_list); | ||
178 | wake_up(&serio_wait); | ||
179 | } else { | ||
180 | printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type); | ||
181 | } | ||
182 | out: | ||
183 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
184 | } | ||
185 | |||
186 | static void serio_free_event(struct serio_event *event) | ||
187 | { | ||
188 | module_put(event->owner); | ||
189 | kfree(event); | ||
190 | } | ||
191 | |||
192 | static void serio_remove_duplicate_events(struct serio_event *event) | ||
193 | { | ||
194 | struct list_head *node, *next; | ||
195 | struct serio_event *e; | ||
196 | unsigned long flags; | ||
197 | |||
198 | spin_lock_irqsave(&serio_event_lock, flags); | ||
199 | |||
200 | list_for_each_safe(node, next, &serio_event_list) { | ||
201 | e = list_entry(node, struct serio_event, node); | ||
202 | if (event->object == e->object) { | ||
203 | /* | ||
204 | * If this event is of different type we should not | ||
205 | * look further - we only suppress duplicate events | ||
206 | * that were sent back-to-back. | ||
207 | */ | ||
208 | if (event->type != e->type) | ||
209 | break; | ||
210 | |||
211 | list_del_init(node); | ||
212 | serio_free_event(e); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
217 | } | ||
218 | |||
219 | |||
220 | static struct serio_event *serio_get_event(void) | ||
221 | { | ||
222 | struct serio_event *event; | ||
223 | struct list_head *node; | ||
224 | unsigned long flags; | ||
225 | |||
226 | spin_lock_irqsave(&serio_event_lock, flags); | ||
227 | |||
228 | if (list_empty(&serio_event_list)) { | ||
229 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
230 | return NULL; | ||
231 | } | ||
232 | |||
233 | node = serio_event_list.next; | ||
234 | event = list_entry(node, struct serio_event, node); | ||
235 | list_del_init(node); | ||
236 | |||
237 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
238 | |||
239 | return event; | ||
240 | } | ||
241 | |||
242 | static void serio_handle_events(void) | ||
243 | { | ||
244 | struct serio_event *event; | ||
245 | struct serio_driver *serio_drv; | ||
246 | |||
247 | down(&serio_sem); | ||
248 | |||
249 | while ((event = serio_get_event())) { | ||
250 | |||
251 | switch (event->type) { | ||
252 | case SERIO_REGISTER_PORT: | ||
253 | serio_add_port(event->object); | ||
254 | break; | ||
255 | |||
256 | case SERIO_UNREGISTER_PORT: | ||
257 | serio_disconnect_port(event->object); | ||
258 | serio_destroy_port(event->object); | ||
259 | break; | ||
260 | |||
261 | case SERIO_RECONNECT: | ||
262 | serio_reconnect_port(event->object); | ||
263 | break; | ||
264 | |||
265 | case SERIO_RESCAN: | ||
266 | serio_disconnect_port(event->object); | ||
267 | serio_find_driver(event->object); | ||
268 | break; | ||
269 | |||
270 | case SERIO_REGISTER_DRIVER: | ||
271 | serio_drv = event->object; | ||
272 | driver_register(&serio_drv->driver); | ||
273 | break; | ||
274 | |||
275 | default: | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | serio_remove_duplicate_events(event); | ||
280 | serio_free_event(event); | ||
281 | } | ||
282 | |||
283 | up(&serio_sem); | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * Remove all events that have been submitted for a given serio port. | ||
288 | */ | ||
289 | static void serio_remove_pending_events(struct serio *serio) | ||
290 | { | ||
291 | struct list_head *node, *next; | ||
292 | struct serio_event *event; | ||
293 | unsigned long flags; | ||
294 | |||
295 | spin_lock_irqsave(&serio_event_lock, flags); | ||
296 | |||
297 | list_for_each_safe(node, next, &serio_event_list) { | ||
298 | event = list_entry(node, struct serio_event, node); | ||
299 | if (event->object == serio) { | ||
300 | list_del_init(node); | ||
301 | serio_free_event(event); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
306 | } | ||
307 | |||
308 | /* | ||
309 | * Destroy child serio port (if any) that has not been fully registered yet. | ||
310 | * | ||
311 | * Note that we rely on the fact that port can have only one child and therefore | ||
312 | * only one child registration request can be pending. Additionally, children | ||
313 | * are registered by driver's connect() handler so there can't be a grandchild | ||
314 | * pending registration together with a child. | ||
315 | */ | ||
316 | static struct serio *serio_get_pending_child(struct serio *parent) | ||
317 | { | ||
318 | struct serio_event *event; | ||
319 | struct serio *serio, *child = NULL; | ||
320 | unsigned long flags; | ||
321 | |||
322 | spin_lock_irqsave(&serio_event_lock, flags); | ||
323 | |||
324 | list_for_each_entry(event, &serio_event_list, node) { | ||
325 | if (event->type == SERIO_REGISTER_PORT) { | ||
326 | serio = event->object; | ||
327 | if (serio->parent == parent) { | ||
328 | child = serio; | ||
329 | break; | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | |||
334 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
335 | return child; | ||
336 | } | ||
337 | |||
338 | static int serio_thread(void *nothing) | ||
339 | { | ||
340 | lock_kernel(); | ||
341 | daemonize("kseriod"); | ||
342 | allow_signal(SIGTERM); | ||
343 | |||
344 | do { | ||
345 | serio_handle_events(); | ||
346 | wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); | ||
347 | try_to_freeze(PF_FREEZE); | ||
348 | } while (!signal_pending(current)); | ||
349 | |||
350 | printk(KERN_DEBUG "serio: kseriod exiting\n"); | ||
351 | |||
352 | unlock_kernel(); | ||
353 | complete_and_exit(&serio_exited, 0); | ||
354 | } | ||
355 | |||
356 | |||
357 | /* | ||
358 | * Serio port operations | ||
359 | */ | ||
360 | |||
361 | static ssize_t serio_show_description(struct device *dev, char *buf) | ||
362 | { | ||
363 | struct serio *serio = to_serio_port(dev); | ||
364 | return sprintf(buf, "%s\n", serio->name); | ||
365 | } | ||
366 | |||
367 | static ssize_t serio_show_id_type(struct device *dev, char *buf) | ||
368 | { | ||
369 | struct serio *serio = to_serio_port(dev); | ||
370 | return sprintf(buf, "%02x\n", serio->id.type); | ||
371 | } | ||
372 | |||
373 | static ssize_t serio_show_id_proto(struct device *dev, char *buf) | ||
374 | { | ||
375 | struct serio *serio = to_serio_port(dev); | ||
376 | return sprintf(buf, "%02x\n", serio->id.proto); | ||
377 | } | ||
378 | |||
379 | static ssize_t serio_show_id_id(struct device *dev, char *buf) | ||
380 | { | ||
381 | struct serio *serio = to_serio_port(dev); | ||
382 | return sprintf(buf, "%02x\n", serio->id.id); | ||
383 | } | ||
384 | |||
385 | static ssize_t serio_show_id_extra(struct device *dev, char *buf) | ||
386 | { | ||
387 | struct serio *serio = to_serio_port(dev); | ||
388 | return sprintf(buf, "%02x\n", serio->id.extra); | ||
389 | } | ||
390 | |||
391 | static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) | ||
392 | { | ||
393 | struct serio *serio = to_serio_port(dev); | ||
394 | struct device_driver *drv; | ||
395 | int retval; | ||
396 | |||
397 | retval = down_interruptible(&serio_sem); | ||
398 | if (retval) | ||
399 | return retval; | ||
400 | |||
401 | retval = count; | ||
402 | if (!strncmp(buf, "none", count)) { | ||
403 | serio_disconnect_port(serio); | ||
404 | } else if (!strncmp(buf, "reconnect", count)) { | ||
405 | serio_reconnect_port(serio); | ||
406 | } else if (!strncmp(buf, "rescan", count)) { | ||
407 | serio_disconnect_port(serio); | ||
408 | serio_find_driver(serio); | ||
409 | } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { | ||
410 | serio_disconnect_port(serio); | ||
411 | serio_bind_driver(serio, to_serio_driver(drv)); | ||
412 | put_driver(drv); | ||
413 | } else { | ||
414 | retval = -EINVAL; | ||
415 | } | ||
416 | |||
417 | up(&serio_sem); | ||
418 | |||
419 | return retval; | ||
420 | } | ||
421 | |||
422 | static ssize_t serio_show_bind_mode(struct device *dev, char *buf) | ||
423 | { | ||
424 | struct serio *serio = to_serio_port(dev); | ||
425 | return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto"); | ||
426 | } | ||
427 | |||
428 | static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t count) | ||
429 | { | ||
430 | struct serio *serio = to_serio_port(dev); | ||
431 | int retval; | ||
432 | |||
433 | retval = count; | ||
434 | if (!strncmp(buf, "manual", count)) { | ||
435 | serio->manual_bind = 1; | ||
436 | } else if (!strncmp(buf, "auto", count)) { | ||
437 | serio->manual_bind = 0; | ||
438 | } else { | ||
439 | retval = -EINVAL; | ||
440 | } | ||
441 | |||
442 | return retval; | ||
443 | } | ||
444 | |||
445 | static struct device_attribute serio_device_attrs[] = { | ||
446 | __ATTR(description, S_IRUGO, serio_show_description, NULL), | ||
447 | __ATTR(id_type, S_IRUGO, serio_show_id_type, NULL), | ||
448 | __ATTR(id_proto, S_IRUGO, serio_show_id_proto, NULL), | ||
449 | __ATTR(id_id, S_IRUGO, serio_show_id_id, NULL), | ||
450 | __ATTR(id_extra, S_IRUGO, serio_show_id_extra, NULL), | ||
451 | __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver), | ||
452 | __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), | ||
453 | __ATTR_NULL | ||
454 | }; | ||
455 | |||
456 | |||
457 | static void serio_release_port(struct device *dev) | ||
458 | { | ||
459 | struct serio *serio = to_serio_port(dev); | ||
460 | |||
461 | kfree(serio); | ||
462 | module_put(THIS_MODULE); | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * Prepare serio port for registration. | ||
467 | */ | ||
468 | static void serio_init_port(struct serio *serio) | ||
469 | { | ||
470 | static atomic_t serio_no = ATOMIC_INIT(0); | ||
471 | |||
472 | __module_get(THIS_MODULE); | ||
473 | |||
474 | spin_lock_init(&serio->lock); | ||
475 | init_MUTEX(&serio->drv_sem); | ||
476 | device_initialize(&serio->dev); | ||
477 | snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), | ||
478 | "serio%ld", (long)atomic_inc_return(&serio_no) - 1); | ||
479 | serio->dev.bus = &serio_bus; | ||
480 | serio->dev.release = serio_release_port; | ||
481 | if (serio->parent) | ||
482 | serio->dev.parent = &serio->parent->dev; | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * Complete serio port registration. | ||
487 | * Driver core will attempt to find appropriate driver for the port. | ||
488 | */ | ||
489 | static void serio_add_port(struct serio *serio) | ||
490 | { | ||
491 | if (serio->parent) { | ||
492 | serio_pause_rx(serio->parent); | ||
493 | serio->parent->child = serio; | ||
494 | serio_continue_rx(serio->parent); | ||
495 | } | ||
496 | |||
497 | list_add_tail(&serio->node, &serio_list); | ||
498 | if (serio->start) | ||
499 | serio->start(serio); | ||
500 | device_add(&serio->dev); | ||
501 | serio->registered = 1; | ||
502 | } | ||
503 | |||
504 | /* | ||
505 | * serio_destroy_port() completes deregistration process and removes | ||
506 | * port from the system | ||
507 | */ | ||
508 | static void serio_destroy_port(struct serio *serio) | ||
509 | { | ||
510 | struct serio *child; | ||
511 | |||
512 | child = serio_get_pending_child(serio); | ||
513 | if (child) { | ||
514 | serio_remove_pending_events(child); | ||
515 | put_device(&child->dev); | ||
516 | } | ||
517 | |||
518 | if (serio->stop) | ||
519 | serio->stop(serio); | ||
520 | |||
521 | if (serio->parent) { | ||
522 | serio_pause_rx(serio->parent); | ||
523 | serio->parent->child = NULL; | ||
524 | serio_continue_rx(serio->parent); | ||
525 | serio->parent = NULL; | ||
526 | } | ||
527 | |||
528 | if (serio->registered) { | ||
529 | device_del(&serio->dev); | ||
530 | list_del_init(&serio->node); | ||
531 | serio->registered = 0; | ||
532 | } | ||
533 | |||
534 | serio_remove_pending_events(serio); | ||
535 | put_device(&serio->dev); | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * Reconnect serio port and all its children (re-initialize attached devices) | ||
540 | */ | ||
541 | static void serio_reconnect_port(struct serio *serio) | ||
542 | { | ||
543 | do { | ||
544 | if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { | ||
545 | serio_disconnect_port(serio); | ||
546 | serio_find_driver(serio); | ||
547 | /* Ok, old children are now gone, we are done */ | ||
548 | break; | ||
549 | } | ||
550 | serio = serio->child; | ||
551 | } while (serio); | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * serio_disconnect_port() unbinds a port from its driver. As a side effect | ||
556 | * all child ports are unbound and destroyed. | ||
557 | */ | ||
558 | static void serio_disconnect_port(struct serio *serio) | ||
559 | { | ||
560 | struct serio *s, *parent; | ||
561 | |||
562 | if (serio->child) { | ||
563 | /* | ||
564 | * Children ports should be disconnected and destroyed | ||
565 | * first, staring with the leaf one, since we don't want | ||
566 | * to do recursion | ||
567 | */ | ||
568 | for (s = serio; s->child; s = s->child) | ||
569 | /* empty */; | ||
570 | |||
571 | do { | ||
572 | parent = s->parent; | ||
573 | |||
574 | serio_release_driver(s); | ||
575 | serio_destroy_port(s); | ||
576 | } while ((s = parent) != serio); | ||
577 | } | ||
578 | |||
579 | /* | ||
580 | * Ok, no children left, now disconnect this port | ||
581 | */ | ||
582 | serio_release_driver(serio); | ||
583 | } | ||
584 | |||
585 | void serio_rescan(struct serio *serio) | ||
586 | { | ||
587 | serio_queue_event(serio, NULL, SERIO_RESCAN); | ||
588 | } | ||
589 | |||
590 | void serio_reconnect(struct serio *serio) | ||
591 | { | ||
592 | serio_queue_event(serio, NULL, SERIO_RECONNECT); | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * Submits register request to kseriod for subsequent execution. | ||
597 | * Note that port registration is always asynchronous. | ||
598 | */ | ||
599 | void __serio_register_port(struct serio *serio, struct module *owner) | ||
600 | { | ||
601 | serio_init_port(serio); | ||
602 | serio_queue_event(serio, owner, SERIO_REGISTER_PORT); | ||
603 | } | ||
604 | |||
605 | /* | ||
606 | * Synchronously unregisters serio port. | ||
607 | */ | ||
608 | void serio_unregister_port(struct serio *serio) | ||
609 | { | ||
610 | down(&serio_sem); | ||
611 | serio_disconnect_port(serio); | ||
612 | serio_destroy_port(serio); | ||
613 | up(&serio_sem); | ||
614 | } | ||
615 | |||
616 | /* | ||
617 | * Submits register request to kseriod for subsequent execution. | ||
618 | * Can be used when it is not obvious whether the serio_sem is | ||
619 | * taken or not and when delayed execution is feasible. | ||
620 | */ | ||
621 | void __serio_unregister_port_delayed(struct serio *serio, struct module *owner) | ||
622 | { | ||
623 | serio_queue_event(serio, owner, SERIO_UNREGISTER_PORT); | ||
624 | } | ||
625 | |||
626 | |||
627 | /* | ||
628 | * Serio driver operations | ||
629 | */ | ||
630 | |||
631 | static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf) | ||
632 | { | ||
633 | struct serio_driver *driver = to_serio_driver(drv); | ||
634 | return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); | ||
635 | } | ||
636 | |||
637 | static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf) | ||
638 | { | ||
639 | struct serio_driver *serio_drv = to_serio_driver(drv); | ||
640 | return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); | ||
641 | } | ||
642 | |||
643 | static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count) | ||
644 | { | ||
645 | struct serio_driver *serio_drv = to_serio_driver(drv); | ||
646 | int retval; | ||
647 | |||
648 | retval = count; | ||
649 | if (!strncmp(buf, "manual", count)) { | ||
650 | serio_drv->manual_bind = 1; | ||
651 | } else if (!strncmp(buf, "auto", count)) { | ||
652 | serio_drv->manual_bind = 0; | ||
653 | } else { | ||
654 | retval = -EINVAL; | ||
655 | } | ||
656 | |||
657 | return retval; | ||
658 | } | ||
659 | |||
660 | |||
661 | static struct driver_attribute serio_driver_attrs[] = { | ||
662 | __ATTR(description, S_IRUGO, serio_driver_show_description, NULL), | ||
663 | __ATTR(bind_mode, S_IWUSR | S_IRUGO, | ||
664 | serio_driver_show_bind_mode, serio_driver_set_bind_mode), | ||
665 | __ATTR_NULL | ||
666 | }; | ||
667 | |||
668 | static int serio_driver_probe(struct device *dev) | ||
669 | { | ||
670 | struct serio *serio = to_serio_port(dev); | ||
671 | struct serio_driver *drv = to_serio_driver(dev->driver); | ||
672 | |||
673 | return drv->connect(serio, drv); | ||
674 | } | ||
675 | |||
676 | static int serio_driver_remove(struct device *dev) | ||
677 | { | ||
678 | struct serio *serio = to_serio_port(dev); | ||
679 | struct serio_driver *drv = to_serio_driver(dev->driver); | ||
680 | |||
681 | drv->disconnect(serio); | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | void __serio_register_driver(struct serio_driver *drv, struct module *owner) | ||
686 | { | ||
687 | drv->driver.bus = &serio_bus; | ||
688 | drv->driver.probe = serio_driver_probe; | ||
689 | drv->driver.remove = serio_driver_remove; | ||
690 | |||
691 | serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER); | ||
692 | } | ||
693 | |||
694 | void serio_unregister_driver(struct serio_driver *drv) | ||
695 | { | ||
696 | struct serio *serio; | ||
697 | |||
698 | down(&serio_sem); | ||
699 | drv->manual_bind = 1; /* so serio_find_driver ignores it */ | ||
700 | |||
701 | start_over: | ||
702 | list_for_each_entry(serio, &serio_list, node) { | ||
703 | if (serio->drv == drv) { | ||
704 | serio_disconnect_port(serio); | ||
705 | serio_find_driver(serio); | ||
706 | /* we could've deleted some ports, restart */ | ||
707 | goto start_over; | ||
708 | } | ||
709 | } | ||
710 | |||
711 | driver_unregister(&drv->driver); | ||
712 | up(&serio_sem); | ||
713 | } | ||
714 | |||
715 | static void serio_set_drv(struct serio *serio, struct serio_driver *drv) | ||
716 | { | ||
717 | down(&serio->drv_sem); | ||
718 | serio_pause_rx(serio); | ||
719 | serio->drv = drv; | ||
720 | serio_continue_rx(serio); | ||
721 | up(&serio->drv_sem); | ||
722 | } | ||
723 | |||
724 | static int serio_bus_match(struct device *dev, struct device_driver *drv) | ||
725 | { | ||
726 | struct serio *serio = to_serio_port(dev); | ||
727 | struct serio_driver *serio_drv = to_serio_driver(drv); | ||
728 | |||
729 | if (serio->manual_bind || serio_drv->manual_bind) | ||
730 | return 0; | ||
731 | |||
732 | return serio_match_port(serio_drv->id_table, serio); | ||
733 | } | ||
734 | |||
735 | #ifdef CONFIG_HOTPLUG | ||
736 | |||
737 | #define PUT_ENVP(fmt, val) \ | ||
738 | do { \ | ||
739 | envp[i++] = buffer; \ | ||
740 | length += snprintf(buffer, buffer_size - length, fmt, val); \ | ||
741 | if (buffer_size - length <= 0 || i >= num_envp) \ | ||
742 | return -ENOMEM; \ | ||
743 | length++; \ | ||
744 | buffer += length; \ | ||
745 | } while (0) | ||
746 | static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | ||
747 | { | ||
748 | struct serio *serio; | ||
749 | int i = 0; | ||
750 | int length = 0; | ||
751 | |||
752 | if (!dev) | ||
753 | return -ENODEV; | ||
754 | |||
755 | serio = to_serio_port(dev); | ||
756 | |||
757 | PUT_ENVP("SERIO_TYPE=%02x", serio->id.type); | ||
758 | PUT_ENVP("SERIO_PROTO=%02x", serio->id.proto); | ||
759 | PUT_ENVP("SERIO_ID=%02x", serio->id.id); | ||
760 | PUT_ENVP("SERIO_EXTRA=%02x", serio->id.extra); | ||
761 | |||
762 | envp[i] = NULL; | ||
763 | |||
764 | return 0; | ||
765 | } | ||
766 | #undef PUT_ENVP | ||
767 | |||
768 | #else | ||
769 | |||
770 | static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | ||
771 | { | ||
772 | return -ENODEV; | ||
773 | } | ||
774 | |||
775 | #endif /* CONFIG_HOTPLUG */ | ||
776 | |||
777 | static int serio_resume(struct device *dev) | ||
778 | { | ||
779 | struct serio *serio = to_serio_port(dev); | ||
780 | |||
781 | if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { | ||
782 | serio_disconnect_port(serio); | ||
783 | /* | ||
784 | * Driver re-probing can take a while, so better let kseriod | ||
785 | * deal with it. | ||
786 | */ | ||
787 | serio_rescan(serio); | ||
788 | } | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | /* called from serio_driver->connect/disconnect methods under serio_sem */ | ||
794 | int serio_open(struct serio *serio, struct serio_driver *drv) | ||
795 | { | ||
796 | serio_set_drv(serio, drv); | ||
797 | |||
798 | if (serio->open && serio->open(serio)) { | ||
799 | serio_set_drv(serio, NULL); | ||
800 | return -1; | ||
801 | } | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | /* called from serio_driver->connect/disconnect methods under serio_sem */ | ||
806 | void serio_close(struct serio *serio) | ||
807 | { | ||
808 | if (serio->close) | ||
809 | serio->close(serio); | ||
810 | |||
811 | serio_set_drv(serio, NULL); | ||
812 | } | ||
813 | |||
814 | irqreturn_t serio_interrupt(struct serio *serio, | ||
815 | unsigned char data, unsigned int dfl, struct pt_regs *regs) | ||
816 | { | ||
817 | unsigned long flags; | ||
818 | irqreturn_t ret = IRQ_NONE; | ||
819 | |||
820 | spin_lock_irqsave(&serio->lock, flags); | ||
821 | |||
822 | if (likely(serio->drv)) { | ||
823 | ret = serio->drv->interrupt(serio, data, dfl, regs); | ||
824 | } else if (!dfl && serio->registered) { | ||
825 | serio_rescan(serio); | ||
826 | ret = IRQ_HANDLED; | ||
827 | } | ||
828 | |||
829 | spin_unlock_irqrestore(&serio->lock, flags); | ||
830 | |||
831 | return ret; | ||
832 | } | ||
833 | |||
834 | static int __init serio_init(void) | ||
835 | { | ||
836 | if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { | ||
837 | printk(KERN_ERR "serio: Failed to start kseriod\n"); | ||
838 | return -1; | ||
839 | } | ||
840 | |||
841 | serio_bus.dev_attrs = serio_device_attrs; | ||
842 | serio_bus.drv_attrs = serio_driver_attrs; | ||
843 | serio_bus.match = serio_bus_match; | ||
844 | serio_bus.hotplug = serio_hotplug; | ||
845 | serio_bus.resume = serio_resume; | ||
846 | bus_register(&serio_bus); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static void __exit serio_exit(void) | ||
852 | { | ||
853 | bus_unregister(&serio_bus); | ||
854 | kill_proc(serio_pid, SIGTERM, 1); | ||
855 | wait_for_completion(&serio_exited); | ||
856 | } | ||
857 | |||
858 | module_init(serio_init); | ||
859 | module_exit(serio_exit); | ||
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c new file mode 100644 index 000000000000..d914e7e93db4 --- /dev/null +++ b/drivers/input/serio/serio_raw.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * Raw serio device providing access to a raw byte stream from underlying | ||
3 | * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device | ||
4 | * | ||
5 | * Copyright (c) 2004 Dmitry Torokhov | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | #include <linux/poll.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/serio.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/major.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/devfs_fs_kernel.h> | ||
20 | #include <linux/miscdevice.h> | ||
21 | #include <linux/wait.h> | ||
22 | |||
23 | #define DRIVER_DESC "Raw serio driver" | ||
24 | |||
25 | MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); | ||
26 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
27 | MODULE_LICENSE("GPL"); | ||
28 | |||
29 | #define SERIO_RAW_QUEUE_LEN 64 | ||
30 | struct serio_raw { | ||
31 | unsigned char queue[SERIO_RAW_QUEUE_LEN]; | ||
32 | unsigned int tail, head; | ||
33 | |||
34 | char name[16]; | ||
35 | unsigned int refcnt; | ||
36 | struct serio *serio; | ||
37 | struct miscdevice dev; | ||
38 | wait_queue_head_t wait; | ||
39 | struct list_head list; | ||
40 | struct list_head node; | ||
41 | }; | ||
42 | |||
43 | struct serio_raw_list { | ||
44 | struct fasync_struct *fasync; | ||
45 | struct serio_raw *serio_raw; | ||
46 | struct list_head node; | ||
47 | }; | ||
48 | |||
49 | static DECLARE_MUTEX(serio_raw_sem); | ||
50 | static LIST_HEAD(serio_raw_list); | ||
51 | static unsigned int serio_raw_no; | ||
52 | |||
53 | /********************************************************************* | ||
54 | * Interface with userspace (file operations) * | ||
55 | *********************************************************************/ | ||
56 | |||
57 | static int serio_raw_fasync(int fd, struct file *file, int on) | ||
58 | { | ||
59 | struct serio_raw_list *list = file->private_data; | ||
60 | int retval; | ||
61 | |||
62 | retval = fasync_helper(fd, file, on, &list->fasync); | ||
63 | return retval < 0 ? retval : 0; | ||
64 | } | ||
65 | |||
66 | static struct serio_raw *serio_raw_locate(int minor) | ||
67 | { | ||
68 | struct serio_raw *serio_raw; | ||
69 | |||
70 | list_for_each_entry(serio_raw, &serio_raw_list, node) { | ||
71 | if (serio_raw->dev.minor == minor) | ||
72 | return serio_raw; | ||
73 | } | ||
74 | |||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | static int serio_raw_open(struct inode *inode, struct file *file) | ||
79 | { | ||
80 | struct serio_raw *serio_raw; | ||
81 | struct serio_raw_list *list; | ||
82 | int retval = 0; | ||
83 | |||
84 | retval = down_interruptible(&serio_raw_sem); | ||
85 | if (retval) | ||
86 | return retval; | ||
87 | |||
88 | if (!(serio_raw = serio_raw_locate(iminor(inode)))) { | ||
89 | retval = -ENODEV; | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | if (!serio_raw->serio) { | ||
94 | retval = -ENODEV; | ||
95 | goto out; | ||
96 | } | ||
97 | |||
98 | if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) { | ||
99 | retval = -ENOMEM; | ||
100 | goto out; | ||
101 | } | ||
102 | |||
103 | memset(list, 0, sizeof(struct serio_raw_list)); | ||
104 | list->serio_raw = serio_raw; | ||
105 | file->private_data = list; | ||
106 | |||
107 | serio_raw->refcnt++; | ||
108 | list_add_tail(&list->node, &serio_raw->list); | ||
109 | |||
110 | out: | ||
111 | up(&serio_raw_sem); | ||
112 | return retval; | ||
113 | } | ||
114 | |||
115 | static int serio_raw_cleanup(struct serio_raw *serio_raw) | ||
116 | { | ||
117 | if (--serio_raw->refcnt == 0) { | ||
118 | misc_deregister(&serio_raw->dev); | ||
119 | list_del_init(&serio_raw->node); | ||
120 | kfree(serio_raw); | ||
121 | |||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int serio_raw_release(struct inode *inode, struct file *file) | ||
129 | { | ||
130 | struct serio_raw_list *list = file->private_data; | ||
131 | struct serio_raw *serio_raw = list->serio_raw; | ||
132 | |||
133 | down(&serio_raw_sem); | ||
134 | |||
135 | serio_raw_fasync(-1, file, 0); | ||
136 | serio_raw_cleanup(serio_raw); | ||
137 | |||
138 | up(&serio_raw_sem); | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) | ||
143 | { | ||
144 | unsigned long flags; | ||
145 | int empty; | ||
146 | |||
147 | spin_lock_irqsave(&serio_raw->serio->lock, flags); | ||
148 | |||
149 | empty = serio_raw->head == serio_raw->tail; | ||
150 | if (!empty) { | ||
151 | *c = serio_raw->queue[serio_raw->tail]; | ||
152 | serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; | ||
153 | } | ||
154 | |||
155 | spin_unlock_irqrestore(&serio_raw->serio->lock, flags); | ||
156 | |||
157 | return !empty; | ||
158 | } | ||
159 | |||
160 | static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | ||
161 | { | ||
162 | struct serio_raw_list *list = file->private_data; | ||
163 | struct serio_raw *serio_raw = list->serio_raw; | ||
164 | char c; | ||
165 | ssize_t retval = 0; | ||
166 | |||
167 | if (!serio_raw->serio) | ||
168 | return -ENODEV; | ||
169 | |||
170 | if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK)) | ||
171 | return -EAGAIN; | ||
172 | |||
173 | retval = wait_event_interruptible(list->serio_raw->wait, | ||
174 | serio_raw->head != serio_raw->tail || !serio_raw->serio); | ||
175 | if (retval) | ||
176 | return retval; | ||
177 | |||
178 | if (!serio_raw->serio) | ||
179 | return -ENODEV; | ||
180 | |||
181 | while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) { | ||
182 | if (put_user(c, buffer++)) | ||
183 | return -EFAULT; | ||
184 | retval++; | ||
185 | } | ||
186 | |||
187 | return retval; | ||
188 | } | ||
189 | |||
190 | static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | ||
191 | { | ||
192 | struct serio_raw_list *list = file->private_data; | ||
193 | ssize_t written = 0; | ||
194 | int retval; | ||
195 | unsigned char c; | ||
196 | |||
197 | retval = down_interruptible(&serio_raw_sem); | ||
198 | if (retval) | ||
199 | return retval; | ||
200 | |||
201 | if (!list->serio_raw->serio) { | ||
202 | retval = -ENODEV; | ||
203 | goto out; | ||
204 | } | ||
205 | |||
206 | if (count > 32) | ||
207 | count = 32; | ||
208 | |||
209 | while (count--) { | ||
210 | if (get_user(c, buffer++)) { | ||
211 | retval = -EFAULT; | ||
212 | goto out; | ||
213 | } | ||
214 | if (serio_write(list->serio_raw->serio, c)) { | ||
215 | retval = -EIO; | ||
216 | goto out; | ||
217 | } | ||
218 | written++; | ||
219 | }; | ||
220 | |||
221 | out: | ||
222 | up(&serio_raw_sem); | ||
223 | return written; | ||
224 | } | ||
225 | |||
226 | static unsigned int serio_raw_poll(struct file *file, poll_table *wait) | ||
227 | { | ||
228 | struct serio_raw_list *list = file->private_data; | ||
229 | |||
230 | poll_wait(file, &list->serio_raw->wait, wait); | ||
231 | |||
232 | if (list->serio_raw->head != list->serio_raw->tail) | ||
233 | return POLLIN | POLLRDNORM; | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static struct file_operations serio_raw_fops = { | ||
239 | .owner = THIS_MODULE, | ||
240 | .open = serio_raw_open, | ||
241 | .release = serio_raw_release, | ||
242 | .read = serio_raw_read, | ||
243 | .write = serio_raw_write, | ||
244 | .poll = serio_raw_poll, | ||
245 | .fasync = serio_raw_fasync, | ||
246 | }; | ||
247 | |||
248 | |||
249 | /********************************************************************* | ||
250 | * Interface with serio port * | ||
251 | *********************************************************************/ | ||
252 | |||
253 | static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, | ||
254 | unsigned int dfl, struct pt_regs *regs) | ||
255 | { | ||
256 | struct serio_raw *serio_raw = serio_get_drvdata(serio); | ||
257 | struct serio_raw_list *list; | ||
258 | unsigned int head = serio_raw->head; | ||
259 | |||
260 | /* we are holding serio->lock here so we are prootected */ | ||
261 | serio_raw->queue[head] = data; | ||
262 | head = (head + 1) % SERIO_RAW_QUEUE_LEN; | ||
263 | if (likely(head != serio_raw->tail)) { | ||
264 | serio_raw->head = head; | ||
265 | list_for_each_entry(list, &serio_raw->list, node) | ||
266 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
267 | wake_up_interruptible(&serio_raw->wait); | ||
268 | } | ||
269 | |||
270 | return IRQ_HANDLED; | ||
271 | } | ||
272 | |||
273 | static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) | ||
274 | { | ||
275 | struct serio_raw *serio_raw; | ||
276 | int err; | ||
277 | |||
278 | if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) { | ||
279 | printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n"); | ||
280 | return -ENOMEM; | ||
281 | } | ||
282 | |||
283 | down(&serio_raw_sem); | ||
284 | |||
285 | memset(serio_raw, 0, sizeof(struct serio_raw)); | ||
286 | snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); | ||
287 | serio_raw->refcnt = 1; | ||
288 | serio_raw->serio = serio; | ||
289 | INIT_LIST_HEAD(&serio_raw->list); | ||
290 | init_waitqueue_head(&serio_raw->wait); | ||
291 | |||
292 | serio_set_drvdata(serio, serio_raw); | ||
293 | |||
294 | err = serio_open(serio, drv); | ||
295 | if (err) | ||
296 | goto out_free; | ||
297 | |||
298 | list_add_tail(&serio_raw->node, &serio_raw_list); | ||
299 | |||
300 | serio_raw->dev.minor = PSMOUSE_MINOR; | ||
301 | serio_raw->dev.name = serio_raw->name; | ||
302 | serio_raw->dev.fops = &serio_raw_fops; | ||
303 | |||
304 | err = misc_register(&serio_raw->dev); | ||
305 | if (err) { | ||
306 | serio_raw->dev.minor = MISC_DYNAMIC_MINOR; | ||
307 | err = misc_register(&serio_raw->dev); | ||
308 | } | ||
309 | |||
310 | if (err) { | ||
311 | printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n", | ||
312 | serio->phys); | ||
313 | goto out_close; | ||
314 | } | ||
315 | |||
316 | printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n", | ||
317 | serio->phys, serio_raw->name, serio_raw->dev.minor); | ||
318 | goto out; | ||
319 | |||
320 | out_close: | ||
321 | serio_close(serio); | ||
322 | list_del_init(&serio_raw->node); | ||
323 | out_free: | ||
324 | serio_set_drvdata(serio, NULL); | ||
325 | kfree(serio_raw); | ||
326 | out: | ||
327 | up(&serio_raw_sem); | ||
328 | return err; | ||
329 | } | ||
330 | |||
331 | static int serio_raw_reconnect(struct serio *serio) | ||
332 | { | ||
333 | struct serio_raw *serio_raw = serio_get_drvdata(serio); | ||
334 | struct serio_driver *drv = serio->drv; | ||
335 | |||
336 | if (!drv || !serio_raw) { | ||
337 | printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n"); | ||
338 | return -1; | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * Nothing needs to be done here, we just need this method to | ||
343 | * keep the same device. | ||
344 | */ | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static void serio_raw_disconnect(struct serio *serio) | ||
349 | { | ||
350 | struct serio_raw *serio_raw; | ||
351 | |||
352 | down(&serio_raw_sem); | ||
353 | |||
354 | serio_raw = serio_get_drvdata(serio); | ||
355 | |||
356 | serio_close(serio); | ||
357 | serio_set_drvdata(serio, NULL); | ||
358 | |||
359 | serio_raw->serio = NULL; | ||
360 | if (!serio_raw_cleanup(serio_raw)) | ||
361 | wake_up_interruptible(&serio_raw->wait); | ||
362 | |||
363 | up(&serio_raw_sem); | ||
364 | } | ||
365 | |||
366 | static struct serio_device_id serio_raw_serio_ids[] = { | ||
367 | { | ||
368 | .type = SERIO_8042, | ||
369 | .proto = SERIO_ANY, | ||
370 | .id = SERIO_ANY, | ||
371 | .extra = SERIO_ANY, | ||
372 | }, | ||
373 | { 0 } | ||
374 | }; | ||
375 | |||
376 | MODULE_DEVICE_TABLE(serio, serio_raw_serio_ids); | ||
377 | |||
378 | static struct serio_driver serio_raw_drv = { | ||
379 | .driver = { | ||
380 | .name = "serio_raw", | ||
381 | }, | ||
382 | .description = DRIVER_DESC, | ||
383 | .id_table = serio_raw_serio_ids, | ||
384 | .interrupt = serio_raw_interrupt, | ||
385 | .connect = serio_raw_connect, | ||
386 | .reconnect = serio_raw_reconnect, | ||
387 | .disconnect = serio_raw_disconnect, | ||
388 | .manual_bind = 1, | ||
389 | }; | ||
390 | |||
391 | static int __init serio_raw_init(void) | ||
392 | { | ||
393 | serio_register_driver(&serio_raw_drv); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static void __exit serio_raw_exit(void) | ||
398 | { | ||
399 | serio_unregister_driver(&serio_raw_drv); | ||
400 | } | ||
401 | |||
402 | module_init(serio_raw_init); | ||
403 | module_exit(serio_raw_exit); | ||
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c new file mode 100644 index 000000000000..22f73683952b --- /dev/null +++ b/drivers/input/serio/serport.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * Input device TTY line discipline | ||
3 | * | ||
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | ||
5 | * | ||
6 | * This is a module that converts a tty line into a much simpler | ||
7 | * 'serial io port' abstraction that the input device drivers use. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License version 2 as published by | ||
13 | * the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <asm/uaccess.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/serio.h> | ||
22 | #include <linux/tty.h> | ||
23 | |||
24 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
25 | MODULE_DESCRIPTION("Input device TTY line discipline"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | MODULE_ALIAS_LDISC(N_MOUSE); | ||
28 | |||
29 | #define SERPORT_BUSY 1 | ||
30 | |||
31 | struct serport { | ||
32 | struct tty_struct *tty; | ||
33 | wait_queue_head_t wait; | ||
34 | struct serio *serio; | ||
35 | unsigned long flags; | ||
36 | }; | ||
37 | |||
38 | /* | ||
39 | * Callback functions from the serio code. | ||
40 | */ | ||
41 | |||
42 | static int serport_serio_write(struct serio *serio, unsigned char data) | ||
43 | { | ||
44 | struct serport *serport = serio->port_data; | ||
45 | return -(serport->tty->driver->write(serport->tty, &data, 1) != 1); | ||
46 | } | ||
47 | |||
48 | static void serport_serio_close(struct serio *serio) | ||
49 | { | ||
50 | struct serport *serport = serio->port_data; | ||
51 | |||
52 | serport->serio->id.type = 0; | ||
53 | wake_up_interruptible(&serport->wait); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * serport_ldisc_open() is the routine that is called upon setting our line | ||
58 | * discipline on a tty. It prepares the serio struct. | ||
59 | */ | ||
60 | |||
61 | static int serport_ldisc_open(struct tty_struct *tty) | ||
62 | { | ||
63 | struct serport *serport; | ||
64 | struct serio *serio; | ||
65 | char name[64]; | ||
66 | |||
67 | if (!capable(CAP_SYS_ADMIN)) | ||
68 | return -EPERM; | ||
69 | |||
70 | serport = kmalloc(sizeof(struct serport), GFP_KERNEL); | ||
71 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | ||
72 | if (unlikely(!serport || !serio)) { | ||
73 | kfree(serport); | ||
74 | kfree(serio); | ||
75 | return -ENOMEM; | ||
76 | } | ||
77 | |||
78 | memset(serport, 0, sizeof(struct serport)); | ||
79 | serport->serio = serio; | ||
80 | set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | ||
81 | serport->tty = tty; | ||
82 | tty->disc_data = serport; | ||
83 | |||
84 | memset(serio, 0, sizeof(struct serio)); | ||
85 | strlcpy(serio->name, "Serial port", sizeof(serio->name)); | ||
86 | snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name)); | ||
87 | serio->id.type = SERIO_RS232; | ||
88 | serio->write = serport_serio_write; | ||
89 | serio->close = serport_serio_close; | ||
90 | serio->port_data = serport; | ||
91 | |||
92 | init_waitqueue_head(&serport->wait); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * serport_ldisc_close() is the opposite of serport_ldisc_open() | ||
99 | */ | ||
100 | |||
101 | static void serport_ldisc_close(struct tty_struct *tty) | ||
102 | { | ||
103 | struct serport *serport = (struct serport*) tty->disc_data; | ||
104 | kfree(serport); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * serport_ldisc_receive() is called by the low level tty driver when characters | ||
109 | * are ready for us. We forward the characters, one by one to the 'interrupt' | ||
110 | * routine. | ||
111 | * | ||
112 | * FIXME: We should get pt_regs from the tty layer and forward them to | ||
113 | * serio_interrupt here. | ||
114 | */ | ||
115 | |||
116 | static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) | ||
117 | { | ||
118 | struct serport *serport = (struct serport*) tty->disc_data; | ||
119 | int i; | ||
120 | for (i = 0; i < count; i++) | ||
121 | serio_interrupt(serport->serio, cp[i], 0, NULL); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * serport_ldisc_room() reports how much room we do have for receiving data. | ||
126 | * Although we in fact have infinite room, we need to specify some value | ||
127 | * here, and 256 seems to be reasonable. | ||
128 | */ | ||
129 | |||
130 | static int serport_ldisc_room(struct tty_struct *tty) | ||
131 | { | ||
132 | return 256; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * serport_ldisc_read() just waits indefinitely if everything goes well. | ||
137 | * However, when the serio driver closes the serio port, it finishes, | ||
138 | * returning 0 characters. | ||
139 | */ | ||
140 | |||
141 | static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr) | ||
142 | { | ||
143 | struct serport *serport = (struct serport*) tty->disc_data; | ||
144 | char name[64]; | ||
145 | |||
146 | if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) | ||
147 | return -EBUSY; | ||
148 | |||
149 | serio_register_port(serport->serio); | ||
150 | printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name)); | ||
151 | wait_event_interruptible(serport->wait, !serport->serio->id.type); | ||
152 | serio_unregister_port(serport->serio); | ||
153 | |||
154 | clear_bit(SERPORT_BUSY, &serport->flags); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * serport_ldisc_ioctl() allows to set the port protocol, and device ID | ||
161 | */ | ||
162 | |||
163 | static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg) | ||
164 | { | ||
165 | struct serport *serport = (struct serport*) tty->disc_data; | ||
166 | struct serio *serio = serport->serio; | ||
167 | unsigned long type; | ||
168 | |||
169 | if (cmd == SPIOCSTYPE) { | ||
170 | if (get_user(type, (unsigned long __user *) arg)) | ||
171 | return -EFAULT; | ||
172 | |||
173 | serio->id.proto = type & 0x000000ff; | ||
174 | serio->id.id = (type & 0x0000ff00) >> 8; | ||
175 | serio->id.extra = (type & 0x00ff0000) >> 16; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | static void serport_ldisc_write_wakeup(struct tty_struct * tty) | ||
184 | { | ||
185 | struct serport *sp = (struct serport *) tty->disc_data; | ||
186 | |||
187 | serio_drv_write_wakeup(sp->serio); | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * The line discipline structure. | ||
192 | */ | ||
193 | |||
194 | static struct tty_ldisc serport_ldisc = { | ||
195 | .owner = THIS_MODULE, | ||
196 | .name = "input", | ||
197 | .open = serport_ldisc_open, | ||
198 | .close = serport_ldisc_close, | ||
199 | .read = serport_ldisc_read, | ||
200 | .ioctl = serport_ldisc_ioctl, | ||
201 | .receive_buf = serport_ldisc_receive, | ||
202 | .receive_room = serport_ldisc_room, | ||
203 | .write_wakeup = serport_ldisc_write_wakeup | ||
204 | }; | ||
205 | |||
206 | /* | ||
207 | * The functions for insering/removing us as a module. | ||
208 | */ | ||
209 | |||
210 | static int __init serport_init(void) | ||
211 | { | ||
212 | int retval; | ||
213 | retval = tty_register_ldisc(N_MOUSE, &serport_ldisc); | ||
214 | if (retval) | ||
215 | printk(KERN_ERR "serport.c: Error registering line discipline.\n"); | ||
216 | |||
217 | return retval; | ||
218 | } | ||
219 | |||
220 | static void __exit serport_exit(void) | ||
221 | { | ||
222 | tty_register_ldisc(N_MOUSE, NULL); | ||
223 | } | ||
224 | |||
225 | module_init(serport_init); | ||
226 | module_exit(serport_exit); | ||