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