blob: bc2c1c7fb1a45aa8cbc6fd39e592275efe88df39 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * SDLA An implementation of a driver for the Sangoma S502/S508 series
4 * multi-protocol PC interface card. Initial offering is with
5 * the DLCI driver, providing Frame Relay support for linux.
6 *
7 * Global definitions for the Frame relay interface.
8 *
9 * Version: @(#)sdla.c 0.30 12 Sep 1996
10 *
11 * Credits: Sangoma Technologies, for the use of 2 cards for an extended
12 * period of time.
13 * David Mandelstam <dm@sangoma.com> for getting me started on
14 * this project, and incentive to complete it.
15 * Gene Kozen <74604.152@compuserve.com> for providing me with
16 * important information about the cards.
17 *
18 * Author: Mike McLagan <mike.mclagan@linux.org>
19 *
20 * Changes:
21 * 0.15 Mike McLagan Improved error handling, packet dropping
22 * 0.20 Mike McLagan New transmit/receive flags for config
23 * If in FR mode, don't accept packets from
24 * non DLCI devices.
25 * 0.25 Mike McLagan Fixed problem with rejecting packets
26 * from non DLCI devices.
27 * 0.30 Mike McLagan Fixed kernel panic when used with modified
28 * ifconfig
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 */
30
Joe Perches86fb0cc2011-06-26 19:01:31 +000031#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/module.h>
34#include <linux/kernel.h>
35#include <linux/types.h>
36#include <linux/fcntl.h>
37#include <linux/interrupt.h>
38#include <linux/ptrace.h>
39#include <linux/ioport.h>
40#include <linux/in.h>
41#include <linux/slab.h>
42#include <linux/string.h>
43#include <linux/timer.h>
44#include <linux/errno.h>
45#include <linux/init.h>
46#include <linux/netdevice.h>
47#include <linux/skbuff.h>
48#include <linux/if_arp.h>
49#include <linux/if_frad.h>
50#include <linux/sdla.h>
51#include <linux/bitops.h>
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <asm/io.h>
54#include <asm/dma.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080055#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
58
Randy Dunlap96ebb922006-06-25 05:48:37 -070059static unsigned int valid_port[] = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Randy Dunlap96ebb922006-06-25 05:48:37 -070061static unsigned int valid_mem[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
63 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
64 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
65 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,
66 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000};
67
68static DEFINE_SPINLOCK(sdla_lock);
69
70/*********************************************************
71 *
72 * these are the core routines that access the card itself
73 *
74 *********************************************************/
75
76#define SDLA_WINDOW(dev,addr) outb((((addr) >> 13) & 0x1F), (dev)->base_addr + SDLA_REG_Z80_WINDOW)
77
78static void __sdla_read(struct net_device *dev, int addr, void *buf, short len)
79{
80 char *temp;
81 const void *base;
82 int offset, bytes;
83
84 temp = buf;
85 while(len)
86 {
87 offset = addr & SDLA_ADDR_MASK;
88 bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
89 base = (const void *) (dev->mem_start + offset);
90
91 SDLA_WINDOW(dev, addr);
92 memcpy(temp, base, bytes);
93
94 addr += bytes;
95 temp += bytes;
96 len -= bytes;
97 }
98}
99
100static void sdla_read(struct net_device *dev, int addr, void *buf, short len)
101{
102 unsigned long flags;
103 spin_lock_irqsave(&sdla_lock, flags);
104 __sdla_read(dev, addr, buf, len);
105 spin_unlock_irqrestore(&sdla_lock, flags);
106}
107
108static void __sdla_write(struct net_device *dev, int addr,
109 const void *buf, short len)
110{
111 const char *temp;
112 void *base;
113 int offset, bytes;
114
115 temp = buf;
116 while(len)
117 {
118 offset = addr & SDLA_ADDR_MASK;
119 bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
120 base = (void *) (dev->mem_start + offset);
121
122 SDLA_WINDOW(dev, addr);
123 memcpy(base, temp, bytes);
124
125 addr += bytes;
126 temp += bytes;
127 len -= bytes;
128 }
129}
130
131static void sdla_write(struct net_device *dev, int addr,
132 const void *buf, short len)
133{
134 unsigned long flags;
135
136 spin_lock_irqsave(&sdla_lock, flags);
137 __sdla_write(dev, addr, buf, len);
138 spin_unlock_irqrestore(&sdla_lock, flags);
139}
140
141
142static void sdla_clear(struct net_device *dev)
143{
144 unsigned long flags;
145 char *base;
146 int len, addr, bytes;
147
148 len = 65536;
149 addr = 0;
150 bytes = SDLA_WINDOW_SIZE;
151 base = (void *) dev->mem_start;
152
153 spin_lock_irqsave(&sdla_lock, flags);
154 while(len)
155 {
156 SDLA_WINDOW(dev, addr);
157 memset(base, 0, bytes);
158
159 addr += bytes;
160 len -= bytes;
161 }
162 spin_unlock_irqrestore(&sdla_lock, flags);
163
164}
165
166static char sdla_byte(struct net_device *dev, int addr)
167{
168 unsigned long flags;
169 char byte, *temp;
170
171 temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
172
173 spin_lock_irqsave(&sdla_lock, flags);
174 SDLA_WINDOW(dev, addr);
175 byte = *temp;
176 spin_unlock_irqrestore(&sdla_lock, flags);
177
Eric Dumazet807540b2010-09-23 05:40:09 +0000178 return byte;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
Adrian Bunk7665a082005-09-09 23:17:28 -0700181static void sdla_stop(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182{
183 struct frad_local *flp;
184
Wang Chen8f15ea42008-11-12 23:38:36 -0800185 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 switch(flp->type)
187 {
188 case SDLA_S502A:
189 outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
190 flp->state = SDLA_HALT;
191 break;
192 case SDLA_S502E:
193 outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
194 outb(SDLA_S502E_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
195 flp->state = SDLA_S502E_ENABLE;
196 break;
197 case SDLA_S507:
198 flp->state &= ~SDLA_CPUEN;
199 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
200 break;
201 case SDLA_S508:
202 flp->state &= ~SDLA_CPUEN;
203 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
204 break;
205 }
206}
207
Adrian Bunk7665a082005-09-09 23:17:28 -0700208static void sdla_start(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209{
210 struct frad_local *flp;
211
Wang Chen8f15ea42008-11-12 23:38:36 -0800212 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 switch(flp->type)
214 {
215 case SDLA_S502A:
216 outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL);
217 outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
218 flp->state = SDLA_S502A_START;
219 break;
220 case SDLA_S502E:
221 outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL);
222 outb(0x00, dev->base_addr + SDLA_REG_CONTROL);
223 flp->state = 0;
224 break;
225 case SDLA_S507:
226 flp->state |= SDLA_CPUEN;
227 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
228 break;
229 case SDLA_S508:
230 flp->state |= SDLA_CPUEN;
231 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
232 break;
233 }
234}
235
236/****************************************************
237 *
238 * this is used for the S502A/E cards to determine
239 * the speed of the onboard CPU. Calibration is
240 * necessary for the Frame Relay code uploaded
241 * later. Incorrect results cause timing problems
242 * with link checks & status messages
243 *
244 ***************************************************/
245
Adrian Bunk7665a082005-09-09 23:17:28 -0700246static int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247{
248 unsigned long start, done, now;
249 char resp, *temp;
250
251 start = now = jiffies;
252 done = jiffies + jiffs;
253
254 temp = (void *)dev->mem_start;
255 temp += z80_addr & SDLA_ADDR_MASK;
256
257 resp = ~resp1;
258 while (time_before(jiffies, done) && (resp != resp1) && (!resp2 || (resp != resp2)))
259 {
260 if (jiffies != now)
261 {
262 SDLA_WINDOW(dev, z80_addr);
263 now = jiffies;
264 resp = *temp;
265 }
266 }
Eric Dumazet807540b2010-09-23 05:40:09 +0000267 return time_before(jiffies, done) ? jiffies - start : -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268}
269
270/* constants for Z80 CPU speed */
271#define Z80_READY '1' /* Z80 is ready to begin */
272#define LOADER_READY '2' /* driver is ready to begin */
273#define Z80_SCC_OK '3' /* SCC is on board */
274#define Z80_SCC_BAD '4' /* SCC was not found */
275
276static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr)
277{
278 int jiffs;
279 char data;
280
281 sdla_start(dev);
282 if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)
Eric Dumazet807540b2010-09-23 05:40:09 +0000283 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 data = LOADER_READY;
286 sdla_write(dev, 0, &data, 1);
287
288 if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)
Eric Dumazet807540b2010-09-23 05:40:09 +0000289 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 sdla_stop(dev);
292 sdla_read(dev, 0, &data, 1);
293
294 if (data == Z80_SCC_BAD)
295 {
296 printk("%s: SCC bad\n", dev->name);
Eric Dumazet807540b2010-09-23 05:40:09 +0000297 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
299
300 if (data != Z80_SCC_OK)
Eric Dumazet807540b2010-09-23 05:40:09 +0000301 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 if (jiffs < 165)
304 ifr->ifr_mtu = SDLA_CPU_16M;
305 else if (jiffs < 220)
306 ifr->ifr_mtu = SDLA_CPU_10M;
307 else if (jiffs < 258)
308 ifr->ifr_mtu = SDLA_CPU_8M;
309 else if (jiffs < 357)
310 ifr->ifr_mtu = SDLA_CPU_7M;
311 else if (jiffs < 467)
312 ifr->ifr_mtu = SDLA_CPU_5M;
313 else
314 ifr->ifr_mtu = SDLA_CPU_3M;
315
Eric Dumazet807540b2010-09-23 05:40:09 +0000316 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317}
318
319/************************************************
320 *
321 * Direct interaction with the Frame Relay code
322 * starts here.
323 *
324 ************************************************/
325
326struct _dlci_stat
327{
Jan Blunck6a878182006-01-08 01:05:07 -0800328 short dlci;
329 char flags;
Eric Dumazetba2d3582010-06-02 18:10:09 +0000330} __packed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332struct _frad_stat
333{
334 char flags;
335 struct _dlci_stat dlcis[SDLA_MAX_DLCI];
336};
337
338static void sdla_errors(struct net_device *dev, int cmd, int dlci, int ret, int len, void *data)
339{
340 struct _dlci_stat *pstatus;
341 short *pdlci;
342 int i;
343 char *state, line[30];
344
345 switch (ret)
346 {
347 case SDLA_RET_MODEM:
348 state = data;
349 if (*state & SDLA_MODEM_DCD_LOW)
Joe Perches86fb0cc2011-06-26 19:01:31 +0000350 netdev_info(dev, "Modem DCD unexpectedly low!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if (*state & SDLA_MODEM_CTS_LOW)
Joe Perches86fb0cc2011-06-26 19:01:31 +0000352 netdev_info(dev, "Modem CTS unexpectedly low!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 /* I should probably do something about this! */
354 break;
355
356 case SDLA_RET_CHANNEL_OFF:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000357 netdev_info(dev, "Channel became inoperative!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 /* same here */
359 break;
360
361 case SDLA_RET_CHANNEL_ON:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000362 netdev_info(dev, "Channel became operative!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 /* same here */
364 break;
365
366 case SDLA_RET_DLCI_STATUS:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000367 netdev_info(dev, "Status change reported by Access Node\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 len /= sizeof(struct _dlci_stat);
369 for(pstatus = data, i=0;i < len;i++,pstatus++)
370 {
371 if (pstatus->flags & SDLA_DLCI_NEW)
372 state = "new";
373 else if (pstatus->flags & SDLA_DLCI_DELETED)
374 state = "deleted";
375 else if (pstatus->flags & SDLA_DLCI_ACTIVE)
376 state = "active";
377 else
378 {
379 sprintf(line, "unknown status: %02X", pstatus->flags);
380 state = line;
381 }
Joe Perches86fb0cc2011-06-26 19:01:31 +0000382 netdev_info(dev, "DLCI %i: %s\n",
383 pstatus->dlci, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 /* same here */
385 }
386 break;
387
388 case SDLA_RET_DLCI_UNKNOWN:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000389 netdev_info(dev, "Received unknown DLCIs:");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 len /= sizeof(short);
391 for(pdlci = data,i=0;i < len;i++,pdlci++)
Joe Perches86fb0cc2011-06-26 19:01:31 +0000392 pr_cont(" %i", *pdlci);
393 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 break;
395
396 case SDLA_RET_TIMEOUT:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000397 netdev_err(dev, "Command timed out!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 break;
399
400 case SDLA_RET_BUF_OVERSIZE:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000401 netdev_info(dev, "Bc/CIR overflow, acceptable size is %i\n",
402 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 break;
404
405 case SDLA_RET_BUF_TOO_BIG:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000406 netdev_info(dev, "Buffer size over specified max of %i\n",
407 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 break;
409
410 case SDLA_RET_CHANNEL_INACTIVE:
411 case SDLA_RET_DLCI_INACTIVE:
412 case SDLA_RET_CIR_OVERFLOW:
413 case SDLA_RET_NO_BUFS:
414 if (cmd == SDLA_INFORMATION_WRITE)
415 break;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500416 fallthrough;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418 default:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000419 netdev_dbg(dev, "Cmd 0x%02X generated return code 0x%02X\n",
420 cmd, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 /* Further processing could be done here */
422 break;
423 }
424}
425
426static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags,
427 void *inbuf, short inlen, void *outbuf, short *outlen)
428{
429 static struct _frad_stat status;
430 struct frad_local *flp;
431 struct sdla_cmd *cmd_buf;
432 unsigned long pflags;
433 unsigned long jiffs;
434 int ret, waiting, len;
435 long window;
436
Wang Chen8f15ea42008-11-12 23:38:36 -0800437 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
439 cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
440 ret = 0;
441 len = 0;
442 jiffs = jiffies + HZ; /* 1 second is plenty */
443
444 spin_lock_irqsave(&sdla_lock, pflags);
445 SDLA_WINDOW(dev, window);
446 cmd_buf->cmd = cmd;
447 cmd_buf->dlci = dlci;
448 cmd_buf->flags = flags;
449
450 if (inbuf)
451 memcpy(cmd_buf->data, inbuf, inlen);
452
453 cmd_buf->length = inlen;
454
455 cmd_buf->opp_flag = 1;
456 spin_unlock_irqrestore(&sdla_lock, pflags);
457
458 waiting = 1;
459 len = 0;
460 while (waiting && time_before_eq(jiffies, jiffs))
461 {
462 if (waiting++ % 3)
463 {
464 spin_lock_irqsave(&sdla_lock, pflags);
465 SDLA_WINDOW(dev, window);
466 waiting = ((volatile int)(cmd_buf->opp_flag));
467 spin_unlock_irqrestore(&sdla_lock, pflags);
468 }
469 }
470
471 if (!waiting)
472 {
473
474 spin_lock_irqsave(&sdla_lock, pflags);
475 SDLA_WINDOW(dev, window);
476 ret = cmd_buf->retval;
477 len = cmd_buf->length;
478 if (outbuf && outlen)
479 {
480 *outlen = *outlen >= len ? len : *outlen;
481
482 if (*outlen)
483 memcpy(outbuf, cmd_buf->data, *outlen);
484 }
485
486 /* This is a local copy that's used for error handling */
487 if (ret)
488 memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
489
490 spin_unlock_irqrestore(&sdla_lock, pflags);
491 }
492 else
493 ret = SDLA_RET_TIMEOUT;
494
495 if (ret != SDLA_RET_OK)
496 sdla_errors(dev, cmd, dlci, ret, len, &status);
497
Eric Dumazet807540b2010-09-23 05:40:09 +0000498 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499}
500
501/***********************************************
502 *
503 * these functions are called by the DLCI driver
504 *
505 ***********************************************/
506
507static int sdla_reconfig(struct net_device *dev);
508
Adrian Bunk7665a082005-09-09 23:17:28 -0700509static int sdla_activate(struct net_device *slave, struct net_device *master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 struct frad_local *flp;
512 int i;
513
Wang Chen8f15ea42008-11-12 23:38:36 -0800514 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516 for(i=0;i<CONFIG_DLCI_MAX;i++)
517 if (flp->master[i] == master)
518 break;
519
520 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000521 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
523 flp->dlci[i] = abs(flp->dlci[i]);
524
525 if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
526 sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
527
Eric Dumazet807540b2010-09-23 05:40:09 +0000528 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529}
530
Adrian Bunk7665a082005-09-09 23:17:28 -0700531static int sdla_deactivate(struct net_device *slave, struct net_device *master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532{
533 struct frad_local *flp;
534 int i;
535
Wang Chen8f15ea42008-11-12 23:38:36 -0800536 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
538 for(i=0;i<CONFIG_DLCI_MAX;i++)
539 if (flp->master[i] == master)
540 break;
541
542 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000543 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 flp->dlci[i] = -abs(flp->dlci[i]);
546
547 if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
548 sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
549
Eric Dumazet807540b2010-09-23 05:40:09 +0000550 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551}
552
Adrian Bunk7665a082005-09-09 23:17:28 -0700553static int sdla_assoc(struct net_device *slave, struct net_device *master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
555 struct frad_local *flp;
556 int i;
557
558 if (master->type != ARPHRD_DLCI)
Eric Dumazet807540b2010-09-23 05:40:09 +0000559 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
Wang Chen8f15ea42008-11-12 23:38:36 -0800561 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 for(i=0;i<CONFIG_DLCI_MAX;i++)
564 {
565 if (!flp->master[i])
566 break;
567 if (abs(flp->dlci[i]) == *(short *)(master->dev_addr))
Eric Dumazet807540b2010-09-23 05:40:09 +0000568 return -EADDRINUSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
570
571 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000572 return -EMLINK; /* #### Alan: Comments on this ?? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
574
575 flp->master[i] = master;
576 flp->dlci[i] = -*(short *)(master->dev_addr);
577 master->mtu = slave->mtu;
578
579 if (netif_running(slave)) {
580 if (flp->config.station == FRAD_STATION_CPE)
581 sdla_reconfig(slave);
582 else
583 sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
584 }
585
Eric Dumazet807540b2010-09-23 05:40:09 +0000586 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587}
588
Adrian Bunk7665a082005-09-09 23:17:28 -0700589static int sdla_deassoc(struct net_device *slave, struct net_device *master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590{
591 struct frad_local *flp;
592 int i;
593
Wang Chen8f15ea42008-11-12 23:38:36 -0800594 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 for(i=0;i<CONFIG_DLCI_MAX;i++)
597 if (flp->master[i] == master)
598 break;
599
600 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000601 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603 flp->master[i] = NULL;
604 flp->dlci[i] = 0;
605
606
607 if (netif_running(slave)) {
608 if (flp->config.station == FRAD_STATION_CPE)
609 sdla_reconfig(slave);
610 else
611 sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
612 }
613
Eric Dumazet807540b2010-09-23 05:40:09 +0000614 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615}
616
Adrian Bunk7665a082005-09-09 23:17:28 -0700617static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
619 struct frad_local *flp;
620 struct dlci_local *dlp;
621 int i;
622 short len, ret;
623
Wang Chen8f15ea42008-11-12 23:38:36 -0800624 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 for(i=0;i<CONFIG_DLCI_MAX;i++)
627 if (flp->master[i] == master)
628 break;
629
630 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000631 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Wang Chen8f15ea42008-11-12 23:38:36 -0800633 dlp = netdev_priv(master);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
635 ret = SDLA_RET_OK;
636 len = sizeof(struct dlci_conf);
637 if (netif_running(slave)) {
638 if (get)
639 ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
640 NULL, 0, &dlp->config, &len);
641 else
642 ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
643 &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
644 }
645
Eric Dumazet807540b2010-09-23 05:40:09 +0000646 return ret == SDLA_RET_OK ? 0 : -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
649/**************************
650 *
651 * now for the Linux driver
652 *
653 **************************/
654
655/* NOTE: the DLCI driver deals with freeing the SKB!! */
Stephen Hemmingerd71a6742009-08-31 19:50:47 +0000656static netdev_tx_t sdla_transmit(struct sk_buff *skb,
Stephen Hemminger38482422009-09-04 05:33:46 +0000657 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658{
659 struct frad_local *flp;
660 int ret, addr, accept, i;
661 short size;
662 unsigned long flags;
663 struct buf_entry *pbuf;
664
Wang Chen8f15ea42008-11-12 23:38:36 -0800665 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 ret = 0;
667 accept = 1;
668
669 netif_stop_queue(dev);
670
671 /*
672 * stupid GateD insists on setting up the multicast router thru us
673 * and we're ill equipped to handle a non Frame Relay packet at this
674 * time!
675 */
676
677 accept = 1;
678 switch (dev->type)
679 {
680 case ARPHRD_FRAD:
681 if (skb->dev->type != ARPHRD_DLCI)
682 {
Joe Perches86fb0cc2011-06-26 19:01:31 +0000683 netdev_warn(dev, "Non DLCI device, type %i, tried to send on FRAD module\n",
684 skb->dev->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 accept = 0;
686 }
687 break;
688 default:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000689 netdev_warn(dev, "unknown firmware type 0x%04X\n",
690 dev->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 accept = 0;
692 break;
693 }
694 if (accept)
695 {
696 /* this is frame specific, but till there's a PPP module, it's the default */
697 switch (flp->type)
698 {
699 case SDLA_S502A:
700 case SDLA_S502E:
701 ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
702 break;
703 case SDLA_S508:
704 size = sizeof(addr);
705 ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
706 if (ret == SDLA_RET_OK)
707 {
708
709 spin_lock_irqsave(&sdla_lock, flags);
710 SDLA_WINDOW(dev, addr);
Krzysztof Kozlowski00c06882020-01-04 15:31:43 +0100711 pbuf = (void *)(dev->mem_start + (addr & SDLA_ADDR_MASK));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 __sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
713 SDLA_WINDOW(dev, addr);
714 pbuf->opp_flag = 1;
715 spin_unlock_irqrestore(&sdla_lock, flags);
716 }
717 break;
718 }
Stephen Hemminger38482422009-09-04 05:33:46 +0000719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 switch (ret)
721 {
722 case SDLA_RET_OK:
Stephen Hemmingerac995332009-03-26 15:11:25 +0000723 dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 break;
725
726 case SDLA_RET_CIR_OVERFLOW:
727 case SDLA_RET_BUF_OVERSIZE:
728 case SDLA_RET_NO_BUFS:
Stephen Hemmingerac995332009-03-26 15:11:25 +0000729 dev->stats.tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 break;
731
732 default:
Stephen Hemmingerac995332009-03-26 15:11:25 +0000733 dev->stats.tx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 break;
735 }
736 }
737 netif_wake_queue(dev);
738 for(i=0;i<CONFIG_DLCI_MAX;i++)
739 {
740 if(flp->master[i]!=NULL)
741 netif_wake_queue(flp->master[i]);
742 }
Stephen Hemminger38482422009-09-04 05:33:46 +0000743
744 dev_kfree_skb(skb);
Stephen Hemmingerd71a6742009-08-31 19:50:47 +0000745 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746}
747
748static void sdla_receive(struct net_device *dev)
749{
750 struct net_device *master;
751 struct frad_local *flp;
752 struct dlci_local *dlp;
753 struct sk_buff *skb;
754
755 struct sdla_cmd *cmd;
756 struct buf_info *pbufi;
757 struct buf_entry *pbuf;
758
759 unsigned long flags;
760 int i=0, received, success, addr, buf_base, buf_top;
761 short dlci, len, len2, split;
762
Wang Chen8f15ea42008-11-12 23:38:36 -0800763 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 success = 1;
765 received = addr = buf_top = buf_base = 0;
766 len = dlci = 0;
767 skb = NULL;
768 master = NULL;
769 cmd = NULL;
770 pbufi = NULL;
771 pbuf = NULL;
772
773 spin_lock_irqsave(&sdla_lock, flags);
774
775 switch (flp->type)
776 {
777 case SDLA_S502A:
778 case SDLA_S502E:
779 cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
780 SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
781 success = cmd->opp_flag;
782 if (!success)
783 break;
784
785 dlci = cmd->dlci;
786 len = cmd->length;
787 break;
788
789 case SDLA_S508:
790 pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
791 SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
792 pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
793 success = pbuf->opp_flag;
794 if (!success)
795 break;
796
797 buf_top = pbufi->buf_top;
798 buf_base = pbufi->buf_base;
799 dlci = pbuf->dlci;
800 len = pbuf->length;
801 addr = pbuf->buf_addr;
802 break;
803 }
804
805 /* common code, find the DLCI and get the SKB */
806 if (success)
807 {
808 for (i=0;i<CONFIG_DLCI_MAX;i++)
809 if (flp->dlci[i] == dlci)
810 break;
811
812 if (i == CONFIG_DLCI_MAX)
813 {
Joe Perches86fb0cc2011-06-26 19:01:31 +0000814 netdev_notice(dev, "Received packet from invalid DLCI %i, ignoring\n",
815 dlci);
Stephen Hemmingerac995332009-03-26 15:11:25 +0000816 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 success = 0;
818 }
819 }
820
821 if (success)
822 {
823 master = flp->master[i];
824 skb = dev_alloc_skb(len + sizeof(struct frhdr));
825 if (skb == NULL)
826 {
Joe Perches86fb0cc2011-06-26 19:01:31 +0000827 netdev_notice(dev, "Memory squeeze, dropping packet\n");
Stephen Hemmingerac995332009-03-26 15:11:25 +0000828 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 success = 0;
830 }
831 else
832 skb_reserve(skb, sizeof(struct frhdr));
833 }
834
835 /* pick up the data */
836 switch (flp->type)
837 {
838 case SDLA_S502A:
839 case SDLA_S502E:
840 if (success)
841 __sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
842
843 SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
844 cmd->opp_flag = 0;
845 break;
846
847 case SDLA_S508:
848 if (success)
849 {
850 /* is this buffer split off the end of the internal ring buffer */
851 split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
852 len2 = len - split;
853
854 __sdla_read(dev, addr, skb_put(skb, len2), len2);
855 if (split)
856 __sdla_read(dev, buf_base, skb_put(skb, split), split);
857 }
858
859 /* increment the buffer we're looking at */
860 SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
861 flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
862 pbuf->opp_flag = 0;
863 break;
864 }
865
866 if (success)
867 {
Stephen Hemmingerac995332009-03-26 15:11:25 +0000868 dev->stats.rx_packets++;
Wang Chen8f15ea42008-11-12 23:38:36 -0800869 dlp = netdev_priv(master);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 (*dlp->receive)(skb, master);
871 }
872
873 spin_unlock_irqrestore(&sdla_lock, flags);
874}
875
Jeff Garzik28fc1f52007-10-29 05:46:16 -0400876static irqreturn_t sdla_isr(int dummy, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 struct net_device *dev;
879 struct frad_local *flp;
880 char byte;
881
882 dev = dev_id;
883
Jeff Garzikc31f28e2006-10-06 14:56:04 -0400884 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886 if (!flp->initialized)
887 {
Joe Perches86fb0cc2011-06-26 19:01:31 +0000888 netdev_warn(dev, "irq %d for uninitialized device\n", dev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return IRQ_NONE;
890 }
891
892 byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE);
893 switch (byte)
894 {
895 case SDLA_INTR_RX:
896 sdla_receive(dev);
897 break;
898
899 /* the command will get an error return, which is processed above */
900 case SDLA_INTR_MODEM:
901 case SDLA_INTR_STATUS:
902 sdla_cmd(dev, SDLA_READ_DLC_STATUS, 0, 0, NULL, 0, NULL, NULL);
903 break;
904
905 case SDLA_INTR_TX:
906 case SDLA_INTR_COMPLETE:
907 case SDLA_INTR_TIMER:
Joe Perches86fb0cc2011-06-26 19:01:31 +0000908 netdev_warn(dev, "invalid irq flag 0x%02X\n", byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 break;
910 }
911
912 /* the S502E requires a manual acknowledgement of the interrupt */
913 if (flp->type == SDLA_S502E)
914 {
915 flp->state &= ~SDLA_S502E_INTACK;
916 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
917 flp->state |= SDLA_S502E_INTACK;
918 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
919 }
920
921 /* this clears the byte, informing the Z80 we're done */
922 byte = 0;
923 sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
924 return IRQ_HANDLED;
925}
926
Kees Cook032cfd62017-10-25 03:53:59 -0700927static void sdla_poll(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
Kees Cook032cfd62017-10-25 03:53:59 -0700929 struct frad_local *flp = from_timer(flp, t, timer);
930 struct net_device *dev = flp->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 if (sdla_byte(dev, SDLA_502_RCV_BUF))
933 sdla_receive(dev);
934
935 flp->timer.expires = 1;
936 add_timer(&flp->timer);
937}
938
939static int sdla_close(struct net_device *dev)
940{
941 struct frad_local *flp;
942 struct intr_info intr;
943 int len, i;
944 short dlcis[CONFIG_DLCI_MAX];
945
Wang Chen8f15ea42008-11-12 23:38:36 -0800946 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 len = 0;
949 for(i=0;i<CONFIG_DLCI_MAX;i++)
950 if (flp->dlci[i])
951 dlcis[len++] = abs(flp->dlci[i]);
952 len *= 2;
953
954 if (flp->config.station == FRAD_STATION_NODE)
955 {
956 for(i=0;i<CONFIG_DLCI_MAX;i++)
957 if (flp->dlci[i] > 0)
958 sdla_cmd(dev, SDLA_DEACTIVATE_DLCI, 0, 0, dlcis, len, NULL, NULL);
959 sdla_cmd(dev, SDLA_DELETE_DLCI, 0, 0, &flp->dlci[i], sizeof(flp->dlci[i]), NULL, NULL);
960 }
961
962 memset(&intr, 0, sizeof(intr));
963 /* let's start up the reception */
964 switch(flp->type)
965 {
966 case SDLA_S502A:
967 del_timer(&flp->timer);
968 break;
969
970 case SDLA_S502E:
971 sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
972 flp->state &= ~SDLA_S502E_INTACK;
973 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
974 break;
975
976 case SDLA_S507:
977 break;
978
979 case SDLA_S508:
980 sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
981 flp->state &= ~SDLA_S508_INTEN;
982 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
983 break;
984 }
985
986 sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
987
988 netif_stop_queue(dev);
989
Eric Dumazet807540b2010-09-23 05:40:09 +0000990 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
993struct conf_data {
994 struct frad_conf config;
995 short dlci[CONFIG_DLCI_MAX];
996};
997
998static int sdla_open(struct net_device *dev)
999{
1000 struct frad_local *flp;
1001 struct dlci_local *dlp;
1002 struct conf_data data;
1003 struct intr_info intr;
1004 int len, i;
1005 char byte;
1006
Wang Chen8f15ea42008-11-12 23:38:36 -08001007 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
1009 if (!flp->initialized)
Eric Dumazet807540b2010-09-23 05:40:09 +00001010 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 if (!flp->configured)
Eric Dumazet807540b2010-09-23 05:40:09 +00001013 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015 /* time to send in the configuration */
1016 len = 0;
1017 for(i=0;i<CONFIG_DLCI_MAX;i++)
1018 if (flp->dlci[i])
1019 data.dlci[len++] = abs(flp->dlci[i]);
1020 len *= 2;
1021
1022 memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
1023 len += sizeof(struct frad_conf);
1024
1025 sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
1026 sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
1027
1028 if (flp->type == SDLA_S508)
1029 flp->buffer = 0;
1030
1031 sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
1032
1033 /* let's start up the reception */
1034 memset(&intr, 0, sizeof(intr));
1035 switch(flp->type)
1036 {
1037 case SDLA_S502A:
1038 flp->timer.expires = 1;
1039 add_timer(&flp->timer);
1040 break;
1041
1042 case SDLA_S502E:
1043 flp->state |= SDLA_S502E_ENABLE;
1044 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
1045 flp->state |= SDLA_S502E_INTACK;
1046 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
1047 byte = 0;
1048 sdla_write(dev, SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
1049 intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
1050 sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
1051 break;
1052
1053 case SDLA_S507:
1054 break;
1055
1056 case SDLA_S508:
1057 flp->state |= SDLA_S508_INTEN;
1058 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
1059 byte = 0;
1060 sdla_write(dev, SDLA_508_IRQ_INTERFACE, &byte, sizeof(byte));
1061 intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
1062 intr.irq = dev->irq;
1063 sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
1064 break;
1065 }
1066
1067 if (flp->config.station == FRAD_STATION_CPE)
1068 {
1069 byte = SDLA_ICS_STATUS_ENQ;
1070 sdla_cmd(dev, SDLA_ISSUE_IN_CHANNEL_SIGNAL, 0, 0, &byte, sizeof(byte), NULL, NULL);
1071 }
1072 else
1073 {
1074 sdla_cmd(dev, SDLA_ADD_DLCI, 0, 0, data.dlci, len - sizeof(struct frad_conf), NULL, NULL);
1075 for(i=0;i<CONFIG_DLCI_MAX;i++)
1076 if (flp->dlci[i] > 0)
1077 sdla_cmd(dev, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], 2*sizeof(flp->dlci[i]), NULL, NULL);
1078 }
1079
1080 /* configure any specific DLCI settings */
1081 for(i=0;i<CONFIG_DLCI_MAX;i++)
1082 if (flp->dlci[i])
1083 {
Wang Chen8f15ea42008-11-12 23:38:36 -08001084 dlp = netdev_priv(flp->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 if (dlp->configured)
1086 sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
1087 }
1088
1089 netif_start_queue(dev);
1090
Eric Dumazet807540b2010-09-23 05:40:09 +00001091 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092}
1093
1094static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, int get)
1095{
1096 struct frad_local *flp;
1097 struct conf_data data;
1098 int i;
1099 short size;
1100
1101 if (dev->type == 0xFFFF)
Eric Dumazet807540b2010-09-23 05:40:09 +00001102 return -EUNATCH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
Wang Chen8f15ea42008-11-12 23:38:36 -08001104 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
1106 if (!get)
1107 {
1108 if (netif_running(dev))
Eric Dumazet807540b2010-09-23 05:40:09 +00001109 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
1111 if(copy_from_user(&data.config, conf, sizeof(struct frad_conf)))
1112 return -EFAULT;
1113
1114 if (data.config.station & ~FRAD_STATION_NODE)
Eric Dumazet807540b2010-09-23 05:40:09 +00001115 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
1117 if (data.config.flags & ~FRAD_VALID_FLAGS)
Eric Dumazet807540b2010-09-23 05:40:09 +00001118 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120 if ((data.config.kbaud < 0) ||
1121 ((data.config.kbaud > 128) && (flp->type != SDLA_S508)))
Eric Dumazet807540b2010-09-23 05:40:09 +00001122 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
1124 if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232))
Eric Dumazet807540b2010-09-23 05:40:09 +00001125 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
1127 if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU))
Eric Dumazet807540b2010-09-23 05:40:09 +00001128 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130 if ((data.config.T391 < 5) || (data.config.T391 > 30))
Eric Dumazet807540b2010-09-23 05:40:09 +00001131 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 if ((data.config.T392 < 5) || (data.config.T392 > 30))
Eric Dumazet807540b2010-09-23 05:40:09 +00001134 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136 if ((data.config.N391 < 1) || (data.config.N391 > 255))
Eric Dumazet807540b2010-09-23 05:40:09 +00001137 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
1139 if ((data.config.N392 < 1) || (data.config.N392 > 10))
Eric Dumazet807540b2010-09-23 05:40:09 +00001140 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
1142 if ((data.config.N393 < 1) || (data.config.N393 > 10))
Eric Dumazet807540b2010-09-23 05:40:09 +00001143 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145 memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
1146 flp->config.flags |= SDLA_DIRECT_RECV;
1147
1148 if (flp->type == SDLA_S508)
1149 flp->config.flags |= SDLA_TX70_RX30;
1150
1151 if (dev->mtu != flp->config.mtu)
1152 {
1153 /* this is required to change the MTU */
1154 dev->mtu = flp->config.mtu;
1155 for(i=0;i<CONFIG_DLCI_MAX;i++)
1156 if (flp->master[i])
1157 flp->master[i]->mtu = flp->config.mtu;
1158 }
1159
1160 flp->config.mtu += sizeof(struct frhdr);
1161
1162 /* off to the races! */
1163 if (!flp->configured)
1164 sdla_start(dev);
1165
1166 flp->configured = 1;
1167 }
1168 else
1169 {
1170 /* no sense reading if the CPU isn't started */
1171 if (netif_running(dev))
1172 {
1173 size = sizeof(data);
1174 if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
Eric Dumazet807540b2010-09-23 05:40:09 +00001175 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 }
1177 else
1178 if (flp->configured)
1179 memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
1180 else
1181 memset(&data.config, 0, sizeof(struct frad_conf));
1182
1183 memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
1184 data.config.flags &= FRAD_VALID_FLAGS;
1185 data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
1186 return copy_to_user(conf, &data.config, sizeof(struct frad_conf))?-EFAULT:0;
1187 }
1188
Eric Dumazet807540b2010-09-23 05:40:09 +00001189 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190}
1191
1192static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int read)
1193{
1194 struct sdla_mem mem;
1195 char *temp;
1196
1197 if(copy_from_user(&mem, info, sizeof(mem)))
1198 return -EFAULT;
1199
1200 if (read)
1201 {
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001202 temp = kzalloc(mem.len, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 if (!temp)
Eric Dumazet807540b2010-09-23 05:40:09 +00001204 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 sdla_read(dev, mem.addr, temp, mem.len);
1206 if(copy_to_user(mem.data, temp, mem.len))
1207 {
1208 kfree(temp);
1209 return -EFAULT;
1210 }
1211 kfree(temp);
1212 }
1213 else
1214 {
Julia Lawallc146fc92010-05-21 22:20:26 +00001215 temp = memdup_user(mem.data, mem.len);
1216 if (IS_ERR(temp))
1217 return PTR_ERR(temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 sdla_write(dev, mem.addr, temp, mem.len);
1219 kfree(temp);
1220 }
Eric Dumazet807540b2010-09-23 05:40:09 +00001221 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222}
1223
1224static int sdla_reconfig(struct net_device *dev)
1225{
1226 struct frad_local *flp;
1227 struct conf_data data;
1228 int i, len;
1229
Wang Chen8f15ea42008-11-12 23:38:36 -08001230 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
1232 len = 0;
1233 for(i=0;i<CONFIG_DLCI_MAX;i++)
1234 if (flp->dlci[i])
1235 data.dlci[len++] = flp->dlci[i];
1236 len *= 2;
1237
1238 memcpy(&data, &flp->config, sizeof(struct frad_conf));
1239 len += sizeof(struct frad_conf);
1240
1241 sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
1242 sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
1243 sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
1244
Eric Dumazet807540b2010-09-23 05:40:09 +00001245 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246}
1247
1248static int sdla_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1249{
1250 struct frad_local *flp;
1251
1252 if(!capable(CAP_NET_ADMIN))
1253 return -EPERM;
1254
Wang Chen8f15ea42008-11-12 23:38:36 -08001255 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257 if (!flp->initialized)
Eric Dumazet807540b2010-09-23 05:40:09 +00001258 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 switch (cmd)
1261 {
1262 case FRAD_GET_CONF:
1263 case FRAD_SET_CONF:
Eric Dumazet807540b2010-09-23 05:40:09 +00001264 return sdla_config(dev, ifr->ifr_data, cmd == FRAD_GET_CONF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
1266 case SDLA_IDENTIFY:
1267 ifr->ifr_flags = flp->type;
1268 break;
1269
1270 case SDLA_CPUSPEED:
Eric Dumazet807540b2010-09-23 05:40:09 +00001271 return sdla_cpuspeed(dev, ifr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
1273/* ==========================================================
1274NOTE: This is rather a useless action right now, as the
1275 current driver does not support protocols other than
1276 FR. However, Sangoma has modules for a number of
1277 other protocols in the works.
1278============================================================*/
1279 case SDLA_PROTOCOL:
1280 if (flp->configured)
Eric Dumazet807540b2010-09-23 05:40:09 +00001281 return -EALREADY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
1283 switch (ifr->ifr_flags)
1284 {
1285 case ARPHRD_FRAD:
1286 dev->type = ifr->ifr_flags;
1287 break;
1288 default:
Eric Dumazet807540b2010-09-23 05:40:09 +00001289 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 }
1291 break;
1292
1293 case SDLA_CLEARMEM:
1294 sdla_clear(dev);
1295 break;
1296
1297 case SDLA_WRITEMEM:
1298 case SDLA_READMEM:
1299 if(!capable(CAP_SYS_RAWIO))
1300 return -EPERM;
Eric Dumazet807540b2010-09-23 05:40:09 +00001301 return sdla_xfer(dev, ifr->ifr_data, cmd == SDLA_READMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
1303 case SDLA_START:
1304 sdla_start(dev);
1305 break;
1306
1307 case SDLA_STOP:
1308 sdla_stop(dev);
1309 break;
1310
1311 default:
Eric Dumazet807540b2010-09-23 05:40:09 +00001312 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 }
Eric Dumazet807540b2010-09-23 05:40:09 +00001314 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315}
1316
Adrian Bunk7665a082005-09-09 23:17:28 -07001317static int sdla_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 if (netif_running(dev))
Eric Dumazet807540b2010-09-23 05:40:09 +00001320 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322 /* for now, you can't change the MTU! */
Eric Dumazet807540b2010-09-23 05:40:09 +00001323 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324}
1325
Adrian Bunk7665a082005-09-09 23:17:28 -07001326static int sdla_set_config(struct net_device *dev, struct ifmap *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327{
1328 struct frad_local *flp;
1329 int i;
1330 char byte;
1331 unsigned base;
1332 int err = -EINVAL;
1333
Wang Chen8f15ea42008-11-12 23:38:36 -08001334 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
1336 if (flp->initialized)
Eric Dumazet807540b2010-09-23 05:40:09 +00001337 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
Alejandro Martinez Ruize9edda62007-10-15 03:37:43 +02001339 for(i=0; i < ARRAY_SIZE(valid_port); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (valid_port[i] == map->base_addr)
1341 break;
1342
Alejandro Martinez Ruize9edda62007-10-15 03:37:43 +02001343 if (i == ARRAY_SIZE(valid_port))
Eric Dumazet807540b2010-09-23 05:40:09 +00001344 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){
Joe Perches86fb0cc2011-06-26 19:01:31 +00001347 pr_warn("io-port 0x%04lx in use\n", dev->base_addr);
Eric Dumazet807540b2010-09-23 05:40:09 +00001348 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 }
1350 base = map->base_addr;
1351
1352 /* test for card types, S502A, S502E, S507, S508 */
1353 /* these tests shut down the card completely, so clear the state */
1354 flp->type = SDLA_UNKNOWN;
1355 flp->state = 0;
1356
1357 for(i=1;i<SDLA_IO_EXTENTS;i++)
1358 if (inb(base + i) != 0xFF)
1359 break;
1360
1361 if (i == SDLA_IO_EXTENTS) {
1362 outb(SDLA_HALT, base + SDLA_REG_Z80_CONTROL);
1363 if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x08) {
1364 outb(SDLA_S502E_INTACK, base + SDLA_REG_CONTROL);
1365 if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x0C) {
1366 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1367 flp->type = SDLA_S502E;
1368 goto got_type;
1369 }
1370 }
1371 }
1372
1373 for(byte=inb(base),i=0;i<SDLA_IO_EXTENTS;i++)
1374 if (inb(base + i) != byte)
1375 break;
1376
1377 if (i == SDLA_IO_EXTENTS) {
1378 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1379 if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x30) {
1380 outb(SDLA_S507_ENABLE, base + SDLA_REG_CONTROL);
1381 if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x32) {
1382 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1383 flp->type = SDLA_S507;
1384 goto got_type;
1385 }
1386 }
1387 }
1388
1389 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1390 if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x00) {
1391 outb(SDLA_S508_INTEN, base + SDLA_REG_CONTROL);
1392 if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x10) {
1393 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1394 flp->type = SDLA_S508;
1395 goto got_type;
1396 }
1397 }
1398
1399 outb(SDLA_S502A_HALT, base + SDLA_REG_CONTROL);
1400 if (inb(base + SDLA_S502_STS) == 0x40) {
1401 outb(SDLA_S502A_START, base + SDLA_REG_CONTROL);
1402 if (inb(base + SDLA_S502_STS) == 0x40) {
1403 outb(SDLA_S502A_INTEN, base + SDLA_REG_CONTROL);
1404 if (inb(base + SDLA_S502_STS) == 0x44) {
1405 outb(SDLA_S502A_START, base + SDLA_REG_CONTROL);
1406 flp->type = SDLA_S502A;
1407 goto got_type;
1408 }
1409 }
1410 }
1411
Joe Perches86fb0cc2011-06-26 19:01:31 +00001412 netdev_notice(dev, "Unknown card type\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 err = -ENODEV;
1414 goto fail;
1415
1416got_type:
1417 switch(base) {
1418 case 0x270:
1419 case 0x280:
1420 case 0x380:
1421 case 0x390:
1422 if (flp->type != SDLA_S508 && flp->type != SDLA_S507)
1423 goto fail;
1424 }
1425
1426 switch (map->irq) {
1427 case 2:
1428 if (flp->type != SDLA_S502E)
1429 goto fail;
1430 break;
1431
1432 case 10:
1433 case 11:
1434 case 12:
1435 case 15:
1436 case 4:
1437 if (flp->type != SDLA_S508 && flp->type != SDLA_S507)
1438 goto fail;
1439 break;
1440 case 3:
1441 case 5:
1442 case 7:
1443 if (flp->type == SDLA_S502A)
1444 goto fail;
1445 break;
1446
1447 default:
1448 goto fail;
1449 }
1450
1451 err = -EAGAIN;
Joe Perchesa0607fd2009-11-18 23:29:17 -08001452 if (request_irq(dev->irq, sdla_isr, 0, dev->name, dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 goto fail;
1454
1455 if (flp->type == SDLA_S507) {
1456 switch(dev->irq) {
1457 case 3:
1458 flp->state = SDLA_S507_IRQ3;
1459 break;
1460 case 4:
1461 flp->state = SDLA_S507_IRQ4;
1462 break;
1463 case 5:
1464 flp->state = SDLA_S507_IRQ5;
1465 break;
1466 case 7:
1467 flp->state = SDLA_S507_IRQ7;
1468 break;
1469 case 10:
1470 flp->state = SDLA_S507_IRQ10;
1471 break;
1472 case 11:
1473 flp->state = SDLA_S507_IRQ11;
1474 break;
1475 case 12:
1476 flp->state = SDLA_S507_IRQ12;
1477 break;
1478 case 15:
1479 flp->state = SDLA_S507_IRQ15;
1480 break;
1481 }
1482 }
1483
Alejandro Martinez Ruize9edda62007-10-15 03:37:43 +02001484 for(i=0; i < ARRAY_SIZE(valid_mem); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 if (valid_mem[i] == map->mem_start)
1486 break;
1487
1488 err = -EINVAL;
Alejandro Martinez Ruize9edda62007-10-15 03:37:43 +02001489 if (i == ARRAY_SIZE(valid_mem))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 goto fail2;
1491
1492 if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E)
1493 goto fail2;
1494
1495 if (flp->type != SDLA_S507 && map->mem_start >> 16 == 0x0B)
1496 goto fail2;
1497
1498 if (flp->type == SDLA_S507 && map->mem_start >> 16 == 0x0D)
1499 goto fail2;
1500
1501 byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0;
1502 byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0));
1503 switch(flp->type) {
1504 case SDLA_S502A:
1505 case SDLA_S502E:
1506 switch (map->mem_start >> 16) {
1507 case 0x0A:
1508 byte |= SDLA_S502_SEG_A;
1509 break;
1510 case 0x0C:
1511 byte |= SDLA_S502_SEG_C;
1512 break;
1513 case 0x0D:
1514 byte |= SDLA_S502_SEG_D;
1515 break;
1516 case 0x0E:
1517 byte |= SDLA_S502_SEG_E;
1518 break;
1519 }
1520 break;
1521 case SDLA_S507:
1522 switch (map->mem_start >> 16) {
1523 case 0x0A:
1524 byte |= SDLA_S507_SEG_A;
1525 break;
1526 case 0x0B:
1527 byte |= SDLA_S507_SEG_B;
1528 break;
1529 case 0x0C:
1530 byte |= SDLA_S507_SEG_C;
1531 break;
1532 case 0x0E:
1533 byte |= SDLA_S507_SEG_E;
1534 break;
1535 }
1536 break;
1537 case SDLA_S508:
1538 switch (map->mem_start >> 16) {
1539 case 0x0A:
1540 byte |= SDLA_S508_SEG_A;
1541 break;
1542 case 0x0C:
1543 byte |= SDLA_S508_SEG_C;
1544 break;
1545 case 0x0D:
1546 byte |= SDLA_S508_SEG_D;
1547 break;
1548 case 0x0E:
1549 byte |= SDLA_S508_SEG_E;
1550 break;
1551 }
1552 break;
1553 }
1554
1555 /* set the memory bits, and enable access */
1556 outb(byte, base + SDLA_REG_PC_WINDOW);
1557
1558 switch(flp->type)
1559 {
1560 case SDLA_S502E:
1561 flp->state = SDLA_S502E_ENABLE;
1562 break;
1563 case SDLA_S507:
1564 flp->state |= SDLA_MEMEN;
1565 break;
1566 case SDLA_S508:
1567 flp->state = SDLA_MEMEN;
1568 break;
1569 }
1570 outb(flp->state, base + SDLA_REG_CONTROL);
1571
1572 dev->irq = map->irq;
1573 dev->base_addr = base;
1574 dev->mem_start = map->mem_start;
1575 dev->mem_end = dev->mem_start + 0x2000;
1576 flp->initialized = 1;
1577 return 0;
1578
1579fail2:
1580 free_irq(map->irq, dev);
1581fail:
1582 release_region(base, SDLA_IO_EXTENTS);
1583 return err;
1584}
1585
Stephen Hemmingerac995332009-03-26 15:11:25 +00001586static const struct net_device_ops sdla_netdev_ops = {
1587 .ndo_open = sdla_open,
1588 .ndo_stop = sdla_close,
1589 .ndo_do_ioctl = sdla_ioctl,
1590 .ndo_set_config = sdla_set_config,
1591 .ndo_start_xmit = sdla_transmit,
1592 .ndo_change_mtu = sdla_change_mtu,
1593};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
1595static void setup_sdla(struct net_device *dev)
1596{
Wang Chen8f15ea42008-11-12 23:38:36 -08001597 struct frad_local *flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
1599 netdev_boot_setup_check(dev);
1600
Stephen Hemmingerac995332009-03-26 15:11:25 +00001601 dev->netdev_ops = &sdla_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 dev->flags = 0;
1603 dev->type = 0xFFFF;
1604 dev->hard_header_len = 0;
1605 dev->addr_len = 0;
1606 dev->mtu = SDLA_MAX_MTU;
1607
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 flp->activate = sdla_activate;
1609 flp->deactivate = sdla_deactivate;
1610 flp->assoc = sdla_assoc;
1611 flp->deassoc = sdla_deassoc;
1612 flp->dlci_conf = sdla_dlci_conf;
Kees Cook032cfd62017-10-25 03:53:59 -07001613 flp->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Kees Cook032cfd62017-10-25 03:53:59 -07001615 timer_setup(&flp->timer, sdla_poll, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 flp->timer.expires = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617}
1618
1619static struct net_device *sdla;
1620
1621static int __init init_sdla(void)
1622{
1623 int err;
1624
1625 printk("%s.\n", version);
1626
Tom Gundersenc835a672014-07-14 16:37:24 +02001627 sdla = alloc_netdev(sizeof(struct frad_local), "sdla0",
1628 NET_NAME_UNKNOWN, setup_sdla);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 if (!sdla)
1630 return -ENOMEM;
1631
1632 err = register_netdev(sdla);
1633 if (err)
1634 free_netdev(sdla);
1635
1636 return err;
1637}
1638
1639static void __exit exit_sdla(void)
1640{
Wang Chen8f15ea42008-11-12 23:38:36 -08001641 struct frad_local *flp = netdev_priv(sdla);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
1643 unregister_netdev(sdla);
1644 if (flp->initialized) {
1645 free_irq(sdla->irq, sdla);
1646 release_region(sdla->base_addr, SDLA_IO_EXTENTS);
1647 }
1648 del_timer_sync(&flp->timer);
1649 free_netdev(sdla);
1650}
1651
1652MODULE_LICENSE("GPL");
1653
1654module_init(init_sdla);
1655module_exit(exit_sdla);