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/net/wan/hostess_sv11.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/net/wan/hostess_sv11.c')
-rw-r--r-- | drivers/net/wan/hostess_sv11.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c new file mode 100644 index 000000000000..7db1d1d0bb34 --- /dev/null +++ b/drivers/net/wan/hostess_sv11.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /* | ||
2 | * Comtrol SV11 card driver | ||
3 | * | ||
4 | * This is a slightly odd Z85230 synchronous driver. All you need to | ||
5 | * know basically is | ||
6 | * | ||
7 | * Its a genuine Z85230 | ||
8 | * | ||
9 | * It supports DMA using two DMA channels in SYNC mode. The driver doesn't | ||
10 | * use these facilities | ||
11 | * | ||
12 | * The control port is at io+1, the data at io+3 and turning off the DMA | ||
13 | * is done by writing 0 to io+4 | ||
14 | * | ||
15 | * The hardware does the bus handling to avoid the need for delays between | ||
16 | * touching control registers. | ||
17 | * | ||
18 | * Port B isnt wired (why - beats me) | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/net.h> | ||
25 | #include <linux/skbuff.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/if_arp.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/ioport.h> | ||
30 | #include <net/arp.h> | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | #include <asm/dma.h> | ||
34 | #include <asm/byteorder.h> | ||
35 | #include <net/syncppp.h> | ||
36 | #include "z85230.h" | ||
37 | |||
38 | static int dma; | ||
39 | |||
40 | struct sv11_device | ||
41 | { | ||
42 | void *if_ptr; /* General purpose pointer (used by SPPP) */ | ||
43 | struct z8530_dev sync; | ||
44 | struct ppp_device netdev; | ||
45 | }; | ||
46 | |||
47 | /* | ||
48 | * Network driver support routines | ||
49 | */ | ||
50 | |||
51 | /* | ||
52 | * Frame receive. Simple for our card as we do sync ppp and there | ||
53 | * is no funny garbage involved | ||
54 | */ | ||
55 | |||
56 | static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) | ||
57 | { | ||
58 | /* Drop the CRC - it's not a good idea to try and negotiate it ;) */ | ||
59 | skb_trim(skb, skb->len-2); | ||
60 | skb->protocol=__constant_htons(ETH_P_WAN_PPP); | ||
61 | skb->mac.raw=skb->data; | ||
62 | skb->dev=c->netdevice; | ||
63 | /* | ||
64 | * Send it to the PPP layer. We don't have time to process | ||
65 | * it right now. | ||
66 | */ | ||
67 | netif_rx(skb); | ||
68 | c->netdevice->last_rx = jiffies; | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * We've been placed in the UP state | ||
73 | */ | ||
74 | |||
75 | static int hostess_open(struct net_device *d) | ||
76 | { | ||
77 | struct sv11_device *sv11=d->priv; | ||
78 | int err = -1; | ||
79 | |||
80 | /* | ||
81 | * Link layer up | ||
82 | */ | ||
83 | switch(dma) | ||
84 | { | ||
85 | case 0: | ||
86 | err=z8530_sync_open(d, &sv11->sync.chanA); | ||
87 | break; | ||
88 | case 1: | ||
89 | err=z8530_sync_dma_open(d, &sv11->sync.chanA); | ||
90 | break; | ||
91 | case 2: | ||
92 | err=z8530_sync_txdma_open(d, &sv11->sync.chanA); | ||
93 | break; | ||
94 | } | ||
95 | |||
96 | if(err) | ||
97 | return err; | ||
98 | /* | ||
99 | * Begin PPP | ||
100 | */ | ||
101 | err=sppp_open(d); | ||
102 | if(err) | ||
103 | { | ||
104 | switch(dma) | ||
105 | { | ||
106 | case 0: | ||
107 | z8530_sync_close(d, &sv11->sync.chanA); | ||
108 | break; | ||
109 | case 1: | ||
110 | z8530_sync_dma_close(d, &sv11->sync.chanA); | ||
111 | break; | ||
112 | case 2: | ||
113 | z8530_sync_txdma_close(d, &sv11->sync.chanA); | ||
114 | break; | ||
115 | } | ||
116 | return err; | ||
117 | } | ||
118 | sv11->sync.chanA.rx_function=hostess_input; | ||
119 | |||
120 | /* | ||
121 | * Go go go | ||
122 | */ | ||
123 | |||
124 | netif_start_queue(d); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int hostess_close(struct net_device *d) | ||
129 | { | ||
130 | struct sv11_device *sv11=d->priv; | ||
131 | /* | ||
132 | * Discard new frames | ||
133 | */ | ||
134 | sv11->sync.chanA.rx_function=z8530_null_rx; | ||
135 | /* | ||
136 | * PPP off | ||
137 | */ | ||
138 | sppp_close(d); | ||
139 | /* | ||
140 | * Link layer down | ||
141 | */ | ||
142 | netif_stop_queue(d); | ||
143 | |||
144 | switch(dma) | ||
145 | { | ||
146 | case 0: | ||
147 | z8530_sync_close(d, &sv11->sync.chanA); | ||
148 | break; | ||
149 | case 1: | ||
150 | z8530_sync_dma_close(d, &sv11->sync.chanA); | ||
151 | break; | ||
152 | case 2: | ||
153 | z8530_sync_txdma_close(d, &sv11->sync.chanA); | ||
154 | break; | ||
155 | } | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) | ||
160 | { | ||
161 | /* struct sv11_device *sv11=d->priv; | ||
162 | z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */ | ||
163 | return sppp_do_ioctl(d, ifr,cmd); | ||
164 | } | ||
165 | |||
166 | static struct net_device_stats *hostess_get_stats(struct net_device *d) | ||
167 | { | ||
168 | struct sv11_device *sv11=d->priv; | ||
169 | if(sv11) | ||
170 | return z8530_get_stats(&sv11->sync.chanA); | ||
171 | else | ||
172 | return NULL; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * Passed PPP frames, fire them downwind. | ||
177 | */ | ||
178 | |||
179 | static int hostess_queue_xmit(struct sk_buff *skb, struct net_device *d) | ||
180 | { | ||
181 | struct sv11_device *sv11=d->priv; | ||
182 | return z8530_queue_xmit(&sv11->sync.chanA, skb); | ||
183 | } | ||
184 | |||
185 | static int hostess_neigh_setup(struct neighbour *n) | ||
186 | { | ||
187 | if (n->nud_state == NUD_NONE) { | ||
188 | n->ops = &arp_broken_ops; | ||
189 | n->output = n->ops->output; | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int hostess_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) | ||
195 | { | ||
196 | if (p->tbl->family == AF_INET) { | ||
197 | p->neigh_setup = hostess_neigh_setup; | ||
198 | p->ucast_probes = 0; | ||
199 | p->mcast_probes = 0; | ||
200 | } | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static void sv11_setup(struct net_device *dev) | ||
205 | { | ||
206 | dev->open = hostess_open; | ||
207 | dev->stop = hostess_close; | ||
208 | dev->hard_start_xmit = hostess_queue_xmit; | ||
209 | dev->get_stats = hostess_get_stats; | ||
210 | dev->do_ioctl = hostess_ioctl; | ||
211 | dev->neigh_setup = hostess_neigh_setup_dev; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * Description block for a Comtrol Hostess SV11 card | ||
216 | */ | ||
217 | |||
218 | static struct sv11_device *sv11_init(int iobase, int irq) | ||
219 | { | ||
220 | struct z8530_dev *dev; | ||
221 | struct sv11_device *sv; | ||
222 | |||
223 | /* | ||
224 | * Get the needed I/O space | ||
225 | */ | ||
226 | |||
227 | if(!request_region(iobase, 8, "Comtrol SV11")) | ||
228 | { | ||
229 | printk(KERN_WARNING "hostess: I/O 0x%X already in use.\n", iobase); | ||
230 | return NULL; | ||
231 | } | ||
232 | |||
233 | sv=(struct sv11_device *)kmalloc(sizeof(struct sv11_device), GFP_KERNEL); | ||
234 | if(!sv) | ||
235 | goto fail3; | ||
236 | |||
237 | memset(sv, 0, sizeof(*sv)); | ||
238 | sv->if_ptr=&sv->netdev; | ||
239 | |||
240 | sv->netdev.dev = alloc_netdev(0, "hdlc%d", sv11_setup); | ||
241 | if(!sv->netdev.dev) | ||
242 | goto fail2; | ||
243 | |||
244 | SET_MODULE_OWNER(sv->netdev.dev); | ||
245 | |||
246 | dev=&sv->sync; | ||
247 | |||
248 | /* | ||
249 | * Stuff in the I/O addressing | ||
250 | */ | ||
251 | |||
252 | dev->active = 0; | ||
253 | |||
254 | dev->chanA.ctrlio=iobase+1; | ||
255 | dev->chanA.dataio=iobase+3; | ||
256 | dev->chanB.ctrlio=-1; | ||
257 | dev->chanB.dataio=-1; | ||
258 | dev->chanA.irqs=&z8530_nop; | ||
259 | dev->chanB.irqs=&z8530_nop; | ||
260 | |||
261 | outb(0, iobase+4); /* DMA off */ | ||
262 | |||
263 | /* We want a fast IRQ for this device. Actually we'd like an even faster | ||
264 | IRQ ;) - This is one driver RtLinux is made for */ | ||
265 | |||
266 | if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "Hostess SV11", dev)<0) | ||
267 | { | ||
268 | printk(KERN_WARNING "hostess: IRQ %d already in use.\n", irq); | ||
269 | goto fail1; | ||
270 | } | ||
271 | |||
272 | dev->irq=irq; | ||
273 | dev->chanA.private=sv; | ||
274 | dev->chanA.netdevice=sv->netdev.dev; | ||
275 | dev->chanA.dev=dev; | ||
276 | dev->chanB.dev=dev; | ||
277 | |||
278 | if(dma) | ||
279 | { | ||
280 | /* | ||
281 | * You can have DMA off or 1 and 3 thats the lot | ||
282 | * on the Comtrol. | ||
283 | */ | ||
284 | dev->chanA.txdma=3; | ||
285 | dev->chanA.rxdma=1; | ||
286 | outb(0x03|0x08, iobase+4); /* DMA on */ | ||
287 | if(request_dma(dev->chanA.txdma, "Hostess SV/11 (TX)")!=0) | ||
288 | goto fail; | ||
289 | |||
290 | if(dma==1) | ||
291 | { | ||
292 | if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0) | ||
293 | goto dmafail; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /* Kill our private IRQ line the hostess can end up chattering | ||
298 | until the configuration is set */ | ||
299 | disable_irq(irq); | ||
300 | |||
301 | /* | ||
302 | * Begin normal initialise | ||
303 | */ | ||
304 | |||
305 | if(z8530_init(dev)!=0) | ||
306 | { | ||
307 | printk(KERN_ERR "Z8530 series device not found.\n"); | ||
308 | enable_irq(irq); | ||
309 | goto dmafail2; | ||
310 | } | ||
311 | z8530_channel_load(&dev->chanB, z8530_dead_port); | ||
312 | if(dev->type==Z85C30) | ||
313 | z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); | ||
314 | else | ||
315 | z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); | ||
316 | |||
317 | enable_irq(irq); | ||
318 | |||
319 | |||
320 | /* | ||
321 | * Now we can take the IRQ | ||
322 | */ | ||
323 | if(dev_alloc_name(dev->chanA.netdevice,"hdlc%d")>=0) | ||
324 | { | ||
325 | struct net_device *d=dev->chanA.netdevice; | ||
326 | |||
327 | /* | ||
328 | * Initialise the PPP components | ||
329 | */ | ||
330 | sppp_attach(&sv->netdev); | ||
331 | |||
332 | /* | ||
333 | * Local fields | ||
334 | */ | ||
335 | |||
336 | d->base_addr = iobase; | ||
337 | d->irq = irq; | ||
338 | d->priv = sv; | ||
339 | |||
340 | if(register_netdev(d)) | ||
341 | { | ||
342 | printk(KERN_ERR "%s: unable to register device.\n", | ||
343 | d->name); | ||
344 | sppp_detach(d); | ||
345 | goto dmafail2; | ||
346 | } | ||
347 | |||
348 | z8530_describe(dev, "I/O", iobase); | ||
349 | dev->active=1; | ||
350 | return sv; | ||
351 | } | ||
352 | dmafail2: | ||
353 | if(dma==1) | ||
354 | free_dma(dev->chanA.rxdma); | ||
355 | dmafail: | ||
356 | if(dma) | ||
357 | free_dma(dev->chanA.txdma); | ||
358 | fail: | ||
359 | free_irq(irq, dev); | ||
360 | fail1: | ||
361 | free_netdev(sv->netdev.dev); | ||
362 | fail2: | ||
363 | kfree(sv); | ||
364 | fail3: | ||
365 | release_region(iobase,8); | ||
366 | return NULL; | ||
367 | } | ||
368 | |||
369 | static void sv11_shutdown(struct sv11_device *dev) | ||
370 | { | ||
371 | sppp_detach(dev->netdev.dev); | ||
372 | unregister_netdev(dev->netdev.dev); | ||
373 | z8530_shutdown(&dev->sync); | ||
374 | free_irq(dev->sync.irq, dev); | ||
375 | if(dma) | ||
376 | { | ||
377 | if(dma==1) | ||
378 | free_dma(dev->sync.chanA.rxdma); | ||
379 | free_dma(dev->sync.chanA.txdma); | ||
380 | } | ||
381 | release_region(dev->sync.chanA.ctrlio-1, 8); | ||
382 | free_netdev(dev->netdev.dev); | ||
383 | kfree(dev); | ||
384 | } | ||
385 | |||
386 | #ifdef MODULE | ||
387 | |||
388 | static int io=0x200; | ||
389 | static int irq=9; | ||
390 | |||
391 | module_param(io, int, 0); | ||
392 | MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card"); | ||
393 | module_param(dma, int, 0); | ||
394 | MODULE_PARM_DESC(dma, "Set this to 1 to use DMA1/DMA3 for TX/RX"); | ||
395 | module_param(irq, int, 0); | ||
396 | MODULE_PARM_DESC(irq, "The interrupt line setting for the Comtrol Hostess SV11 card"); | ||
397 | |||
398 | MODULE_AUTHOR("Alan Cox"); | ||
399 | MODULE_LICENSE("GPL"); | ||
400 | MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11"); | ||
401 | |||
402 | static struct sv11_device *sv11_unit; | ||
403 | |||
404 | int init_module(void) | ||
405 | { | ||
406 | printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.03.\n"); | ||
407 | printk(KERN_INFO "(c) Copyright 2001, Red Hat Inc.\n"); | ||
408 | if((sv11_unit=sv11_init(io,irq))==NULL) | ||
409 | return -ENODEV; | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | void cleanup_module(void) | ||
414 | { | ||
415 | if(sv11_unit) | ||
416 | sv11_shutdown(sv11_unit); | ||
417 | } | ||
418 | |||
419 | #endif | ||
420 | |||