diff options
Diffstat (limited to 'drivers/parport/parport_sunbpp.c')
-rw-r--r-- | drivers/parport/parport_sunbpp.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c new file mode 100644 index 000000000000..36a1556e64c7 --- /dev/null +++ b/drivers/parport/parport_sunbpp.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* $Id: parport_sunbpp.c,v 1.12 2001/05/26 03:01:42 davem Exp $ | ||
2 | * Parallel-port routines for Sun architecture | ||
3 | * | ||
4 | * Author: Derrick J. Brashear <shadow@dementia.org> | ||
5 | * | ||
6 | * based on work by: | ||
7 | * Phil Blundell <philb@gnu.org> | ||
8 | * Tim Waugh <tim@cyberelk.demon.co.uk> | ||
9 | * Jose Renau <renau@acm.org> | ||
10 | * David Campbell <campbell@tirian.che.curtin.edu.au> | ||
11 | * Grant Guenther <grant@torque.net> | ||
12 | * Eddie C. Dost <ecd@skynet.be> | ||
13 | * Stephen Williams (steve@icarus.com) | ||
14 | * Gus Baldauf (gbaldauf@ix.netcom.com) | ||
15 | * Peter Zaitcev | ||
16 | * Tom Dyas | ||
17 | */ | ||
18 | |||
19 | #include <linux/string.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/init.h> | ||
27 | |||
28 | #include <linux/parport.h> | ||
29 | |||
30 | #include <asm/ptrace.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | |||
33 | #include <asm/io.h> | ||
34 | #include <asm/oplib.h> /* OpenProm Library */ | ||
35 | #include <asm/sbus.h> | ||
36 | #include <asm/dma.h> /* BPP uses LSI 64854 for DMA */ | ||
37 | #include <asm/irq.h> | ||
38 | #include <asm/sunbpp.h> | ||
39 | |||
40 | #undef __SUNBPP_DEBUG | ||
41 | #ifdef __SUNBPP_DEBUG | ||
42 | #define dprintk(x) printk x | ||
43 | #else | ||
44 | #define dprintk(x) | ||
45 | #endif | ||
46 | |||
47 | static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
48 | { | ||
49 | parport_generic_irq(irq, (struct parport *) dev_id, regs); | ||
50 | return IRQ_HANDLED; | ||
51 | } | ||
52 | |||
53 | static void parport_sunbpp_disable_irq(struct parport *p) | ||
54 | { | ||
55 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
56 | u32 tmp; | ||
57 | |||
58 | tmp = sbus_readl(®s->p_csr); | ||
59 | tmp &= ~DMA_INT_ENAB; | ||
60 | sbus_writel(tmp, ®s->p_csr); | ||
61 | } | ||
62 | |||
63 | static void parport_sunbpp_enable_irq(struct parport *p) | ||
64 | { | ||
65 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
66 | u32 tmp; | ||
67 | |||
68 | tmp = sbus_readl(®s->p_csr); | ||
69 | tmp |= DMA_INT_ENAB; | ||
70 | sbus_writel(tmp, ®s->p_csr); | ||
71 | } | ||
72 | |||
73 | static void parport_sunbpp_write_data(struct parport *p, unsigned char d) | ||
74 | { | ||
75 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
76 | |||
77 | sbus_writeb(d, ®s->p_dr); | ||
78 | dprintk((KERN_DEBUG "wrote 0x%x\n", d)); | ||
79 | } | ||
80 | |||
81 | static unsigned char parport_sunbpp_read_data(struct parport *p) | ||
82 | { | ||
83 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
84 | |||
85 | return sbus_readb(®s->p_dr); | ||
86 | } | ||
87 | |||
88 | #if 0 | ||
89 | static void control_pc_to_sunbpp(struct parport *p, unsigned char status) | ||
90 | { | ||
91 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
92 | unsigned char value_tcr = sbus_readb(®s->p_tcr); | ||
93 | unsigned char value_or = sbus_readb(®s->p_or); | ||
94 | |||
95 | if (status & PARPORT_CONTROL_STROBE) | ||
96 | value_tcr |= P_TCR_DS; | ||
97 | if (status & PARPORT_CONTROL_AUTOFD) | ||
98 | value_or |= P_OR_AFXN; | ||
99 | if (status & PARPORT_CONTROL_INIT) | ||
100 | value_or |= P_OR_INIT; | ||
101 | if (status & PARPORT_CONTROL_SELECT) | ||
102 | value_or |= P_OR_SLCT_IN; | ||
103 | |||
104 | sbus_writeb(value_or, ®s->p_or); | ||
105 | sbus_writeb(value_tcr, ®s->p_tcr); | ||
106 | } | ||
107 | #endif | ||
108 | |||
109 | static unsigned char status_sunbpp_to_pc(struct parport *p) | ||
110 | { | ||
111 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
112 | unsigned char bits = 0; | ||
113 | unsigned char value_tcr = sbus_readb(®s->p_tcr); | ||
114 | unsigned char value_ir = sbus_readb(®s->p_ir); | ||
115 | |||
116 | if (!(value_ir & P_IR_ERR)) | ||
117 | bits |= PARPORT_STATUS_ERROR; | ||
118 | if (!(value_ir & P_IR_SLCT)) | ||
119 | bits |= PARPORT_STATUS_SELECT; | ||
120 | if (!(value_ir & P_IR_PE)) | ||
121 | bits |= PARPORT_STATUS_PAPEROUT; | ||
122 | if (value_tcr & P_TCR_ACK) | ||
123 | bits |= PARPORT_STATUS_ACK; | ||
124 | if (!(value_tcr & P_TCR_BUSY)) | ||
125 | bits |= PARPORT_STATUS_BUSY; | ||
126 | |||
127 | dprintk((KERN_DEBUG "tcr 0x%x ir 0x%x\n", regs->p_tcr, regs->p_ir)); | ||
128 | dprintk((KERN_DEBUG "read status 0x%x\n", bits)); | ||
129 | return bits; | ||
130 | } | ||
131 | |||
132 | static unsigned char control_sunbpp_to_pc(struct parport *p) | ||
133 | { | ||
134 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
135 | unsigned char bits = 0; | ||
136 | unsigned char value_tcr = sbus_readb(®s->p_tcr); | ||
137 | unsigned char value_or = sbus_readb(®s->p_or); | ||
138 | |||
139 | if (!(value_tcr & P_TCR_DS)) | ||
140 | bits |= PARPORT_CONTROL_STROBE; | ||
141 | if (!(value_or & P_OR_AFXN)) | ||
142 | bits |= PARPORT_CONTROL_AUTOFD; | ||
143 | if (!(value_or & P_OR_INIT)) | ||
144 | bits |= PARPORT_CONTROL_INIT; | ||
145 | if (value_or & P_OR_SLCT_IN) | ||
146 | bits |= PARPORT_CONTROL_SELECT; | ||
147 | |||
148 | dprintk((KERN_DEBUG "tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); | ||
149 | dprintk((KERN_DEBUG "read control 0x%x\n", bits)); | ||
150 | return bits; | ||
151 | } | ||
152 | |||
153 | static unsigned char parport_sunbpp_read_control(struct parport *p) | ||
154 | { | ||
155 | return control_sunbpp_to_pc(p); | ||
156 | } | ||
157 | |||
158 | static unsigned char parport_sunbpp_frob_control(struct parport *p, | ||
159 | unsigned char mask, | ||
160 | unsigned char val) | ||
161 | { | ||
162 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
163 | unsigned char value_tcr = sbus_readb(®s->p_tcr); | ||
164 | unsigned char value_or = sbus_readb(®s->p_or); | ||
165 | |||
166 | dprintk((KERN_DEBUG "frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); | ||
167 | if (mask & PARPORT_CONTROL_STROBE) { | ||
168 | if (val & PARPORT_CONTROL_STROBE) { | ||
169 | value_tcr &= ~P_TCR_DS; | ||
170 | } else { | ||
171 | value_tcr |= P_TCR_DS; | ||
172 | } | ||
173 | } | ||
174 | if (mask & PARPORT_CONTROL_AUTOFD) { | ||
175 | if (val & PARPORT_CONTROL_AUTOFD) { | ||
176 | value_or &= ~P_OR_AFXN; | ||
177 | } else { | ||
178 | value_or |= P_OR_AFXN; | ||
179 | } | ||
180 | } | ||
181 | if (mask & PARPORT_CONTROL_INIT) { | ||
182 | if (val & PARPORT_CONTROL_INIT) { | ||
183 | value_or &= ~P_OR_INIT; | ||
184 | } else { | ||
185 | value_or |= P_OR_INIT; | ||
186 | } | ||
187 | } | ||
188 | if (mask & PARPORT_CONTROL_SELECT) { | ||
189 | if (val & PARPORT_CONTROL_SELECT) { | ||
190 | value_or |= P_OR_SLCT_IN; | ||
191 | } else { | ||
192 | value_or &= ~P_OR_SLCT_IN; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | sbus_writeb(value_or, ®s->p_or); | ||
197 | sbus_writeb(value_tcr, ®s->p_tcr); | ||
198 | dprintk((KERN_DEBUG "frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); | ||
199 | return parport_sunbpp_read_control(p); | ||
200 | } | ||
201 | |||
202 | static void parport_sunbpp_write_control(struct parport *p, unsigned char d) | ||
203 | { | ||
204 | const unsigned char wm = (PARPORT_CONTROL_STROBE | | ||
205 | PARPORT_CONTROL_AUTOFD | | ||
206 | PARPORT_CONTROL_INIT | | ||
207 | PARPORT_CONTROL_SELECT); | ||
208 | |||
209 | parport_sunbpp_frob_control (p, wm, d & wm); | ||
210 | } | ||
211 | |||
212 | static unsigned char parport_sunbpp_read_status(struct parport *p) | ||
213 | { | ||
214 | return status_sunbpp_to_pc(p); | ||
215 | } | ||
216 | |||
217 | static void parport_sunbpp_data_forward (struct parport *p) | ||
218 | { | ||
219 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
220 | unsigned char value_tcr = sbus_readb(®s->p_tcr); | ||
221 | |||
222 | dprintk((KERN_DEBUG "forward\n")); | ||
223 | value_tcr &= ~P_TCR_DIR; | ||
224 | sbus_writeb(value_tcr, ®s->p_tcr); | ||
225 | } | ||
226 | |||
227 | static void parport_sunbpp_data_reverse (struct parport *p) | ||
228 | { | ||
229 | struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; | ||
230 | u8 val = sbus_readb(®s->p_tcr); | ||
231 | |||
232 | dprintk((KERN_DEBUG "reverse\n")); | ||
233 | val |= P_TCR_DIR; | ||
234 | sbus_writeb(val, ®s->p_tcr); | ||
235 | } | ||
236 | |||
237 | static void parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s) | ||
238 | { | ||
239 | s->u.pc.ctr = 0xc; | ||
240 | s->u.pc.ecr = 0x0; | ||
241 | } | ||
242 | |||
243 | static void parport_sunbpp_save_state(struct parport *p, struct parport_state *s) | ||
244 | { | ||
245 | s->u.pc.ctr = parport_sunbpp_read_control(p); | ||
246 | } | ||
247 | |||
248 | static void parport_sunbpp_restore_state(struct parport *p, struct parport_state *s) | ||
249 | { | ||
250 | parport_sunbpp_write_control(p, s->u.pc.ctr); | ||
251 | } | ||
252 | |||
253 | static struct parport_operations parport_sunbpp_ops = | ||
254 | { | ||
255 | .write_data = parport_sunbpp_write_data, | ||
256 | .read_data = parport_sunbpp_read_data, | ||
257 | |||
258 | .write_control = parport_sunbpp_write_control, | ||
259 | .read_control = parport_sunbpp_read_control, | ||
260 | .frob_control = parport_sunbpp_frob_control, | ||
261 | |||
262 | .read_status = parport_sunbpp_read_status, | ||
263 | |||
264 | .enable_irq = parport_sunbpp_enable_irq, | ||
265 | .disable_irq = parport_sunbpp_disable_irq, | ||
266 | |||
267 | .data_forward = parport_sunbpp_data_forward, | ||
268 | .data_reverse = parport_sunbpp_data_reverse, | ||
269 | |||
270 | .init_state = parport_sunbpp_init_state, | ||
271 | .save_state = parport_sunbpp_save_state, | ||
272 | .restore_state = parport_sunbpp_restore_state, | ||
273 | |||
274 | .epp_write_data = parport_ieee1284_epp_write_data, | ||
275 | .epp_read_data = parport_ieee1284_epp_read_data, | ||
276 | .epp_write_addr = parport_ieee1284_epp_write_addr, | ||
277 | .epp_read_addr = parport_ieee1284_epp_read_addr, | ||
278 | |||
279 | .ecp_write_data = parport_ieee1284_ecp_write_data, | ||
280 | .ecp_read_data = parport_ieee1284_ecp_read_data, | ||
281 | .ecp_write_addr = parport_ieee1284_ecp_write_addr, | ||
282 | |||
283 | .compat_write_data = parport_ieee1284_write_compat, | ||
284 | .nibble_read_data = parport_ieee1284_read_nibble, | ||
285 | .byte_read_data = parport_ieee1284_read_byte, | ||
286 | |||
287 | .owner = THIS_MODULE, | ||
288 | }; | ||
289 | |||
290 | typedef struct { | ||
291 | struct list_head list; | ||
292 | struct parport *port; | ||
293 | } Node; | ||
294 | /* no locks, everything's serialized */ | ||
295 | static LIST_HEAD(port_list); | ||
296 | |||
297 | static int __init init_one_port(struct sbus_dev *sdev) | ||
298 | { | ||
299 | struct parport *p; | ||
300 | /* at least in theory there may be a "we don't dma" case */ | ||
301 | struct parport_operations *ops; | ||
302 | void __iomem *base; | ||
303 | int irq, dma, err = 0, size; | ||
304 | struct bpp_regs __iomem *regs; | ||
305 | unsigned char value_tcr; | ||
306 | Node *node; | ||
307 | |||
308 | dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev)); | ||
309 | node = kmalloc(sizeof(Node), GFP_KERNEL); | ||
310 | if (!node) | ||
311 | goto out0; | ||
312 | |||
313 | irq = sdev->irqs[0]; | ||
314 | base = sbus_ioremap(&sdev->resource[0], 0, | ||
315 | sdev->reg_addrs[0].reg_size, | ||
316 | "sunbpp"); | ||
317 | if (!base) | ||
318 | goto out1; | ||
319 | |||
320 | size = sdev->reg_addrs[0].reg_size; | ||
321 | dma = PARPORT_DMA_NONE; | ||
322 | |||
323 | dprintk(("alloc(ppops), ")); | ||
324 | ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); | ||
325 | if (!ops) | ||
326 | goto out2; | ||
327 | |||
328 | memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); | ||
329 | |||
330 | dprintk(("register_port\n")); | ||
331 | if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) | ||
332 | goto out3; | ||
333 | |||
334 | p->size = size; | ||
335 | |||
336 | dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ", | ||
337 | p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)); | ||
338 | if ((err = request_irq(p->irq, parport_sunbpp_interrupt, | ||
339 | SA_SHIRQ, p->name, p)) != 0) { | ||
340 | dprintk(("ERROR %d\n", err)); | ||
341 | goto out4; | ||
342 | } | ||
343 | dprintk(("OK\n")); | ||
344 | parport_sunbpp_enable_irq(p); | ||
345 | |||
346 | regs = (struct bpp_regs __iomem *)p->base; | ||
347 | dprintk((KERN_DEBUG "forward\n")); | ||
348 | value_tcr = sbus_readb(®s->p_tcr); | ||
349 | value_tcr &= ~P_TCR_DIR; | ||
350 | sbus_writeb(value_tcr, ®s->p_tcr); | ||
351 | |||
352 | printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base); | ||
353 | node->port = p; | ||
354 | list_add(&node->list, &port_list); | ||
355 | parport_announce_port (p); | ||
356 | |||
357 | return 1; | ||
358 | |||
359 | out4: | ||
360 | parport_put_port(p); | ||
361 | out3: | ||
362 | kfree(ops); | ||
363 | out2: | ||
364 | sbus_iounmap(base, size); | ||
365 | out1: | ||
366 | kfree(node); | ||
367 | out0: | ||
368 | return err; | ||
369 | } | ||
370 | |||
371 | static int __init parport_sunbpp_init(void) | ||
372 | { | ||
373 | struct sbus_bus *sbus; | ||
374 | struct sbus_dev *sdev; | ||
375 | int count = 0; | ||
376 | |||
377 | for_each_sbus(sbus) { | ||
378 | for_each_sbusdev(sdev, sbus) { | ||
379 | if (!strcmp(sdev->prom_name, "SUNW,bpp")) | ||
380 | count += init_one_port(sdev); | ||
381 | } | ||
382 | } | ||
383 | return count ? 0 : -ENODEV; | ||
384 | } | ||
385 | |||
386 | static void __exit parport_sunbpp_exit(void) | ||
387 | { | ||
388 | while (!list_empty(&port_list)) { | ||
389 | Node *node = list_entry(port_list.next, Node, list); | ||
390 | struct parport *p = node->port; | ||
391 | struct parport_operations *ops = p->ops; | ||
392 | parport_remove_port(p); | ||
393 | |||
394 | if (p->irq != PARPORT_IRQ_NONE) { | ||
395 | parport_sunbpp_disable_irq(p); | ||
396 | free_irq(p->irq, p); | ||
397 | } | ||
398 | sbus_iounmap((void __iomem *)p->base, p->size); | ||
399 | parport_put_port(p); | ||
400 | kfree (ops); | ||
401 | list_del(&node->list); | ||
402 | kfree (node); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | MODULE_AUTHOR("Derrick J Brashear"); | ||
407 | MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port"); | ||
408 | MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port"); | ||
409 | MODULE_LICENSE("GPL"); | ||
410 | |||
411 | module_init(parport_sunbpp_init) | ||
412 | module_exit(parport_sunbpp_exit) | ||