diff options
Diffstat (limited to 'drivers/net/wan/sealevel.c')
-rw-r--r-- | drivers/net/wan/sealevel.c | 361 |
1 files changed, 142 insertions, 219 deletions
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index 44a89df1b8bf..c0235844a4d5 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * | 8 | * |
9 | * (c) Copyright 1999, 2001 Alan Cox | 9 | * (c) Copyright 1999, 2001 Alan Cox |
10 | * (c) Copyright 2001 Red Hat Inc. | 10 | * (c) Copyright 2001 Red Hat Inc. |
11 | * Generic HDLC port Copyright (C) 2008 Krzysztof Halasa <khc@pm.waw.pl> | ||
11 | * | 12 | * |
12 | */ | 13 | */ |
13 | 14 | ||
@@ -19,6 +20,7 @@ | |||
19 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
20 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
21 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/hdlc.h> | ||
22 | #include <linux/ioport.h> | 24 | #include <linux/ioport.h> |
23 | #include <linux/init.h> | 25 | #include <linux/init.h> |
24 | #include <net/arp.h> | 26 | #include <net/arp.h> |
@@ -27,22 +29,19 @@ | |||
27 | #include <asm/io.h> | 29 | #include <asm/io.h> |
28 | #include <asm/dma.h> | 30 | #include <asm/dma.h> |
29 | #include <asm/byteorder.h> | 31 | #include <asm/byteorder.h> |
30 | #include <net/syncppp.h> | ||
31 | #include "z85230.h" | 32 | #include "z85230.h" |
32 | 33 | ||
33 | 34 | ||
34 | struct slvl_device | 35 | struct slvl_device |
35 | { | 36 | { |
36 | void *if_ptr; /* General purpose pointer (used by SPPP) */ | ||
37 | struct z8530_channel *chan; | 37 | struct z8530_channel *chan; |
38 | struct ppp_device pppdev; | ||
39 | int channel; | 38 | int channel; |
40 | }; | 39 | }; |
41 | 40 | ||
42 | 41 | ||
43 | struct slvl_board | 42 | struct slvl_board |
44 | { | 43 | { |
45 | struct slvl_device *dev[2]; | 44 | struct slvl_device dev[2]; |
46 | struct z8530_dev board; | 45 | struct z8530_dev board; |
47 | int iobase; | 46 | int iobase; |
48 | }; | 47 | }; |
@@ -51,72 +50,69 @@ struct slvl_board | |||
51 | * Network driver support routines | 50 | * Network driver support routines |
52 | */ | 51 | */ |
53 | 52 | ||
53 | static inline struct slvl_device* dev_to_chan(struct net_device *dev) | ||
54 | { | ||
55 | return (struct slvl_device *)dev_to_hdlc(dev)->priv; | ||
56 | } | ||
57 | |||
54 | /* | 58 | /* |
55 | * Frame receive. Simple for our card as we do sync ppp and there | 59 | * Frame receive. Simple for our card as we do HDLC and there |
56 | * is no funny garbage involved | 60 | * is no funny garbage involved |
57 | */ | 61 | */ |
58 | 62 | ||
59 | static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) | 63 | static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) |
60 | { | 64 | { |
61 | /* Drop the CRC - it's not a good idea to try and negotiate it ;) */ | 65 | /* Drop the CRC - it's not a good idea to try and negotiate it ;) */ |
62 | skb_trim(skb, skb->len-2); | 66 | skb_trim(skb, skb->len - 2); |
63 | skb->protocol=htons(ETH_P_WAN_PPP); | 67 | skb->protocol = hdlc_type_trans(skb, c->netdevice); |
64 | skb_reset_mac_header(skb); | 68 | skb_reset_mac_header(skb); |
65 | skb->dev=c->netdevice; | 69 | skb->dev = c->netdevice; |
66 | /* | ||
67 | * Send it to the PPP layer. We don't have time to process | ||
68 | * it right now. | ||
69 | */ | ||
70 | netif_rx(skb); | 70 | netif_rx(skb); |
71 | c->netdevice->last_rx = jiffies; | 71 | c->netdevice->last_rx = jiffies; |
72 | } | 72 | } |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * We've been placed in the UP state | 75 | * We've been placed in the UP state |
76 | */ | 76 | */ |
77 | 77 | ||
78 | static int sealevel_open(struct net_device *d) | 78 | static int sealevel_open(struct net_device *d) |
79 | { | 79 | { |
80 | struct slvl_device *slvl=d->priv; | 80 | struct slvl_device *slvl = dev_to_chan(d); |
81 | int err = -1; | 81 | int err = -1; |
82 | int unit = slvl->channel; | 82 | int unit = slvl->channel; |
83 | 83 | ||
84 | /* | 84 | /* |
85 | * Link layer up. | 85 | * Link layer up. |
86 | */ | 86 | */ |
87 | 87 | ||
88 | switch(unit) | 88 | switch (unit) |
89 | { | 89 | { |
90 | case 0: | 90 | case 0: |
91 | err=z8530_sync_dma_open(d, slvl->chan); | 91 | err = z8530_sync_dma_open(d, slvl->chan); |
92 | break; | 92 | break; |
93 | case 1: | 93 | case 1: |
94 | err=z8530_sync_open(d, slvl->chan); | 94 | err = z8530_sync_open(d, slvl->chan); |
95 | break; | 95 | break; |
96 | } | 96 | } |
97 | 97 | ||
98 | if(err) | 98 | if (err) |
99 | return err; | 99 | return err; |
100 | /* | 100 | |
101 | * Begin PPP | 101 | err = hdlc_open(d); |
102 | */ | 102 | if (err) { |
103 | err=sppp_open(d); | 103 | switch (unit) { |
104 | if(err) | ||
105 | { | ||
106 | switch(unit) | ||
107 | { | ||
108 | case 0: | 104 | case 0: |
109 | z8530_sync_dma_close(d, slvl->chan); | 105 | z8530_sync_dma_close(d, slvl->chan); |
110 | break; | 106 | break; |
111 | case 1: | 107 | case 1: |
112 | z8530_sync_close(d, slvl->chan); | 108 | z8530_sync_close(d, slvl->chan); |
113 | break; | 109 | break; |
114 | } | 110 | } |
115 | return err; | 111 | return err; |
116 | } | 112 | } |
117 | 113 | ||
118 | slvl->chan->rx_function=sealevel_input; | 114 | slvl->chan->rx_function = sealevel_input; |
119 | 115 | ||
120 | /* | 116 | /* |
121 | * Go go go | 117 | * Go go go |
122 | */ | 118 | */ |
@@ -126,26 +122,19 @@ static int sealevel_open(struct net_device *d) | |||
126 | 122 | ||
127 | static int sealevel_close(struct net_device *d) | 123 | static int sealevel_close(struct net_device *d) |
128 | { | 124 | { |
129 | struct slvl_device *slvl=d->priv; | 125 | struct slvl_device *slvl = dev_to_chan(d); |
130 | int unit = slvl->channel; | 126 | int unit = slvl->channel; |
131 | 127 | ||
132 | /* | 128 | /* |
133 | * Discard new frames | 129 | * Discard new frames |
134 | */ | 130 | */ |
135 | |||
136 | slvl->chan->rx_function=z8530_null_rx; | ||
137 | |||
138 | /* | ||
139 | * PPP off | ||
140 | */ | ||
141 | sppp_close(d); | ||
142 | /* | ||
143 | * Link layer down | ||
144 | */ | ||
145 | 131 | ||
132 | slvl->chan->rx_function = z8530_null_rx; | ||
133 | |||
134 | hdlc_close(d); | ||
146 | netif_stop_queue(d); | 135 | netif_stop_queue(d); |
147 | 136 | ||
148 | switch(unit) | 137 | switch (unit) |
149 | { | 138 | { |
150 | case 0: | 139 | case 0: |
151 | z8530_sync_dma_close(d, slvl->chan); | 140 | z8530_sync_dma_close(d, slvl->chan); |
@@ -159,210 +148,153 @@ static int sealevel_close(struct net_device *d) | |||
159 | 148 | ||
160 | static int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) | 149 | static int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) |
161 | { | 150 | { |
162 | /* struct slvl_device *slvl=d->priv; | 151 | /* struct slvl_device *slvl=dev_to_chan(d); |
163 | z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */ | 152 | z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */ |
164 | return sppp_do_ioctl(d, ifr,cmd); | 153 | return hdlc_ioctl(d, ifr, cmd); |
165 | } | ||
166 | |||
167 | static struct net_device_stats *sealevel_get_stats(struct net_device *d) | ||
168 | { | ||
169 | struct slvl_device *slvl=d->priv; | ||
170 | if(slvl) | ||
171 | return z8530_get_stats(slvl->chan); | ||
172 | else | ||
173 | return NULL; | ||
174 | } | 154 | } |
175 | 155 | ||
176 | /* | 156 | /* |
177 | * Passed PPP frames, fire them downwind. | 157 | * Passed network frames, fire them downwind. |
178 | */ | 158 | */ |
179 | 159 | ||
180 | static int sealevel_queue_xmit(struct sk_buff *skb, struct net_device *d) | 160 | static int sealevel_queue_xmit(struct sk_buff *skb, struct net_device *d) |
181 | { | 161 | { |
182 | struct slvl_device *slvl=d->priv; | 162 | return z8530_queue_xmit(dev_to_chan(d)->chan, skb); |
183 | return z8530_queue_xmit(slvl->chan, skb); | ||
184 | } | 163 | } |
185 | 164 | ||
186 | static int sealevel_neigh_setup(struct neighbour *n) | 165 | static int sealevel_attach(struct net_device *dev, unsigned short encoding, |
166 | unsigned short parity) | ||
187 | { | 167 | { |
188 | if (n->nud_state == NUD_NONE) { | 168 | if (encoding == ENCODING_NRZ && parity == PARITY_CRC16_PR1_CCITT) |
189 | n->ops = &arp_broken_ops; | 169 | return 0; |
190 | n->output = n->ops->output; | 170 | return -EINVAL; |
191 | } | ||
192 | return 0; | ||
193 | } | 171 | } |
194 | 172 | ||
195 | static int sealevel_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) | 173 | static int slvl_setup(struct slvl_device *sv, int iobase, int irq) |
196 | { | 174 | { |
197 | if (p->tbl->family == AF_INET) { | 175 | struct net_device *dev = alloc_hdlcdev(sv); |
198 | p->neigh_setup = sealevel_neigh_setup; | 176 | if (!dev) |
199 | p->ucast_probes = 0; | 177 | return -1; |
200 | p->mcast_probes = 0; | 178 | |
179 | dev_to_hdlc(dev)->attach = sealevel_attach; | ||
180 | dev_to_hdlc(dev)->xmit = sealevel_queue_xmit; | ||
181 | dev->open = sealevel_open; | ||
182 | dev->stop = sealevel_close; | ||
183 | dev->do_ioctl = sealevel_ioctl; | ||
184 | dev->base_addr = iobase; | ||
185 | dev->irq = irq; | ||
186 | |||
187 | if (register_hdlc_device(dev)) { | ||
188 | printk(KERN_ERR "sealevel: unable to register HDLC device\n"); | ||
189 | free_netdev(dev); | ||
190 | return -1; | ||
201 | } | 191 | } |
202 | return 0; | ||
203 | } | ||
204 | 192 | ||
205 | static int sealevel_attach(struct net_device *dev) | 193 | sv->chan->netdevice = dev; |
206 | { | ||
207 | struct slvl_device *sv = dev->priv; | ||
208 | sppp_attach(&sv->pppdev); | ||
209 | return 0; | 194 | return 0; |
210 | } | 195 | } |
211 | 196 | ||
212 | static void sealevel_detach(struct net_device *dev) | ||
213 | { | ||
214 | sppp_detach(dev); | ||
215 | } | ||
216 | |||
217 | static void slvl_setup(struct net_device *d) | ||
218 | { | ||
219 | d->open = sealevel_open; | ||
220 | d->stop = sealevel_close; | ||
221 | d->init = sealevel_attach; | ||
222 | d->uninit = sealevel_detach; | ||
223 | d->hard_start_xmit = sealevel_queue_xmit; | ||
224 | d->get_stats = sealevel_get_stats; | ||
225 | d->set_multicast_list = NULL; | ||
226 | d->do_ioctl = sealevel_ioctl; | ||
227 | d->neigh_setup = sealevel_neigh_setup_dev; | ||
228 | d->set_mac_address = NULL; | ||
229 | |||
230 | } | ||
231 | |||
232 | static inline struct slvl_device *slvl_alloc(int iobase, int irq) | ||
233 | { | ||
234 | struct net_device *d; | ||
235 | struct slvl_device *sv; | ||
236 | |||
237 | d = alloc_netdev(sizeof(struct slvl_device), "hdlc%d", | ||
238 | slvl_setup); | ||
239 | |||
240 | if (!d) | ||
241 | return NULL; | ||
242 | |||
243 | sv = d->priv; | ||
244 | d->ml_priv = sv; | ||
245 | sv->if_ptr = &sv->pppdev; | ||
246 | sv->pppdev.dev = d; | ||
247 | d->base_addr = iobase; | ||
248 | d->irq = irq; | ||
249 | |||
250 | return sv; | ||
251 | } | ||
252 | |||
253 | 197 | ||
254 | /* | 198 | /* |
255 | * Allocate and setup Sealevel board. | 199 | * Allocate and setup Sealevel board. |
256 | */ | 200 | */ |
257 | 201 | ||
258 | static __init struct slvl_board *slvl_init(int iobase, int irq, | 202 | static __init struct slvl_board *slvl_init(int iobase, int irq, |
259 | int txdma, int rxdma, int slow) | 203 | int txdma, int rxdma, int slow) |
260 | { | 204 | { |
261 | struct z8530_dev *dev; | 205 | struct z8530_dev *dev; |
262 | struct slvl_board *b; | 206 | struct slvl_board *b; |
263 | 207 | ||
264 | /* | 208 | /* |
265 | * Get the needed I/O space | 209 | * Get the needed I/O space |
266 | */ | 210 | */ |
267 | 211 | ||
268 | if(!request_region(iobase, 8, "Sealevel 4021")) | 212 | if (!request_region(iobase, 8, "Sealevel 4021")) { |
269 | { | 213 | printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", |
270 | printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); | 214 | iobase); |
271 | return NULL; | 215 | return NULL; |
272 | } | 216 | } |
273 | |||
274 | b = kzalloc(sizeof(struct slvl_board), GFP_KERNEL); | ||
275 | if(!b) | ||
276 | goto fail3; | ||
277 | 217 | ||
278 | if (!(b->dev[0]= slvl_alloc(iobase, irq))) | 218 | b = kzalloc(sizeof(struct slvl_board), GFP_KERNEL); |
279 | goto fail2; | 219 | if (!b) |
220 | goto err_kzalloc; | ||
280 | 221 | ||
281 | b->dev[0]->chan = &b->board.chanA; | 222 | b->dev[0].chan = &b->board.chanA; |
282 | b->dev[0]->channel = 0; | 223 | b->dev[0].channel = 0; |
283 | |||
284 | if (!(b->dev[1] = slvl_alloc(iobase, irq))) | ||
285 | goto fail1_0; | ||
286 | 224 | ||
287 | b->dev[1]->chan = &b->board.chanB; | 225 | b->dev[1].chan = &b->board.chanB; |
288 | b->dev[1]->channel = 1; | 226 | b->dev[1].channel = 1; |
289 | 227 | ||
290 | dev = &b->board; | 228 | dev = &b->board; |
291 | 229 | ||
292 | /* | 230 | /* |
293 | * Stuff in the I/O addressing | 231 | * Stuff in the I/O addressing |
294 | */ | 232 | */ |
295 | 233 | ||
296 | dev->active = 0; | 234 | dev->active = 0; |
297 | 235 | ||
298 | b->iobase = iobase; | 236 | b->iobase = iobase; |
299 | 237 | ||
300 | /* | 238 | /* |
301 | * Select 8530 delays for the old board | 239 | * Select 8530 delays for the old board |
302 | */ | 240 | */ |
303 | 241 | ||
304 | if(slow) | 242 | if (slow) |
305 | iobase |= Z8530_PORT_SLEEP; | 243 | iobase |= Z8530_PORT_SLEEP; |
306 | 244 | ||
307 | dev->chanA.ctrlio=iobase+1; | 245 | dev->chanA.ctrlio = iobase + 1; |
308 | dev->chanA.dataio=iobase; | 246 | dev->chanA.dataio = iobase; |
309 | dev->chanB.ctrlio=iobase+3; | 247 | dev->chanB.ctrlio = iobase + 3; |
310 | dev->chanB.dataio=iobase+2; | 248 | dev->chanB.dataio = iobase + 2; |
311 | 249 | ||
312 | dev->chanA.irqs=&z8530_nop; | 250 | dev->chanA.irqs = &z8530_nop; |
313 | dev->chanB.irqs=&z8530_nop; | 251 | dev->chanB.irqs = &z8530_nop; |
314 | 252 | ||
315 | /* | 253 | /* |
316 | * Assert DTR enable DMA | 254 | * Assert DTR enable DMA |
317 | */ | 255 | */ |
318 | 256 | ||
319 | outb(3|(1<<7), b->iobase+4); | 257 | outb(3 | (1 << 7), b->iobase + 4); |
320 | 258 | ||
321 | 259 | ||
322 | /* We want a fast IRQ for this device. Actually we'd like an even faster | 260 | /* We want a fast IRQ for this device. Actually we'd like an even faster |
323 | IRQ ;) - This is one driver RtLinux is made for */ | 261 | IRQ ;) - This is one driver RtLinux is made for */ |
324 | 262 | ||
325 | if(request_irq(irq, &z8530_interrupt, IRQF_DISABLED, "SeaLevel", dev)<0) | 263 | if (request_irq(irq, &z8530_interrupt, IRQF_DISABLED, |
326 | { | 264 | "SeaLevel", dev) < 0) { |
327 | printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq); | 265 | printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq); |
328 | goto fail1_1; | 266 | goto err_request_irq; |
329 | } | 267 | } |
330 | 268 | ||
331 | dev->irq=irq; | 269 | dev->irq = irq; |
332 | dev->chanA.private=&b->dev[0]; | 270 | dev->chanA.private = &b->dev[0]; |
333 | dev->chanB.private=&b->dev[1]; | 271 | dev->chanB.private = &b->dev[1]; |
334 | dev->chanA.netdevice=b->dev[0]->pppdev.dev; | 272 | dev->chanA.dev = dev; |
335 | dev->chanB.netdevice=b->dev[1]->pppdev.dev; | 273 | dev->chanB.dev = dev; |
336 | dev->chanA.dev=dev; | 274 | |
337 | dev->chanB.dev=dev; | 275 | dev->chanA.txdma = 3; |
338 | 276 | dev->chanA.rxdma = 1; | |
339 | dev->chanA.txdma=3; | 277 | if (request_dma(dev->chanA.txdma, "SeaLevel (TX)")) |
340 | dev->chanA.rxdma=1; | 278 | goto err_dma_tx; |
341 | if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0) | 279 | |
342 | goto fail; | 280 | if (request_dma(dev->chanA.rxdma, "SeaLevel (RX)")) |
343 | 281 | goto err_dma_rx; | |
344 | if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0) | 282 | |
345 | goto dmafail; | ||
346 | |||
347 | disable_irq(irq); | 283 | disable_irq(irq); |
348 | 284 | ||
349 | /* | 285 | /* |
350 | * Begin normal initialise | 286 | * Begin normal initialise |
351 | */ | 287 | */ |
352 | 288 | ||
353 | if(z8530_init(dev)!=0) | 289 | if (z8530_init(dev) != 0) { |
354 | { | ||
355 | printk(KERN_ERR "Z8530 series device not found.\n"); | 290 | printk(KERN_ERR "Z8530 series device not found.\n"); |
356 | enable_irq(irq); | 291 | enable_irq(irq); |
357 | goto dmafail2; | 292 | goto free_hw; |
358 | } | 293 | } |
359 | if(dev->type==Z85C30) | 294 | if (dev->type == Z85C30) { |
360 | { | ||
361 | z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); | 295 | z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); |
362 | z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); | 296 | z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); |
363 | } | 297 | } else { |
364 | else | ||
365 | { | ||
366 | z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); | 298 | z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); |
367 | z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); | 299 | z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); |
368 | } | 300 | } |
@@ -370,36 +302,31 @@ static __init struct slvl_board *slvl_init(int iobase, int irq, | |||
370 | /* | 302 | /* |
371 | * Now we can take the IRQ | 303 | * Now we can take the IRQ |
372 | */ | 304 | */ |
373 | 305 | ||
374 | enable_irq(irq); | 306 | enable_irq(irq); |
375 | 307 | ||
376 | if (register_netdev(b->dev[0]->pppdev.dev)) | 308 | if (slvl_setup(&b->dev[0], iobase, irq)) |
377 | goto dmafail2; | 309 | goto free_hw; |
378 | 310 | if (slvl_setup(&b->dev[1], iobase, irq)) | |
379 | if (register_netdev(b->dev[1]->pppdev.dev)) | 311 | goto free_netdev0; |
380 | goto fail_unit; | ||
381 | 312 | ||
382 | z8530_describe(dev, "I/O", iobase); | 313 | z8530_describe(dev, "I/O", iobase); |
383 | dev->active=1; | 314 | dev->active = 1; |
384 | return b; | 315 | return b; |
385 | 316 | ||
386 | fail_unit: | 317 | free_netdev0: |
387 | unregister_netdev(b->dev[0]->pppdev.dev); | 318 | unregister_hdlc_device(b->dev[0].chan->netdevice); |
388 | 319 | free_netdev(b->dev[0].chan->netdevice); | |
389 | dmafail2: | 320 | free_hw: |
390 | free_dma(dev->chanA.rxdma); | 321 | free_dma(dev->chanA.rxdma); |
391 | dmafail: | 322 | err_dma_rx: |
392 | free_dma(dev->chanA.txdma); | 323 | free_dma(dev->chanA.txdma); |
393 | fail: | 324 | err_dma_tx: |
394 | free_irq(irq, dev); | 325 | free_irq(irq, dev); |
395 | fail1_1: | 326 | err_request_irq: |
396 | free_netdev(b->dev[1]->pppdev.dev); | ||
397 | fail1_0: | ||
398 | free_netdev(b->dev[0]->pppdev.dev); | ||
399 | fail2: | ||
400 | kfree(b); | 327 | kfree(b); |
401 | fail3: | 328 | err_kzalloc: |
402 | release_region(iobase,8); | 329 | release_region(iobase, 8); |
403 | return NULL; | 330 | return NULL; |
404 | } | 331 | } |
405 | 332 | ||
@@ -408,14 +335,14 @@ static void __exit slvl_shutdown(struct slvl_board *b) | |||
408 | int u; | 335 | int u; |
409 | 336 | ||
410 | z8530_shutdown(&b->board); | 337 | z8530_shutdown(&b->board); |
411 | 338 | ||
412 | for(u=0; u<2; u++) | 339 | for (u = 0; u < 2; u++) |
413 | { | 340 | { |
414 | struct net_device *d = b->dev[u]->pppdev.dev; | 341 | struct net_device *d = b->dev[u].chan->netdevice; |
415 | unregister_netdev(d); | 342 | unregister_hdlc_device(d); |
416 | free_netdev(d); | 343 | free_netdev(d); |
417 | } | 344 | } |
418 | 345 | ||
419 | free_irq(b->board.irq, &b->board); | 346 | free_irq(b->board.irq, &b->board); |
420 | free_dma(b->board.chanA.rxdma); | 347 | free_dma(b->board.chanA.rxdma); |
421 | free_dma(b->board.chanA.txdma); | 348 | free_dma(b->board.chanA.txdma); |
@@ -451,10 +378,6 @@ static struct slvl_board *slvl_unit; | |||
451 | 378 | ||
452 | static int __init slvl_init_module(void) | 379 | static int __init slvl_init_module(void) |
453 | { | 380 | { |
454 | #ifdef MODULE | ||
455 | printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.02.\n"); | ||
456 | printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); | ||
457 | #endif | ||
458 | slvl_unit = slvl_init(io, irq, txdma, rxdma, slow); | 381 | slvl_unit = slvl_init(io, irq, txdma, rxdma, slow); |
459 | 382 | ||
460 | return slvl_unit ? 0 : -ENODEV; | 383 | return slvl_unit ? 0 : -ENODEV; |