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/parport/parport_gsc.c |
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/parport/parport_gsc.c')
-rw-r--r-- | drivers/parport/parport_gsc.c | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c new file mode 100644 index 000000000000..02d72acd1c89 --- /dev/null +++ b/drivers/parport/parport_gsc.c | |||
@@ -0,0 +1,437 @@ | |||
1 | /* | ||
2 | * Low-level parallel-support for PC-style hardware integrated in the | ||
3 | * LASI-Controller (on GSC-Bus) for HP-PARISC Workstations | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * (C) 1999-2001 by Helge Deller <deller@gmx.de> | ||
11 | * | ||
12 | * | ||
13 | * based on parport_pc.c by | ||
14 | * Grant Guenther <grant@torque.net> | ||
15 | * Phil Blundell <philb@gnu.org> | ||
16 | * Tim Waugh <tim@cyberelk.demon.co.uk> | ||
17 | * Jose Renau <renau@acm.org> | ||
18 | * David Campbell <campbell@torque.net> | ||
19 | * Andrea Arcangeli | ||
20 | */ | ||
21 | |||
22 | #undef DEBUG /* undef for production */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/ioport.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/pci.h> | ||
34 | #include <linux/sysctl.h> | ||
35 | |||
36 | #include <asm/io.h> | ||
37 | #include <asm/dma.h> | ||
38 | #include <asm/uaccess.h> | ||
39 | #include <asm/superio.h> | ||
40 | |||
41 | #include <linux/parport.h> | ||
42 | #include <asm/pdc.h> | ||
43 | #include <asm/parisc-device.h> | ||
44 | #include <asm/hardware.h> | ||
45 | #include "parport_gsc.h" | ||
46 | |||
47 | |||
48 | MODULE_AUTHOR("Helge Deller <deller@gmx.de>"); | ||
49 | MODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver"); | ||
50 | MODULE_SUPPORTED_DEVICE("integrated PC-style parallel port"); | ||
51 | MODULE_LICENSE("GPL"); | ||
52 | |||
53 | |||
54 | /* | ||
55 | * Clear TIMEOUT BIT in EPP MODE | ||
56 | * | ||
57 | * This is also used in SPP detection. | ||
58 | */ | ||
59 | static int clear_epp_timeout(struct parport *pb) | ||
60 | { | ||
61 | unsigned char r; | ||
62 | |||
63 | if (!(parport_gsc_read_status(pb) & 0x01)) | ||
64 | return 1; | ||
65 | |||
66 | /* To clear timeout some chips require double read */ | ||
67 | parport_gsc_read_status(pb); | ||
68 | r = parport_gsc_read_status(pb); | ||
69 | parport_writeb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */ | ||
70 | parport_writeb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */ | ||
71 | r = parport_gsc_read_status(pb); | ||
72 | |||
73 | return !(r & 0x01); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Access functions. | ||
78 | * | ||
79 | * Most of these aren't static because they may be used by the | ||
80 | * parport_xxx_yyy macros. extern __inline__ versions of several | ||
81 | * of these are in parport_gsc.h. | ||
82 | */ | ||
83 | |||
84 | static irqreturn_t parport_gsc_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
85 | { | ||
86 | parport_generic_irq(irq, (struct parport *) dev_id, regs); | ||
87 | return IRQ_HANDLED; | ||
88 | } | ||
89 | |||
90 | void parport_gsc_init_state(struct pardevice *dev, struct parport_state *s) | ||
91 | { | ||
92 | s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); | ||
93 | } | ||
94 | |||
95 | void parport_gsc_save_state(struct parport *p, struct parport_state *s) | ||
96 | { | ||
97 | s->u.pc.ctr = parport_readb (CONTROL (p)); | ||
98 | } | ||
99 | |||
100 | void parport_gsc_restore_state(struct parport *p, struct parport_state *s) | ||
101 | { | ||
102 | parport_writeb (s->u.pc.ctr, CONTROL (p)); | ||
103 | } | ||
104 | |||
105 | struct parport_operations parport_gsc_ops = | ||
106 | { | ||
107 | .write_data = parport_gsc_write_data, | ||
108 | .read_data = parport_gsc_read_data, | ||
109 | |||
110 | .write_control = parport_gsc_write_control, | ||
111 | .read_control = parport_gsc_read_control, | ||
112 | .frob_control = parport_gsc_frob_control, | ||
113 | |||
114 | .read_status = parport_gsc_read_status, | ||
115 | |||
116 | .enable_irq = parport_gsc_enable_irq, | ||
117 | .disable_irq = parport_gsc_disable_irq, | ||
118 | |||
119 | .data_forward = parport_gsc_data_forward, | ||
120 | .data_reverse = parport_gsc_data_reverse, | ||
121 | |||
122 | .init_state = parport_gsc_init_state, | ||
123 | .save_state = parport_gsc_save_state, | ||
124 | .restore_state = parport_gsc_restore_state, | ||
125 | |||
126 | .epp_write_data = parport_ieee1284_epp_write_data, | ||
127 | .epp_read_data = parport_ieee1284_epp_read_data, | ||
128 | .epp_write_addr = parport_ieee1284_epp_write_addr, | ||
129 | .epp_read_addr = parport_ieee1284_epp_read_addr, | ||
130 | |||
131 | .ecp_write_data = parport_ieee1284_ecp_write_data, | ||
132 | .ecp_read_data = parport_ieee1284_ecp_read_data, | ||
133 | .ecp_write_addr = parport_ieee1284_ecp_write_addr, | ||
134 | |||
135 | .compat_write_data = parport_ieee1284_write_compat, | ||
136 | .nibble_read_data = parport_ieee1284_read_nibble, | ||
137 | .byte_read_data = parport_ieee1284_read_byte, | ||
138 | |||
139 | .owner = THIS_MODULE, | ||
140 | }; | ||
141 | |||
142 | /* --- Mode detection ------------------------------------- */ | ||
143 | |||
144 | /* | ||
145 | * Checks for port existence, all ports support SPP MODE | ||
146 | */ | ||
147 | static int __devinit parport_SPP_supported(struct parport *pb) | ||
148 | { | ||
149 | unsigned char r, w; | ||
150 | |||
151 | /* | ||
152 | * first clear an eventually pending EPP timeout | ||
153 | * I (sailer@ife.ee.ethz.ch) have an SMSC chipset | ||
154 | * that does not even respond to SPP cycles if an EPP | ||
155 | * timeout is pending | ||
156 | */ | ||
157 | clear_epp_timeout(pb); | ||
158 | |||
159 | /* Do a simple read-write test to make sure the port exists. */ | ||
160 | w = 0xc; | ||
161 | parport_writeb (w, CONTROL (pb)); | ||
162 | |||
163 | /* Is there a control register that we can read from? Some | ||
164 | * ports don't allow reads, so read_control just returns a | ||
165 | * software copy. Some ports _do_ allow reads, so bypass the | ||
166 | * software copy here. In addition, some bits aren't | ||
167 | * writable. */ | ||
168 | r = parport_readb (CONTROL (pb)); | ||
169 | if ((r & 0xf) == w) { | ||
170 | w = 0xe; | ||
171 | parport_writeb (w, CONTROL (pb)); | ||
172 | r = parport_readb (CONTROL (pb)); | ||
173 | parport_writeb (0xc, CONTROL (pb)); | ||
174 | if ((r & 0xf) == w) | ||
175 | return PARPORT_MODE_PCSPP; | ||
176 | } | ||
177 | |||
178 | /* Try the data register. The data lines aren't tri-stated at | ||
179 | * this stage, so we expect back what we wrote. */ | ||
180 | w = 0xaa; | ||
181 | parport_gsc_write_data (pb, w); | ||
182 | r = parport_gsc_read_data (pb); | ||
183 | if (r == w) { | ||
184 | w = 0x55; | ||
185 | parport_gsc_write_data (pb, w); | ||
186 | r = parport_gsc_read_data (pb); | ||
187 | if (r == w) | ||
188 | return PARPORT_MODE_PCSPP; | ||
189 | } | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | /* Detect PS/2 support. | ||
195 | * | ||
196 | * Bit 5 (0x20) sets the PS/2 data direction; setting this high | ||
197 | * allows us to read data from the data lines. In theory we would get back | ||
198 | * 0xff but any peripheral attached to the port may drag some or all of the | ||
199 | * lines down to zero. So if we get back anything that isn't the contents | ||
200 | * of the data register we deem PS/2 support to be present. | ||
201 | * | ||
202 | * Some SPP ports have "half PS/2" ability - you can't turn off the line | ||
203 | * drivers, but an external peripheral with sufficiently beefy drivers of | ||
204 | * its own can overpower them and assert its own levels onto the bus, from | ||
205 | * where they can then be read back as normal. Ports with this property | ||
206 | * and the right type of device attached are likely to fail the SPP test, | ||
207 | * (as they will appear to have stuck bits) and so the fact that they might | ||
208 | * be misdetected here is rather academic. | ||
209 | */ | ||
210 | |||
211 | static int __devinit parport_PS2_supported(struct parport *pb) | ||
212 | { | ||
213 | int ok = 0; | ||
214 | |||
215 | clear_epp_timeout(pb); | ||
216 | |||
217 | /* try to tri-state the buffer */ | ||
218 | parport_gsc_data_reverse (pb); | ||
219 | |||
220 | parport_gsc_write_data(pb, 0x55); | ||
221 | if (parport_gsc_read_data(pb) != 0x55) ok++; | ||
222 | |||
223 | parport_gsc_write_data(pb, 0xaa); | ||
224 | if (parport_gsc_read_data(pb) != 0xaa) ok++; | ||
225 | |||
226 | /* cancel input mode */ | ||
227 | parport_gsc_data_forward (pb); | ||
228 | |||
229 | if (ok) { | ||
230 | pb->modes |= PARPORT_MODE_TRISTATE; | ||
231 | } else { | ||
232 | struct parport_gsc_private *priv = pb->private_data; | ||
233 | priv->ctr_writable &= ~0x20; | ||
234 | } | ||
235 | |||
236 | return ok; | ||
237 | } | ||
238 | |||
239 | |||
240 | /* --- Initialisation code -------------------------------- */ | ||
241 | |||
242 | struct parport *__devinit parport_gsc_probe_port (unsigned long base, | ||
243 | unsigned long base_hi, | ||
244 | int irq, int dma, | ||
245 | struct pci_dev *dev) | ||
246 | { | ||
247 | struct parport_gsc_private *priv; | ||
248 | struct parport_operations *ops; | ||
249 | struct parport tmp; | ||
250 | struct parport *p = &tmp; | ||
251 | |||
252 | priv = kmalloc (sizeof (struct parport_gsc_private), GFP_KERNEL); | ||
253 | if (!priv) { | ||
254 | printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base); | ||
255 | return NULL; | ||
256 | } | ||
257 | ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); | ||
258 | if (!ops) { | ||
259 | printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n", | ||
260 | base); | ||
261 | kfree (priv); | ||
262 | return NULL; | ||
263 | } | ||
264 | memcpy (ops, &parport_gsc_ops, sizeof (struct parport_operations)); | ||
265 | priv->ctr = 0xc; | ||
266 | priv->ctr_writable = 0xff; | ||
267 | priv->dma_buf = 0; | ||
268 | priv->dma_handle = 0; | ||
269 | priv->dev = dev; | ||
270 | p->base = base; | ||
271 | p->base_hi = base_hi; | ||
272 | p->irq = irq; | ||
273 | p->dma = dma; | ||
274 | p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT; | ||
275 | p->ops = ops; | ||
276 | p->private_data = priv; | ||
277 | p->physport = p; | ||
278 | if (!parport_SPP_supported (p)) { | ||
279 | /* No port. */ | ||
280 | kfree (priv); | ||
281 | return NULL; | ||
282 | } | ||
283 | parport_PS2_supported (p); | ||
284 | |||
285 | if (!(p = parport_register_port(base, PARPORT_IRQ_NONE, | ||
286 | PARPORT_DMA_NONE, ops))) { | ||
287 | kfree (priv); | ||
288 | kfree (ops); | ||
289 | return NULL; | ||
290 | } | ||
291 | |||
292 | p->base_hi = base_hi; | ||
293 | p->modes = tmp.modes; | ||
294 | p->size = (p->modes & PARPORT_MODE_EPP)?8:3; | ||
295 | p->private_data = priv; | ||
296 | |||
297 | printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); | ||
298 | p->irq = irq; | ||
299 | if (p->irq == PARPORT_IRQ_AUTO) { | ||
300 | p->irq = PARPORT_IRQ_NONE; | ||
301 | } | ||
302 | if (p->irq != PARPORT_IRQ_NONE) { | ||
303 | printk(", irq %d", p->irq); | ||
304 | |||
305 | if (p->dma == PARPORT_DMA_AUTO) { | ||
306 | p->dma = PARPORT_DMA_NONE; | ||
307 | } | ||
308 | } | ||
309 | if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq | ||
310 | is mandatory (see above) */ | ||
311 | p->dma = PARPORT_DMA_NONE; | ||
312 | |||
313 | printk(" ["); | ||
314 | #define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}} | ||
315 | { | ||
316 | int f = 0; | ||
317 | printmode(PCSPP); | ||
318 | printmode(TRISTATE); | ||
319 | printmode(COMPAT) | ||
320 | printmode(EPP); | ||
321 | // printmode(ECP); | ||
322 | // printmode(DMA); | ||
323 | } | ||
324 | #undef printmode | ||
325 | printk("]\n"); | ||
326 | |||
327 | if (p->irq != PARPORT_IRQ_NONE) { | ||
328 | if (request_irq (p->irq, parport_gsc_interrupt, | ||
329 | 0, p->name, p)) { | ||
330 | printk (KERN_WARNING "%s: irq %d in use, " | ||
331 | "resorting to polled operation\n", | ||
332 | p->name, p->irq); | ||
333 | p->irq = PARPORT_IRQ_NONE; | ||
334 | p->dma = PARPORT_DMA_NONE; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | /* Done probing. Now put the port into a sensible start-up state. */ | ||
339 | |||
340 | parport_gsc_write_data(p, 0); | ||
341 | parport_gsc_data_forward (p); | ||
342 | |||
343 | /* Now that we've told the sharing engine about the port, and | ||
344 | found out its characteristics, let the high-level drivers | ||
345 | know about it. */ | ||
346 | parport_announce_port (p); | ||
347 | |||
348 | return p; | ||
349 | } | ||
350 | |||
351 | |||
352 | #define PARPORT_GSC_OFFSET 0x800 | ||
353 | |||
354 | static int __initdata parport_count; | ||
355 | |||
356 | static int __devinit parport_init_chip(struct parisc_device *dev) | ||
357 | { | ||
358 | struct parport *p; | ||
359 | unsigned long port; | ||
360 | |||
361 | if (!dev->irq) { | ||
362 | printk("IRQ not found for parallel device at 0x%lx\n", dev->hpa); | ||
363 | return -ENODEV; | ||
364 | } | ||
365 | |||
366 | port = dev->hpa + PARPORT_GSC_OFFSET; | ||
367 | |||
368 | /* some older machines with ASP-chip don't support | ||
369 | * the enhanced parport modes. | ||
370 | */ | ||
371 | if (boot_cpu_data.cpu_type > pcxt && !pdc_add_valid(port+4)) { | ||
372 | |||
373 | /* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */ | ||
374 | printk("%s: initialize bidirectional-mode.\n", __FUNCTION__); | ||
375 | parport_writeb ( (0x10 + 0x20), port + 4); | ||
376 | |||
377 | } else { | ||
378 | printk("%s: enhanced parport-modes not supported.\n", __FUNCTION__); | ||
379 | } | ||
380 | |||
381 | p = parport_gsc_probe_port(port, 0, dev->irq, | ||
382 | /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, NULL); | ||
383 | if (p) | ||
384 | parport_count++; | ||
385 | dev->dev.driver_data = p; | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int __devexit parport_remove_chip(struct parisc_device *dev) | ||
391 | { | ||
392 | struct parport *p = dev->dev.driver_data; | ||
393 | if (p) { | ||
394 | struct parport_gsc_private *priv = p->private_data; | ||
395 | struct parport_operations *ops = p->ops; | ||
396 | parport_remove_port(p); | ||
397 | if (p->dma != PARPORT_DMA_NONE) | ||
398 | free_dma(p->dma); | ||
399 | if (p->irq != PARPORT_IRQ_NONE) | ||
400 | free_irq(p->irq, p); | ||
401 | if (priv->dma_buf) | ||
402 | pci_free_consistent(priv->dev, PAGE_SIZE, | ||
403 | priv->dma_buf, | ||
404 | priv->dma_handle); | ||
405 | kfree (p->private_data); | ||
406 | parport_put_port(p); | ||
407 | kfree (ops); /* hope no-one cached it */ | ||
408 | } | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static struct parisc_device_id parport_tbl[] = { | ||
413 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x74 }, | ||
414 | { 0, } | ||
415 | }; | ||
416 | |||
417 | MODULE_DEVICE_TABLE(parisc, parport_tbl); | ||
418 | |||
419 | static struct parisc_driver parport_driver = { | ||
420 | .name = "Parallel", | ||
421 | .id_table = parport_tbl, | ||
422 | .probe = parport_init_chip, | ||
423 | .remove = __devexit_p(parport_remove_chip), | ||
424 | }; | ||
425 | |||
426 | int __devinit parport_gsc_init(void) | ||
427 | { | ||
428 | return register_parisc_driver(&parport_driver); | ||
429 | } | ||
430 | |||
431 | static void __devexit parport_gsc_exit(void) | ||
432 | { | ||
433 | unregister_parisc_driver(&parport_driver); | ||
434 | } | ||
435 | |||
436 | module_init(parport_gsc_init); | ||
437 | module_exit(parport_gsc_exit); | ||