blob: 3f4e2b5684db29a2a11069b87d9f38c5371061f9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * SDLA An implementation of a driver for the Sangoma S502/S508 series
3 * multi-protocol PC interface card. Initial offering is with
4 * the DLCI driver, providing Frame Relay support for linux.
5 *
6 * Global definitions for the Frame relay interface.
7 *
8 * Version: @(#)sdla.c 0.30 12 Sep 1996
9 *
10 * Credits: Sangoma Technologies, for the use of 2 cards for an extended
11 * period of time.
12 * David Mandelstam <dm@sangoma.com> for getting me started on
13 * this project, and incentive to complete it.
14 * Gene Kozen <74604.152@compuserve.com> for providing me with
15 * important information about the cards.
16 *
17 * Author: Mike McLagan <mike.mclagan@linux.org>
18 *
19 * Changes:
20 * 0.15 Mike McLagan Improved error handling, packet dropping
21 * 0.20 Mike McLagan New transmit/receive flags for config
22 * If in FR mode, don't accept packets from
23 * non DLCI devices.
24 * 0.25 Mike McLagan Fixed problem with rejecting packets
25 * from non DLCI devices.
26 * 0.30 Mike McLagan Fixed kernel panic when used with modified
27 * ifconfig
28 *
29 * This program is free software; you can redistribute it and/or
30 * modify it under the terms of the GNU General Public License
31 * as published by the Free Software Foundation; either version
32 * 2 of the License, or (at your option) any later version.
33 */
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/module.h>
36#include <linux/kernel.h>
37#include <linux/types.h>
38#include <linux/fcntl.h>
39#include <linux/interrupt.h>
40#include <linux/ptrace.h>
41#include <linux/ioport.h>
42#include <linux/in.h>
43#include <linux/slab.h>
44#include <linux/string.h>
45#include <linux/timer.h>
46#include <linux/errno.h>
47#include <linux/init.h>
48#include <linux/netdevice.h>
49#include <linux/skbuff.h>
50#include <linux/if_arp.h>
51#include <linux/if_frad.h>
52#include <linux/sdla.h>
53#include <linux/bitops.h>
54
55#include <asm/system.h>
56#include <asm/io.h>
57#include <asm/dma.h>
58#include <asm/uaccess.h>
59
60static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
61
Randy Dunlap96ebb922006-06-25 05:48:37 -070062static unsigned int valid_port[] = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Randy Dunlap96ebb922006-06-25 05:48:37 -070064static unsigned int valid_mem[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
66 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
67 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
68 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,
69 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000};
70
71static DEFINE_SPINLOCK(sdla_lock);
72
73/*********************************************************
74 *
75 * these are the core routines that access the card itself
76 *
77 *********************************************************/
78
79#define SDLA_WINDOW(dev,addr) outb((((addr) >> 13) & 0x1F), (dev)->base_addr + SDLA_REG_Z80_WINDOW)
80
81static void __sdla_read(struct net_device *dev, int addr, void *buf, short len)
82{
83 char *temp;
84 const void *base;
85 int offset, bytes;
86
87 temp = buf;
88 while(len)
89 {
90 offset = addr & SDLA_ADDR_MASK;
91 bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
92 base = (const void *) (dev->mem_start + offset);
93
94 SDLA_WINDOW(dev, addr);
95 memcpy(temp, base, bytes);
96
97 addr += bytes;
98 temp += bytes;
99 len -= bytes;
100 }
101}
102
103static void sdla_read(struct net_device *dev, int addr, void *buf, short len)
104{
105 unsigned long flags;
106 spin_lock_irqsave(&sdla_lock, flags);
107 __sdla_read(dev, addr, buf, len);
108 spin_unlock_irqrestore(&sdla_lock, flags);
109}
110
111static void __sdla_write(struct net_device *dev, int addr,
112 const void *buf, short len)
113{
114 const char *temp;
115 void *base;
116 int offset, bytes;
117
118 temp = buf;
119 while(len)
120 {
121 offset = addr & SDLA_ADDR_MASK;
122 bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
123 base = (void *) (dev->mem_start + offset);
124
125 SDLA_WINDOW(dev, addr);
126 memcpy(base, temp, bytes);
127
128 addr += bytes;
129 temp += bytes;
130 len -= bytes;
131 }
132}
133
134static void sdla_write(struct net_device *dev, int addr,
135 const void *buf, short len)
136{
137 unsigned long flags;
138
139 spin_lock_irqsave(&sdla_lock, flags);
140 __sdla_write(dev, addr, buf, len);
141 spin_unlock_irqrestore(&sdla_lock, flags);
142}
143
144
145static void sdla_clear(struct net_device *dev)
146{
147 unsigned long flags;
148 char *base;
149 int len, addr, bytes;
150
151 len = 65536;
152 addr = 0;
153 bytes = SDLA_WINDOW_SIZE;
154 base = (void *) dev->mem_start;
155
156 spin_lock_irqsave(&sdla_lock, flags);
157 while(len)
158 {
159 SDLA_WINDOW(dev, addr);
160 memset(base, 0, bytes);
161
162 addr += bytes;
163 len -= bytes;
164 }
165 spin_unlock_irqrestore(&sdla_lock, flags);
166
167}
168
169static char sdla_byte(struct net_device *dev, int addr)
170{
171 unsigned long flags;
172 char byte, *temp;
173
174 temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
175
176 spin_lock_irqsave(&sdla_lock, flags);
177 SDLA_WINDOW(dev, addr);
178 byte = *temp;
179 spin_unlock_irqrestore(&sdla_lock, flags);
180
Eric Dumazet807540b2010-09-23 05:40:09 +0000181 return byte;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182}
183
Adrian Bunk7665a082005-09-09 23:17:28 -0700184static void sdla_stop(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
186 struct frad_local *flp;
187
Wang Chen8f15ea42008-11-12 23:38:36 -0800188 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 switch(flp->type)
190 {
191 case SDLA_S502A:
192 outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
193 flp->state = SDLA_HALT;
194 break;
195 case SDLA_S502E:
196 outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
197 outb(SDLA_S502E_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
198 flp->state = SDLA_S502E_ENABLE;
199 break;
200 case SDLA_S507:
201 flp->state &= ~SDLA_CPUEN;
202 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
203 break;
204 case SDLA_S508:
205 flp->state &= ~SDLA_CPUEN;
206 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
207 break;
208 }
209}
210
Adrian Bunk7665a082005-09-09 23:17:28 -0700211static void sdla_start(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212{
213 struct frad_local *flp;
214
Wang Chen8f15ea42008-11-12 23:38:36 -0800215 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 switch(flp->type)
217 {
218 case SDLA_S502A:
219 outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL);
220 outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
221 flp->state = SDLA_S502A_START;
222 break;
223 case SDLA_S502E:
224 outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL);
225 outb(0x00, dev->base_addr + SDLA_REG_CONTROL);
226 flp->state = 0;
227 break;
228 case SDLA_S507:
229 flp->state |= SDLA_CPUEN;
230 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
231 break;
232 case SDLA_S508:
233 flp->state |= SDLA_CPUEN;
234 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
235 break;
236 }
237}
238
239/****************************************************
240 *
241 * this is used for the S502A/E cards to determine
242 * the speed of the onboard CPU. Calibration is
243 * necessary for the Frame Relay code uploaded
244 * later. Incorrect results cause timing problems
245 * with link checks & status messages
246 *
247 ***************************************************/
248
Adrian Bunk7665a082005-09-09 23:17:28 -0700249static int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
251 unsigned long start, done, now;
252 char resp, *temp;
253
254 start = now = jiffies;
255 done = jiffies + jiffs;
256
257 temp = (void *)dev->mem_start;
258 temp += z80_addr & SDLA_ADDR_MASK;
259
260 resp = ~resp1;
261 while (time_before(jiffies, done) && (resp != resp1) && (!resp2 || (resp != resp2)))
262 {
263 if (jiffies != now)
264 {
265 SDLA_WINDOW(dev, z80_addr);
266 now = jiffies;
267 resp = *temp;
268 }
269 }
Eric Dumazet807540b2010-09-23 05:40:09 +0000270 return time_before(jiffies, done) ? jiffies - start : -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271}
272
273/* constants for Z80 CPU speed */
274#define Z80_READY '1' /* Z80 is ready to begin */
275#define LOADER_READY '2' /* driver is ready to begin */
276#define Z80_SCC_OK '3' /* SCC is on board */
277#define Z80_SCC_BAD '4' /* SCC was not found */
278
279static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr)
280{
281 int jiffs;
282 char data;
283
284 sdla_start(dev);
285 if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)
Eric Dumazet807540b2010-09-23 05:40:09 +0000286 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 data = LOADER_READY;
289 sdla_write(dev, 0, &data, 1);
290
291 if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)
Eric Dumazet807540b2010-09-23 05:40:09 +0000292 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294 sdla_stop(dev);
295 sdla_read(dev, 0, &data, 1);
296
297 if (data == Z80_SCC_BAD)
298 {
299 printk("%s: SCC bad\n", dev->name);
Eric Dumazet807540b2010-09-23 05:40:09 +0000300 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302
303 if (data != Z80_SCC_OK)
Eric Dumazet807540b2010-09-23 05:40:09 +0000304 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 if (jiffs < 165)
307 ifr->ifr_mtu = SDLA_CPU_16M;
308 else if (jiffs < 220)
309 ifr->ifr_mtu = SDLA_CPU_10M;
310 else if (jiffs < 258)
311 ifr->ifr_mtu = SDLA_CPU_8M;
312 else if (jiffs < 357)
313 ifr->ifr_mtu = SDLA_CPU_7M;
314 else if (jiffs < 467)
315 ifr->ifr_mtu = SDLA_CPU_5M;
316 else
317 ifr->ifr_mtu = SDLA_CPU_3M;
318
Eric Dumazet807540b2010-09-23 05:40:09 +0000319 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
321
322/************************************************
323 *
324 * Direct interaction with the Frame Relay code
325 * starts here.
326 *
327 ************************************************/
328
329struct _dlci_stat
330{
Jan Blunck6a878182006-01-08 01:05:07 -0800331 short dlci;
332 char flags;
Eric Dumazetba2d3582010-06-02 18:10:09 +0000333} __packed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
335struct _frad_stat
336{
337 char flags;
338 struct _dlci_stat dlcis[SDLA_MAX_DLCI];
339};
340
341static void sdla_errors(struct net_device *dev, int cmd, int dlci, int ret, int len, void *data)
342{
343 struct _dlci_stat *pstatus;
344 short *pdlci;
345 int i;
346 char *state, line[30];
347
348 switch (ret)
349 {
350 case SDLA_RET_MODEM:
351 state = data;
352 if (*state & SDLA_MODEM_DCD_LOW)
353 printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name);
354 if (*state & SDLA_MODEM_CTS_LOW)
355 printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name);
356 /* I should probably do something about this! */
357 break;
358
359 case SDLA_RET_CHANNEL_OFF:
360 printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name);
361 /* same here */
362 break;
363
364 case SDLA_RET_CHANNEL_ON:
365 printk(KERN_INFO "%s: Channel became operative!\n", dev->name);
366 /* same here */
367 break;
368
369 case SDLA_RET_DLCI_STATUS:
370 printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name);
371 len /= sizeof(struct _dlci_stat);
372 for(pstatus = data, i=0;i < len;i++,pstatus++)
373 {
374 if (pstatus->flags & SDLA_DLCI_NEW)
375 state = "new";
376 else if (pstatus->flags & SDLA_DLCI_DELETED)
377 state = "deleted";
378 else if (pstatus->flags & SDLA_DLCI_ACTIVE)
379 state = "active";
380 else
381 {
382 sprintf(line, "unknown status: %02X", pstatus->flags);
383 state = line;
384 }
385 printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
386 /* same here */
387 }
388 break;
389
390 case SDLA_RET_DLCI_UNKNOWN:
391 printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name);
392 len /= sizeof(short);
393 for(pdlci = data,i=0;i < len;i++,pdlci++)
394 printk(" %i", *pdlci);
395 printk("\n");
396 break;
397
398 case SDLA_RET_TIMEOUT:
399 printk(KERN_ERR "%s: Command timed out!\n", dev->name);
400 break;
401
402 case SDLA_RET_BUF_OVERSIZE:
403 printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);
404 break;
405
406 case SDLA_RET_BUF_TOO_BIG:
407 printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);
408 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;
416
417 default:
418 printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);
419 /* Further processing could be done here */
420 break;
421 }
422}
423
424static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags,
425 void *inbuf, short inlen, void *outbuf, short *outlen)
426{
427 static struct _frad_stat status;
428 struct frad_local *flp;
429 struct sdla_cmd *cmd_buf;
430 unsigned long pflags;
431 unsigned long jiffs;
432 int ret, waiting, len;
433 long window;
434
Wang Chen8f15ea42008-11-12 23:38:36 -0800435 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
437 cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
438 ret = 0;
439 len = 0;
440 jiffs = jiffies + HZ; /* 1 second is plenty */
441
442 spin_lock_irqsave(&sdla_lock, pflags);
443 SDLA_WINDOW(dev, window);
444 cmd_buf->cmd = cmd;
445 cmd_buf->dlci = dlci;
446 cmd_buf->flags = flags;
447
448 if (inbuf)
449 memcpy(cmd_buf->data, inbuf, inlen);
450
451 cmd_buf->length = inlen;
452
453 cmd_buf->opp_flag = 1;
454 spin_unlock_irqrestore(&sdla_lock, pflags);
455
456 waiting = 1;
457 len = 0;
458 while (waiting && time_before_eq(jiffies, jiffs))
459 {
460 if (waiting++ % 3)
461 {
462 spin_lock_irqsave(&sdla_lock, pflags);
463 SDLA_WINDOW(dev, window);
464 waiting = ((volatile int)(cmd_buf->opp_flag));
465 spin_unlock_irqrestore(&sdla_lock, pflags);
466 }
467 }
468
469 if (!waiting)
470 {
471
472 spin_lock_irqsave(&sdla_lock, pflags);
473 SDLA_WINDOW(dev, window);
474 ret = cmd_buf->retval;
475 len = cmd_buf->length;
476 if (outbuf && outlen)
477 {
478 *outlen = *outlen >= len ? len : *outlen;
479
480 if (*outlen)
481 memcpy(outbuf, cmd_buf->data, *outlen);
482 }
483
484 /* This is a local copy that's used for error handling */
485 if (ret)
486 memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
487
488 spin_unlock_irqrestore(&sdla_lock, pflags);
489 }
490 else
491 ret = SDLA_RET_TIMEOUT;
492
493 if (ret != SDLA_RET_OK)
494 sdla_errors(dev, cmd, dlci, ret, len, &status);
495
Eric Dumazet807540b2010-09-23 05:40:09 +0000496 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
499/***********************************************
500 *
501 * these functions are called by the DLCI driver
502 *
503 ***********************************************/
504
505static int sdla_reconfig(struct net_device *dev);
506
Adrian Bunk7665a082005-09-09 23:17:28 -0700507static int sdla_activate(struct net_device *slave, struct net_device *master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
509 struct frad_local *flp;
510 int i;
511
Wang Chen8f15ea42008-11-12 23:38:36 -0800512 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514 for(i=0;i<CONFIG_DLCI_MAX;i++)
515 if (flp->master[i] == master)
516 break;
517
518 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000519 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521 flp->dlci[i] = abs(flp->dlci[i]);
522
523 if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
524 sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
525
Eric Dumazet807540b2010-09-23 05:40:09 +0000526 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527}
528
Adrian Bunk7665a082005-09-09 23:17:28 -0700529static int sdla_deactivate(struct net_device *slave, struct net_device *master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
531 struct frad_local *flp;
532 int i;
533
Wang Chen8f15ea42008-11-12 23:38:36 -0800534 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 for(i=0;i<CONFIG_DLCI_MAX;i++)
537 if (flp->master[i] == master)
538 break;
539
540 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000541 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 flp->dlci[i] = -abs(flp->dlci[i]);
544
545 if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
546 sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
547
Eric Dumazet807540b2010-09-23 05:40:09 +0000548 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549}
550
Adrian Bunk7665a082005-09-09 23:17:28 -0700551static int sdla_assoc(struct net_device *slave, struct net_device *master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
553 struct frad_local *flp;
554 int i;
555
556 if (master->type != ARPHRD_DLCI)
Eric Dumazet807540b2010-09-23 05:40:09 +0000557 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Wang Chen8f15ea42008-11-12 23:38:36 -0800559 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
561 for(i=0;i<CONFIG_DLCI_MAX;i++)
562 {
563 if (!flp->master[i])
564 break;
565 if (abs(flp->dlci[i]) == *(short *)(master->dev_addr))
Eric Dumazet807540b2010-09-23 05:40:09 +0000566 return -EADDRINUSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 }
568
569 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000570 return -EMLINK; /* #### Alan: Comments on this ?? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572
573 flp->master[i] = master;
574 flp->dlci[i] = -*(short *)(master->dev_addr);
575 master->mtu = slave->mtu;
576
577 if (netif_running(slave)) {
578 if (flp->config.station == FRAD_STATION_CPE)
579 sdla_reconfig(slave);
580 else
581 sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
582 }
583
Eric Dumazet807540b2010-09-23 05:40:09 +0000584 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585}
586
Adrian Bunk7665a082005-09-09 23:17:28 -0700587static int sdla_deassoc(struct net_device *slave, struct net_device *master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
589 struct frad_local *flp;
590 int i;
591
Wang Chen8f15ea42008-11-12 23:38:36 -0800592 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 for(i=0;i<CONFIG_DLCI_MAX;i++)
595 if (flp->master[i] == master)
596 break;
597
598 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000599 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
601 flp->master[i] = NULL;
602 flp->dlci[i] = 0;
603
604
605 if (netif_running(slave)) {
606 if (flp->config.station == FRAD_STATION_CPE)
607 sdla_reconfig(slave);
608 else
609 sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
610 }
611
Eric Dumazet807540b2010-09-23 05:40:09 +0000612 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613}
614
Adrian Bunk7665a082005-09-09 23:17:28 -0700615static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
617 struct frad_local *flp;
618 struct dlci_local *dlp;
619 int i;
620 short len, ret;
621
Wang Chen8f15ea42008-11-12 23:38:36 -0800622 flp = netdev_priv(slave);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
624 for(i=0;i<CONFIG_DLCI_MAX;i++)
625 if (flp->master[i] == master)
626 break;
627
628 if (i == CONFIG_DLCI_MAX)
Eric Dumazet807540b2010-09-23 05:40:09 +0000629 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
Wang Chen8f15ea42008-11-12 23:38:36 -0800631 dlp = netdev_priv(master);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 ret = SDLA_RET_OK;
634 len = sizeof(struct dlci_conf);
635 if (netif_running(slave)) {
636 if (get)
637 ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
638 NULL, 0, &dlp->config, &len);
639 else
640 ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
641 &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
642 }
643
Eric Dumazet807540b2010-09-23 05:40:09 +0000644 return ret == SDLA_RET_OK ? 0 : -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645}
646
647/**************************
648 *
649 * now for the Linux driver
650 *
651 **************************/
652
653/* NOTE: the DLCI driver deals with freeing the SKB!! */
Stephen Hemmingerd71a6742009-08-31 19:50:47 +0000654static netdev_tx_t sdla_transmit(struct sk_buff *skb,
Stephen Hemminger38482422009-09-04 05:33:46 +0000655 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
657 struct frad_local *flp;
658 int ret, addr, accept, i;
659 short size;
660 unsigned long flags;
661 struct buf_entry *pbuf;
662
Wang Chen8f15ea42008-11-12 23:38:36 -0800663 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 ret = 0;
665 accept = 1;
666
667 netif_stop_queue(dev);
668
669 /*
670 * stupid GateD insists on setting up the multicast router thru us
671 * and we're ill equipped to handle a non Frame Relay packet at this
672 * time!
673 */
674
675 accept = 1;
676 switch (dev->type)
677 {
678 case ARPHRD_FRAD:
679 if (skb->dev->type != ARPHRD_DLCI)
680 {
681 printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
682 accept = 0;
683 }
684 break;
685 default:
686 printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
687 accept = 0;
688 break;
689 }
690 if (accept)
691 {
692 /* this is frame specific, but till there's a PPP module, it's the default */
693 switch (flp->type)
694 {
695 case SDLA_S502A:
696 case SDLA_S502E:
697 ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
698 break;
699 case SDLA_S508:
700 size = sizeof(addr);
701 ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
702 if (ret == SDLA_RET_OK)
703 {
704
705 spin_lock_irqsave(&sdla_lock, flags);
706 SDLA_WINDOW(dev, addr);
707 pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
708 __sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
709 SDLA_WINDOW(dev, addr);
710 pbuf->opp_flag = 1;
711 spin_unlock_irqrestore(&sdla_lock, flags);
712 }
713 break;
714 }
Stephen Hemminger38482422009-09-04 05:33:46 +0000715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 switch (ret)
717 {
718 case SDLA_RET_OK:
Stephen Hemmingerac995332009-03-26 15:11:25 +0000719 dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 break;
721
722 case SDLA_RET_CIR_OVERFLOW:
723 case SDLA_RET_BUF_OVERSIZE:
724 case SDLA_RET_NO_BUFS:
Stephen Hemmingerac995332009-03-26 15:11:25 +0000725 dev->stats.tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 break;
727
728 default:
Stephen Hemmingerac995332009-03-26 15:11:25 +0000729 dev->stats.tx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 break;
731 }
732 }
733 netif_wake_queue(dev);
734 for(i=0;i<CONFIG_DLCI_MAX;i++)
735 {
736 if(flp->master[i]!=NULL)
737 netif_wake_queue(flp->master[i]);
738 }
Stephen Hemminger38482422009-09-04 05:33:46 +0000739
740 dev_kfree_skb(skb);
Stephen Hemmingerd71a6742009-08-31 19:50:47 +0000741 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
744static void sdla_receive(struct net_device *dev)
745{
746 struct net_device *master;
747 struct frad_local *flp;
748 struct dlci_local *dlp;
749 struct sk_buff *skb;
750
751 struct sdla_cmd *cmd;
752 struct buf_info *pbufi;
753 struct buf_entry *pbuf;
754
755 unsigned long flags;
756 int i=0, received, success, addr, buf_base, buf_top;
757 short dlci, len, len2, split;
758
Wang Chen8f15ea42008-11-12 23:38:36 -0800759 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 success = 1;
761 received = addr = buf_top = buf_base = 0;
762 len = dlci = 0;
763 skb = NULL;
764 master = NULL;
765 cmd = NULL;
766 pbufi = NULL;
767 pbuf = NULL;
768
769 spin_lock_irqsave(&sdla_lock, flags);
770
771 switch (flp->type)
772 {
773 case SDLA_S502A:
774 case SDLA_S502E:
775 cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
776 SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
777 success = cmd->opp_flag;
778 if (!success)
779 break;
780
781 dlci = cmd->dlci;
782 len = cmd->length;
783 break;
784
785 case SDLA_S508:
786 pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
787 SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
788 pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
789 success = pbuf->opp_flag;
790 if (!success)
791 break;
792
793 buf_top = pbufi->buf_top;
794 buf_base = pbufi->buf_base;
795 dlci = pbuf->dlci;
796 len = pbuf->length;
797 addr = pbuf->buf_addr;
798 break;
799 }
800
801 /* common code, find the DLCI and get the SKB */
802 if (success)
803 {
804 for (i=0;i<CONFIG_DLCI_MAX;i++)
805 if (flp->dlci[i] == dlci)
806 break;
807
808 if (i == CONFIG_DLCI_MAX)
809 {
810 printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
Stephen Hemmingerac995332009-03-26 15:11:25 +0000811 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 success = 0;
813 }
814 }
815
816 if (success)
817 {
818 master = flp->master[i];
819 skb = dev_alloc_skb(len + sizeof(struct frhdr));
820 if (skb == NULL)
821 {
822 printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
Stephen Hemmingerac995332009-03-26 15:11:25 +0000823 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 success = 0;
825 }
826 else
827 skb_reserve(skb, sizeof(struct frhdr));
828 }
829
830 /* pick up the data */
831 switch (flp->type)
832 {
833 case SDLA_S502A:
834 case SDLA_S502E:
835 if (success)
836 __sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
837
838 SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
839 cmd->opp_flag = 0;
840 break;
841
842 case SDLA_S508:
843 if (success)
844 {
845 /* is this buffer split off the end of the internal ring buffer */
846 split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
847 len2 = len - split;
848
849 __sdla_read(dev, addr, skb_put(skb, len2), len2);
850 if (split)
851 __sdla_read(dev, buf_base, skb_put(skb, split), split);
852 }
853
854 /* increment the buffer we're looking at */
855 SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
856 flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
857 pbuf->opp_flag = 0;
858 break;
859 }
860
861 if (success)
862 {
Stephen Hemmingerac995332009-03-26 15:11:25 +0000863 dev->stats.rx_packets++;
Wang Chen8f15ea42008-11-12 23:38:36 -0800864 dlp = netdev_priv(master);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 (*dlp->receive)(skb, master);
866 }
867
868 spin_unlock_irqrestore(&sdla_lock, flags);
869}
870
Jeff Garzik28fc1f52007-10-29 05:46:16 -0400871static irqreturn_t sdla_isr(int dummy, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
873 struct net_device *dev;
874 struct frad_local *flp;
875 char byte;
876
877 dev = dev_id;
878
Jeff Garzikc31f28e2006-10-06 14:56:04 -0400879 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 if (!flp->initialized)
882 {
Jeff Garzik28fc1f52007-10-29 05:46:16 -0400883 printk(KERN_WARNING "%s: irq %d for uninitialized device.\n",
884 dev->name, dev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 return IRQ_NONE;
886 }
887
888 byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE);
889 switch (byte)
890 {
891 case SDLA_INTR_RX:
892 sdla_receive(dev);
893 break;
894
895 /* the command will get an error return, which is processed above */
896 case SDLA_INTR_MODEM:
897 case SDLA_INTR_STATUS:
898 sdla_cmd(dev, SDLA_READ_DLC_STATUS, 0, 0, NULL, 0, NULL, NULL);
899 break;
900
901 case SDLA_INTR_TX:
902 case SDLA_INTR_COMPLETE:
903 case SDLA_INTR_TIMER:
904 printk(KERN_WARNING "%s: invalid irq flag 0x%02X.\n", dev->name, byte);
905 break;
906 }
907
908 /* the S502E requires a manual acknowledgement of the interrupt */
909 if (flp->type == SDLA_S502E)
910 {
911 flp->state &= ~SDLA_S502E_INTACK;
912 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
913 flp->state |= SDLA_S502E_INTACK;
914 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
915 }
916
917 /* this clears the byte, informing the Z80 we're done */
918 byte = 0;
919 sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
920 return IRQ_HANDLED;
921}
922
923static void sdla_poll(unsigned long device)
924{
925 struct net_device *dev;
926 struct frad_local *flp;
927
928 dev = (struct net_device *) device;
Wang Chen8f15ea42008-11-12 23:38:36 -0800929 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 if (sdla_byte(dev, SDLA_502_RCV_BUF))
932 sdla_receive(dev);
933
934 flp->timer.expires = 1;
935 add_timer(&flp->timer);
936}
937
938static int sdla_close(struct net_device *dev)
939{
940 struct frad_local *flp;
941 struct intr_info intr;
942 int len, i;
943 short dlcis[CONFIG_DLCI_MAX];
944
Wang Chen8f15ea42008-11-12 23:38:36 -0800945 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 len = 0;
948 for(i=0;i<CONFIG_DLCI_MAX;i++)
949 if (flp->dlci[i])
950 dlcis[len++] = abs(flp->dlci[i]);
951 len *= 2;
952
953 if (flp->config.station == FRAD_STATION_NODE)
954 {
955 for(i=0;i<CONFIG_DLCI_MAX;i++)
956 if (flp->dlci[i] > 0)
957 sdla_cmd(dev, SDLA_DEACTIVATE_DLCI, 0, 0, dlcis, len, NULL, NULL);
958 sdla_cmd(dev, SDLA_DELETE_DLCI, 0, 0, &flp->dlci[i], sizeof(flp->dlci[i]), NULL, NULL);
959 }
960
961 memset(&intr, 0, sizeof(intr));
962 /* let's start up the reception */
963 switch(flp->type)
964 {
965 case SDLA_S502A:
966 del_timer(&flp->timer);
967 break;
968
969 case SDLA_S502E:
970 sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
971 flp->state &= ~SDLA_S502E_INTACK;
972 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
973 break;
974
975 case SDLA_S507:
976 break;
977
978 case SDLA_S508:
979 sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
980 flp->state &= ~SDLA_S508_INTEN;
981 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
982 break;
983 }
984
985 sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
986
987 netif_stop_queue(dev);
988
Eric Dumazet807540b2010-09-23 05:40:09 +0000989 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990}
991
992struct conf_data {
993 struct frad_conf config;
994 short dlci[CONFIG_DLCI_MAX];
995};
996
997static int sdla_open(struct net_device *dev)
998{
999 struct frad_local *flp;
1000 struct dlci_local *dlp;
1001 struct conf_data data;
1002 struct intr_info intr;
1003 int len, i;
1004 char byte;
1005
Wang Chen8f15ea42008-11-12 23:38:36 -08001006 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 if (!flp->initialized)
Eric Dumazet807540b2010-09-23 05:40:09 +00001009 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 if (!flp->configured)
Eric Dumazet807540b2010-09-23 05:40:09 +00001012 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014 /* time to send in the configuration */
1015 len = 0;
1016 for(i=0;i<CONFIG_DLCI_MAX;i++)
1017 if (flp->dlci[i])
1018 data.dlci[len++] = abs(flp->dlci[i]);
1019 len *= 2;
1020
1021 memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
1022 len += sizeof(struct frad_conf);
1023
1024 sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
1025 sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
1026
1027 if (flp->type == SDLA_S508)
1028 flp->buffer = 0;
1029
1030 sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
1031
1032 /* let's start up the reception */
1033 memset(&intr, 0, sizeof(intr));
1034 switch(flp->type)
1035 {
1036 case SDLA_S502A:
1037 flp->timer.expires = 1;
1038 add_timer(&flp->timer);
1039 break;
1040
1041 case SDLA_S502E:
1042 flp->state |= SDLA_S502E_ENABLE;
1043 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
1044 flp->state |= SDLA_S502E_INTACK;
1045 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
1046 byte = 0;
1047 sdla_write(dev, SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
1048 intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
1049 sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL);
1050 break;
1051
1052 case SDLA_S507:
1053 break;
1054
1055 case SDLA_S508:
1056 flp->state |= SDLA_S508_INTEN;
1057 outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
1058 byte = 0;
1059 sdla_write(dev, SDLA_508_IRQ_INTERFACE, &byte, sizeof(byte));
1060 intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM;
1061 intr.irq = dev->irq;
1062 sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL);
1063 break;
1064 }
1065
1066 if (flp->config.station == FRAD_STATION_CPE)
1067 {
1068 byte = SDLA_ICS_STATUS_ENQ;
1069 sdla_cmd(dev, SDLA_ISSUE_IN_CHANNEL_SIGNAL, 0, 0, &byte, sizeof(byte), NULL, NULL);
1070 }
1071 else
1072 {
1073 sdla_cmd(dev, SDLA_ADD_DLCI, 0, 0, data.dlci, len - sizeof(struct frad_conf), NULL, NULL);
1074 for(i=0;i<CONFIG_DLCI_MAX;i++)
1075 if (flp->dlci[i] > 0)
1076 sdla_cmd(dev, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], 2*sizeof(flp->dlci[i]), NULL, NULL);
1077 }
1078
1079 /* configure any specific DLCI settings */
1080 for(i=0;i<CONFIG_DLCI_MAX;i++)
1081 if (flp->dlci[i])
1082 {
Wang Chen8f15ea42008-11-12 23:38:36 -08001083 dlp = netdev_priv(flp->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 if (dlp->configured)
1085 sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
1086 }
1087
1088 netif_start_queue(dev);
1089
Eric Dumazet807540b2010-09-23 05:40:09 +00001090 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091}
1092
1093static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, int get)
1094{
1095 struct frad_local *flp;
1096 struct conf_data data;
1097 int i;
1098 short size;
1099
1100 if (dev->type == 0xFFFF)
Eric Dumazet807540b2010-09-23 05:40:09 +00001101 return -EUNATCH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Wang Chen8f15ea42008-11-12 23:38:36 -08001103 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 if (!get)
1106 {
1107 if (netif_running(dev))
Eric Dumazet807540b2010-09-23 05:40:09 +00001108 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
1110 if(copy_from_user(&data.config, conf, sizeof(struct frad_conf)))
1111 return -EFAULT;
1112
1113 if (data.config.station & ~FRAD_STATION_NODE)
Eric Dumazet807540b2010-09-23 05:40:09 +00001114 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
1116 if (data.config.flags & ~FRAD_VALID_FLAGS)
Eric Dumazet807540b2010-09-23 05:40:09 +00001117 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
1119 if ((data.config.kbaud < 0) ||
1120 ((data.config.kbaud > 128) && (flp->type != SDLA_S508)))
Eric Dumazet807540b2010-09-23 05:40:09 +00001121 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123 if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232))
Eric Dumazet807540b2010-09-23 05:40:09 +00001124 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126 if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU))
Eric Dumazet807540b2010-09-23 05:40:09 +00001127 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 if ((data.config.T391 < 5) || (data.config.T391 > 30))
Eric Dumazet807540b2010-09-23 05:40:09 +00001130 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132 if ((data.config.T392 < 5) || (data.config.T392 > 30))
Eric Dumazet807540b2010-09-23 05:40:09 +00001133 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
1135 if ((data.config.N391 < 1) || (data.config.N391 > 255))
Eric Dumazet807540b2010-09-23 05:40:09 +00001136 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 if ((data.config.N392 < 1) || (data.config.N392 > 10))
Eric Dumazet807540b2010-09-23 05:40:09 +00001139 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
1141 if ((data.config.N393 < 1) || (data.config.N393 > 10))
Eric Dumazet807540b2010-09-23 05:40:09 +00001142 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144 memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
1145 flp->config.flags |= SDLA_DIRECT_RECV;
1146
1147 if (flp->type == SDLA_S508)
1148 flp->config.flags |= SDLA_TX70_RX30;
1149
1150 if (dev->mtu != flp->config.mtu)
1151 {
1152 /* this is required to change the MTU */
1153 dev->mtu = flp->config.mtu;
1154 for(i=0;i<CONFIG_DLCI_MAX;i++)
1155 if (flp->master[i])
1156 flp->master[i]->mtu = flp->config.mtu;
1157 }
1158
1159 flp->config.mtu += sizeof(struct frhdr);
1160
1161 /* off to the races! */
1162 if (!flp->configured)
1163 sdla_start(dev);
1164
1165 flp->configured = 1;
1166 }
1167 else
1168 {
1169 /* no sense reading if the CPU isn't started */
1170 if (netif_running(dev))
1171 {
1172 size = sizeof(data);
1173 if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
Eric Dumazet807540b2010-09-23 05:40:09 +00001174 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
1176 else
1177 if (flp->configured)
1178 memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
1179 else
1180 memset(&data.config, 0, sizeof(struct frad_conf));
1181
1182 memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
1183 data.config.flags &= FRAD_VALID_FLAGS;
1184 data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
1185 return copy_to_user(conf, &data.config, sizeof(struct frad_conf))?-EFAULT:0;
1186 }
1187
Eric Dumazet807540b2010-09-23 05:40:09 +00001188 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189}
1190
1191static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int read)
1192{
1193 struct sdla_mem mem;
1194 char *temp;
1195
1196 if(copy_from_user(&mem, info, sizeof(mem)))
1197 return -EFAULT;
1198
1199 if (read)
1200 {
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001201 temp = kzalloc(mem.len, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 if (!temp)
Eric Dumazet807540b2010-09-23 05:40:09 +00001203 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 sdla_read(dev, mem.addr, temp, mem.len);
1205 if(copy_to_user(mem.data, temp, mem.len))
1206 {
1207 kfree(temp);
1208 return -EFAULT;
1209 }
1210 kfree(temp);
1211 }
1212 else
1213 {
Julia Lawallc146fc92010-05-21 22:20:26 +00001214 temp = memdup_user(mem.data, mem.len);
1215 if (IS_ERR(temp))
1216 return PTR_ERR(temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 sdla_write(dev, mem.addr, temp, mem.len);
1218 kfree(temp);
1219 }
Eric Dumazet807540b2010-09-23 05:40:09 +00001220 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221}
1222
1223static int sdla_reconfig(struct net_device *dev)
1224{
1225 struct frad_local *flp;
1226 struct conf_data data;
1227 int i, len;
1228
Wang Chen8f15ea42008-11-12 23:38:36 -08001229 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
1231 len = 0;
1232 for(i=0;i<CONFIG_DLCI_MAX;i++)
1233 if (flp->dlci[i])
1234 data.dlci[len++] = flp->dlci[i];
1235 len *= 2;
1236
1237 memcpy(&data, &flp->config, sizeof(struct frad_conf));
1238 len += sizeof(struct frad_conf);
1239
1240 sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
1241 sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
1242 sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
1243
Eric Dumazet807540b2010-09-23 05:40:09 +00001244 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245}
1246
1247static int sdla_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1248{
1249 struct frad_local *flp;
1250
1251 if(!capable(CAP_NET_ADMIN))
1252 return -EPERM;
1253
Wang Chen8f15ea42008-11-12 23:38:36 -08001254 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
1256 if (!flp->initialized)
Eric Dumazet807540b2010-09-23 05:40:09 +00001257 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
1259 switch (cmd)
1260 {
1261 case FRAD_GET_CONF:
1262 case FRAD_SET_CONF:
Eric Dumazet807540b2010-09-23 05:40:09 +00001263 return sdla_config(dev, ifr->ifr_data, cmd == FRAD_GET_CONF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
1265 case SDLA_IDENTIFY:
1266 ifr->ifr_flags = flp->type;
1267 break;
1268
1269 case SDLA_CPUSPEED:
Eric Dumazet807540b2010-09-23 05:40:09 +00001270 return sdla_cpuspeed(dev, ifr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
1272/* ==========================================================
1273NOTE: This is rather a useless action right now, as the
1274 current driver does not support protocols other than
1275 FR. However, Sangoma has modules for a number of
1276 other protocols in the works.
1277============================================================*/
1278 case SDLA_PROTOCOL:
1279 if (flp->configured)
Eric Dumazet807540b2010-09-23 05:40:09 +00001280 return -EALREADY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
1282 switch (ifr->ifr_flags)
1283 {
1284 case ARPHRD_FRAD:
1285 dev->type = ifr->ifr_flags;
1286 break;
1287 default:
Eric Dumazet807540b2010-09-23 05:40:09 +00001288 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 }
1290 break;
1291
1292 case SDLA_CLEARMEM:
1293 sdla_clear(dev);
1294 break;
1295
1296 case SDLA_WRITEMEM:
1297 case SDLA_READMEM:
1298 if(!capable(CAP_SYS_RAWIO))
1299 return -EPERM;
Eric Dumazet807540b2010-09-23 05:40:09 +00001300 return sdla_xfer(dev, ifr->ifr_data, cmd == SDLA_READMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302 case SDLA_START:
1303 sdla_start(dev);
1304 break;
1305
1306 case SDLA_STOP:
1307 sdla_stop(dev);
1308 break;
1309
1310 default:
Eric Dumazet807540b2010-09-23 05:40:09 +00001311 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 }
Eric Dumazet807540b2010-09-23 05:40:09 +00001313 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314}
1315
Adrian Bunk7665a082005-09-09 23:17:28 -07001316static int sdla_change_mtu(struct net_device *dev, int new_mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317{
1318 struct frad_local *flp;
1319
Wang Chen8f15ea42008-11-12 23:38:36 -08001320 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322 if (netif_running(dev))
Eric Dumazet807540b2010-09-23 05:40:09 +00001323 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
1325 /* for now, you can't change the MTU! */
Eric Dumazet807540b2010-09-23 05:40:09 +00001326 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327}
1328
Adrian Bunk7665a082005-09-09 23:17:28 -07001329static int sdla_set_config(struct net_device *dev, struct ifmap *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330{
1331 struct frad_local *flp;
1332 int i;
1333 char byte;
1334 unsigned base;
1335 int err = -EINVAL;
1336
Wang Chen8f15ea42008-11-12 23:38:36 -08001337 flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
1339 if (flp->initialized)
Eric Dumazet807540b2010-09-23 05:40:09 +00001340 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
Alejandro Martinez Ruize9edda62007-10-15 03:37:43 +02001342 for(i=0; i < ARRAY_SIZE(valid_port); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 if (valid_port[i] == map->base_addr)
1344 break;
1345
Alejandro Martinez Ruize9edda62007-10-15 03:37:43 +02001346 if (i == ARRAY_SIZE(valid_port))
Eric Dumazet807540b2010-09-23 05:40:09 +00001347 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
1349 if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){
Frans Pop2381a552010-03-24 07:57:36 +00001350 printk(KERN_WARNING "SDLA: io-port 0x%04lx in use\n", dev->base_addr);
Eric Dumazet807540b2010-09-23 05:40:09 +00001351 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 }
1353 base = map->base_addr;
1354
1355 /* test for card types, S502A, S502E, S507, S508 */
1356 /* these tests shut down the card completely, so clear the state */
1357 flp->type = SDLA_UNKNOWN;
1358 flp->state = 0;
1359
1360 for(i=1;i<SDLA_IO_EXTENTS;i++)
1361 if (inb(base + i) != 0xFF)
1362 break;
1363
1364 if (i == SDLA_IO_EXTENTS) {
1365 outb(SDLA_HALT, base + SDLA_REG_Z80_CONTROL);
1366 if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x08) {
1367 outb(SDLA_S502E_INTACK, base + SDLA_REG_CONTROL);
1368 if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x0C) {
1369 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1370 flp->type = SDLA_S502E;
1371 goto got_type;
1372 }
1373 }
1374 }
1375
1376 for(byte=inb(base),i=0;i<SDLA_IO_EXTENTS;i++)
1377 if (inb(base + i) != byte)
1378 break;
1379
1380 if (i == SDLA_IO_EXTENTS) {
1381 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1382 if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x30) {
1383 outb(SDLA_S507_ENABLE, base + SDLA_REG_CONTROL);
1384 if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x32) {
1385 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1386 flp->type = SDLA_S507;
1387 goto got_type;
1388 }
1389 }
1390 }
1391
1392 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1393 if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x00) {
1394 outb(SDLA_S508_INTEN, base + SDLA_REG_CONTROL);
1395 if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x10) {
1396 outb(SDLA_HALT, base + SDLA_REG_CONTROL);
1397 flp->type = SDLA_S508;
1398 goto got_type;
1399 }
1400 }
1401
1402 outb(SDLA_S502A_HALT, base + SDLA_REG_CONTROL);
1403 if (inb(base + SDLA_S502_STS) == 0x40) {
1404 outb(SDLA_S502A_START, base + SDLA_REG_CONTROL);
1405 if (inb(base + SDLA_S502_STS) == 0x40) {
1406 outb(SDLA_S502A_INTEN, base + SDLA_REG_CONTROL);
1407 if (inb(base + SDLA_S502_STS) == 0x44) {
1408 outb(SDLA_S502A_START, base + SDLA_REG_CONTROL);
1409 flp->type = SDLA_S502A;
1410 goto got_type;
1411 }
1412 }
1413 }
1414
1415 printk(KERN_NOTICE "%s: Unknown card type\n", dev->name);
1416 err = -ENODEV;
1417 goto fail;
1418
1419got_type:
1420 switch(base) {
1421 case 0x270:
1422 case 0x280:
1423 case 0x380:
1424 case 0x390:
1425 if (flp->type != SDLA_S508 && flp->type != SDLA_S507)
1426 goto fail;
1427 }
1428
1429 switch (map->irq) {
1430 case 2:
1431 if (flp->type != SDLA_S502E)
1432 goto fail;
1433 break;
1434
1435 case 10:
1436 case 11:
1437 case 12:
1438 case 15:
1439 case 4:
1440 if (flp->type != SDLA_S508 && flp->type != SDLA_S507)
1441 goto fail;
1442 break;
1443 case 3:
1444 case 5:
1445 case 7:
1446 if (flp->type == SDLA_S502A)
1447 goto fail;
1448 break;
1449
1450 default:
1451 goto fail;
1452 }
1453
1454 err = -EAGAIN;
Joe Perchesa0607fd2009-11-18 23:29:17 -08001455 if (request_irq(dev->irq, sdla_isr, 0, dev->name, dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 goto fail;
1457
1458 if (flp->type == SDLA_S507) {
1459 switch(dev->irq) {
1460 case 3:
1461 flp->state = SDLA_S507_IRQ3;
1462 break;
1463 case 4:
1464 flp->state = SDLA_S507_IRQ4;
1465 break;
1466 case 5:
1467 flp->state = SDLA_S507_IRQ5;
1468 break;
1469 case 7:
1470 flp->state = SDLA_S507_IRQ7;
1471 break;
1472 case 10:
1473 flp->state = SDLA_S507_IRQ10;
1474 break;
1475 case 11:
1476 flp->state = SDLA_S507_IRQ11;
1477 break;
1478 case 12:
1479 flp->state = SDLA_S507_IRQ12;
1480 break;
1481 case 15:
1482 flp->state = SDLA_S507_IRQ15;
1483 break;
1484 }
1485 }
1486
Alejandro Martinez Ruize9edda62007-10-15 03:37:43 +02001487 for(i=0; i < ARRAY_SIZE(valid_mem); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 if (valid_mem[i] == map->mem_start)
1489 break;
1490
1491 err = -EINVAL;
Alejandro Martinez Ruize9edda62007-10-15 03:37:43 +02001492 if (i == ARRAY_SIZE(valid_mem))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 goto fail2;
1494
1495 if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E)
1496 goto fail2;
1497
1498 if (flp->type != SDLA_S507 && map->mem_start >> 16 == 0x0B)
1499 goto fail2;
1500
1501 if (flp->type == SDLA_S507 && map->mem_start >> 16 == 0x0D)
1502 goto fail2;
1503
1504 byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0;
1505 byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0));
1506 switch(flp->type) {
1507 case SDLA_S502A:
1508 case SDLA_S502E:
1509 switch (map->mem_start >> 16) {
1510 case 0x0A:
1511 byte |= SDLA_S502_SEG_A;
1512 break;
1513 case 0x0C:
1514 byte |= SDLA_S502_SEG_C;
1515 break;
1516 case 0x0D:
1517 byte |= SDLA_S502_SEG_D;
1518 break;
1519 case 0x0E:
1520 byte |= SDLA_S502_SEG_E;
1521 break;
1522 }
1523 break;
1524 case SDLA_S507:
1525 switch (map->mem_start >> 16) {
1526 case 0x0A:
1527 byte |= SDLA_S507_SEG_A;
1528 break;
1529 case 0x0B:
1530 byte |= SDLA_S507_SEG_B;
1531 break;
1532 case 0x0C:
1533 byte |= SDLA_S507_SEG_C;
1534 break;
1535 case 0x0E:
1536 byte |= SDLA_S507_SEG_E;
1537 break;
1538 }
1539 break;
1540 case SDLA_S508:
1541 switch (map->mem_start >> 16) {
1542 case 0x0A:
1543 byte |= SDLA_S508_SEG_A;
1544 break;
1545 case 0x0C:
1546 byte |= SDLA_S508_SEG_C;
1547 break;
1548 case 0x0D:
1549 byte |= SDLA_S508_SEG_D;
1550 break;
1551 case 0x0E:
1552 byte |= SDLA_S508_SEG_E;
1553 break;
1554 }
1555 break;
1556 }
1557
1558 /* set the memory bits, and enable access */
1559 outb(byte, base + SDLA_REG_PC_WINDOW);
1560
1561 switch(flp->type)
1562 {
1563 case SDLA_S502E:
1564 flp->state = SDLA_S502E_ENABLE;
1565 break;
1566 case SDLA_S507:
1567 flp->state |= SDLA_MEMEN;
1568 break;
1569 case SDLA_S508:
1570 flp->state = SDLA_MEMEN;
1571 break;
1572 }
1573 outb(flp->state, base + SDLA_REG_CONTROL);
1574
1575 dev->irq = map->irq;
1576 dev->base_addr = base;
1577 dev->mem_start = map->mem_start;
1578 dev->mem_end = dev->mem_start + 0x2000;
1579 flp->initialized = 1;
1580 return 0;
1581
1582fail2:
1583 free_irq(map->irq, dev);
1584fail:
1585 release_region(base, SDLA_IO_EXTENTS);
1586 return err;
1587}
1588
Stephen Hemmingerac995332009-03-26 15:11:25 +00001589static const struct net_device_ops sdla_netdev_ops = {
1590 .ndo_open = sdla_open,
1591 .ndo_stop = sdla_close,
1592 .ndo_do_ioctl = sdla_ioctl,
1593 .ndo_set_config = sdla_set_config,
1594 .ndo_start_xmit = sdla_transmit,
1595 .ndo_change_mtu = sdla_change_mtu,
1596};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
1598static void setup_sdla(struct net_device *dev)
1599{
Wang Chen8f15ea42008-11-12 23:38:36 -08001600 struct frad_local *flp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 netdev_boot_setup_check(dev);
1603
Stephen Hemmingerac995332009-03-26 15:11:25 +00001604 dev->netdev_ops = &sdla_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 dev->flags = 0;
1606 dev->type = 0xFFFF;
1607 dev->hard_header_len = 0;
1608 dev->addr_len = 0;
1609 dev->mtu = SDLA_MAX_MTU;
1610
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 flp->activate = sdla_activate;
1612 flp->deactivate = sdla_deactivate;
1613 flp->assoc = sdla_assoc;
1614 flp->deassoc = sdla_deassoc;
1615 flp->dlci_conf = sdla_dlci_conf;
1616
1617 init_timer(&flp->timer);
1618 flp->timer.expires = 1;
1619 flp->timer.data = (unsigned long) dev;
1620 flp->timer.function = sdla_poll;
1621}
1622
1623static struct net_device *sdla;
1624
1625static int __init init_sdla(void)
1626{
1627 int err;
1628
1629 printk("%s.\n", version);
1630
1631 sdla = alloc_netdev(sizeof(struct frad_local), "sdla0", setup_sdla);
1632 if (!sdla)
1633 return -ENOMEM;
1634
1635 err = register_netdev(sdla);
1636 if (err)
1637 free_netdev(sdla);
1638
1639 return err;
1640}
1641
1642static void __exit exit_sdla(void)
1643{
Wang Chen8f15ea42008-11-12 23:38:36 -08001644 struct frad_local *flp = netdev_priv(sdla);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 unregister_netdev(sdla);
1647 if (flp->initialized) {
1648 free_irq(sdla->irq, sdla);
1649 release_region(sdla->base_addr, SDLA_IO_EXTENTS);
1650 }
1651 del_timer_sync(&flp->timer);
1652 free_netdev(sdla);
1653}
1654
1655MODULE_LICENSE("GPL");
1656
1657module_init(init_sdla);
1658module_exit(exit_sdla);