11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* $Id: module.c,v 1.14.6.4 2001/09/23 22:24:32 kai Exp $ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author Fritz Elfert 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright by Fritz Elfert <fritz@isdn4linux.de> 7475be4d85a274d0961593db41cf85689db1d583cJoe Perches * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thanks to Friedemann Baitinger and IBM Germany 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "act2000.h" 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "act2000_isa.h" 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "capi.h" 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short act2000_isa_ports[] = 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24475be4d85a274d0961593db41cf85689db1d583cJoe Perches 0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380, 25475be4d85a274d0961593db41cf85689db1d583cJoe Perches 0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60, 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic act2000_card *cards = (act2000_card *) NULL; 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Parameters to be set by insmod */ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int act_bus = 0; 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int act_port = -1; /* -1 = Autoprobe */ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int act_irq = -1; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *act_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36475be4d85a274d0961593db41cf85689db1d583cJoe PerchesMODULE_DESCRIPTION("ISDN4Linux: Driver for IBM Active 2000 ISDN card"); 37475be4d85a274d0961593db41cf85689db1d583cJoe PerchesMODULE_AUTHOR("Fritz Elfert"); 38475be4d85a274d0961593db41cf85689db1d583cJoe PerchesMODULE_LICENSE("GPL"); 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA"); 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(membase, "Base port address of first card"); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(act_irq, "IRQ of first card"); 42475be4d85a274d0961593db41cf85689db1d583cJoe PerchesMODULE_PARM_DESC(act_id, "ID-String of first card"); 43475be4d85a274d0961593db41cf85689db1d583cJoe Perchesmodule_param(act_bus, int, 0); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(act_port, int, 0); 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(act_irq, int, 0); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(act_id, charp, 0); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int act2000_addcard(int, int, int, char *); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic act2000_chan * 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfind_channel(act2000_card *card, int channel) 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((channel >= 0) && (channel < ACT2000_BCH)) 54475be4d85a274d0961593db41cf85689db1d583cJoe Perches return &(card->bch[channel]); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "act2000: Invalid channel %d\n", channel); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free MSN list 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsact2000_clear_msn(act2000_card *card) 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct msn_entry *p = card->msn_list; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct msn_entry *q; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&card->lock, flags); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card->msn_list = NULL; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&card->lock, flags); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (p) { 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = p->next; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(p); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = q; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find an MSN entry in the list. 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If ia5 != 0, return IA5-encoded EAZ, else 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return a bitmask with corresponding bit set. 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __u16 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsact2000_find_msn(act2000_card *card, char *msn, int ia5) 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 87475be4d85a274d0961593db41cf85689db1d583cJoe Perches struct msn_entry *p = card->msn_list; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 eaz = '0'; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (p) { 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!strcmp(p->msn, msn)) { 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eaz = p->eaz; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = p->next; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ia5) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (1 << (eaz - '0')); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return eaz; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find an EAZ entry in the list. 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return a string with corresponding msn. 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldschar * 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsact2000_find_eaz(act2000_card *card, char eaz) 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 110475be4d85a274d0961593db41cf85689db1d583cJoe Perches struct msn_entry *p = card->msn_list; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (p) { 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p->eaz == eaz) 114475be4d85a274d0961593db41cf85689db1d583cJoe Perches return (p->msn); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = p->next; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 117475be4d85a274d0961593db41cf85689db1d583cJoe Perches return ("\0"); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add or delete an MSN to the MSN list 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First character of msneaz is EAZ, rest is MSN. 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If length of eazmsn is 1, delete that entry. 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsact2000_set_msn(act2000_card *card, char *eazmsn) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 129475be4d85a274d0961593db41cf85689db1d583cJoe Perches struct msn_entry *p = card->msn_list; 130475be4d85a274d0961593db41cf85689db1d583cJoe Perches struct msn_entry *q = NULL; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 133475be4d85a274d0961593db41cf85689db1d583cJoe Perches 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!strlen(eazmsn)) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strlen(eazmsn) > 16) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < strlen(eazmsn); i++) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!isdigit(eazmsn[i])) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 141475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (strlen(eazmsn) == 1) { 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Delete a single MSN */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (p) { 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p->eaz == eazmsn[0]) { 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&card->lock, flags); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->next = p->next; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card->msn_list = p->next; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&card->lock, flags); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(p); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Mapping for EAZ %c deleted\n", 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eazmsn[0]); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = p; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = p->next; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 161475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Add a single MSN */ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (p) { 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Found in list, replace MSN */ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p->eaz == eazmsn[0]) { 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&card->lock, flags); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(p->msn, &eazmsn[1]); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&card->lock, flags); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Mapping for EAZ %c changed to %s\n", 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eazmsn[0], 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &eazmsn[1]); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = p->next; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Not found in list, add new entry */ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = kmalloc(sizeof(msn_entry), GFP_KERNEL); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!p) 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p->eaz = eazmsn[0]; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(p->msn, &eazmsn[1]); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p->next = card->msn_list; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&card->lock, flags); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card->msn_list = p; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&card->lock, flags); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Mapping %c -> %s added\n", 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eazmsn[0], 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &eazmsn[1]); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 195c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsact2000_transmit(struct work_struct *work) 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 197c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells struct act2000_card *card = 198c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells container_of(work, struct act2000_card, snd_tq); 199c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (card->bus) { 201475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_ISA: 202475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_isa_send(card); 203475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 204475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_PCMCIA: 205475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_MCA: 206475be4d85a274d0961593db41cf85689db1d583cJoe Perches default: 207475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 208475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000_transmit: Illegal bustype %d\n", card->bus); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 213c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsact2000_receive(struct work_struct *work) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 215c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells struct act2000_card *card = 216c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells container_of(work, struct act2000_card, poll_tq); 217c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (card->bus) { 219475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_ISA: 220475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_isa_receive(card); 221475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 222475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_PCMCIA: 223475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_MCA: 224475be4d85a274d0961593db41cf85689db1d583cJoe Perches default: 225475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 226475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000_receive: Illegal bustype %d\n", card->bus); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsact2000_poll(unsigned long data) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 233475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_card *card = (act2000_card *)data; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 236c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells act2000_receive(&card->poll_tq); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&card->lock, flags); 238475be4d85a274d0961593db41cf85689db1d583cJoe Perches mod_timer(&card->ptimer, jiffies + 3); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&card->lock, flags); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 243475be4d85a274d0961593db41cf85689db1d583cJoe Perchesact2000_command(act2000_card *card, isdn_ctrl *c) 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 245475be4d85a274d0961593db41cf85689db1d583cJoe Perches ulong a; 246475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_chan *chan; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds act2000_cdef cdef; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isdn_ctrl cmd; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char tmp[17]; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *arg; 253475be4d85a274d0961593db41cf85689db1d583cJoe Perches 254475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (c->command) { 255475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ISDN_CMD_IOCTL: 256475be4d85a274d0961593db41cf85689db1d583cJoe Perches memcpy(&a, c->parm.num, sizeof(ulong)); 257475be4d85a274d0961593db41cf85689db1d583cJoe Perches arg = (void __user *)a; 258475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (c->arg) { 259475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_IOCTL_LOADBOOT: 260475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (card->bus) { 261475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_ISA: 262475be4d85a274d0961593db41cf85689db1d583cJoe Perches ret = act2000_isa_download(card, 263475be4d85a274d0961593db41cf85689db1d583cJoe Perches arg); 264475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!ret) { 265475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->flags |= ACT2000_FLAGS_LOADED; 266475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_IVALID)) { 267475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->ptimer.expires = jiffies + 3; 268475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->ptimer.function = act2000_poll; 269475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->ptimer.data = (unsigned long)card; 270475be4d85a274d0961593db41cf85689db1d583cJoe Perches add_timer(&card->ptimer); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 272475be4d85a274d0961593db41cf85689db1d583cJoe Perches actcapi_manufacturer_req_errh(card); 273475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 275475be4d85a274d0961593db41cf85689db1d583cJoe Perches default: 276475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 277475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: Illegal BUS type %d\n", 278475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->bus); 279475be4d85a274d0961593db41cf85689db1d583cJoe Perches ret = -EIO; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 282475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_IOCTL_SETPROTO: 283475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->ptype = a ? ISDN_PTYPE_EURO : ISDN_PTYPE_1TR6; 284eaa0ff15c30dc9799eb4d12660edb73aeb6d32c5Alexey Dobriyan if (!(card->flags & ACT2000_FLAGS_RUNNING)) 285475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 286475be4d85a274d0961593db41cf85689db1d583cJoe Perches actcapi_manufacturer_req_net(card); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 288475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_IOCTL_SETMSN: 289475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (copy_from_user(tmp, arg, 290475be4d85a274d0961593db41cf85689db1d583cJoe Perches sizeof(tmp))) 291475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -EFAULT; 292475be4d85a274d0961593db41cf85689db1d583cJoe Perches if ((ret = act2000_set_msn(card, tmp))) 293475be4d85a274d0961593db41cf85689db1d583cJoe Perches return ret; 294475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card->flags & ACT2000_FLAGS_RUNNING) 295475be4d85a274d0961593db41cf85689db1d583cJoe Perches return (actcapi_manufacturer_req_msn(card)); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 297475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_IOCTL_ADDCARD: 298475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (copy_from_user(&cdef, arg, 299475be4d85a274d0961593db41cf85689db1d583cJoe Perches sizeof(cdef))) 300475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -EFAULT; 301475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id)) 302475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -EIO; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 304475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_IOCTL_TEST: 305eaa0ff15c30dc9799eb4d12660edb73aeb6d32c5Alexey Dobriyan if (!(card->flags & ACT2000_FLAGS_RUNNING)) 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 308475be4d85a274d0961593db41cf85689db1d583cJoe Perches default: 309475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -EINVAL; 310475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 311475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 312475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ISDN_CMD_DIAL: 313475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 314475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 315475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(chan = find_channel(card, c->arg & 0x0f))) 316475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 317475be4d85a274d0961593db41cf85689db1d583cJoe Perches spin_lock_irqsave(&card->lock, flags); 318475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (chan->fsm_state != ACT2000_STATE_NULL) { 319475be4d85a274d0961593db41cf85689db1d583cJoe Perches spin_unlock_irqrestore(&card->lock, flags); 320475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING "Dial on channel with state %d\n", 321475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->fsm_state); 322475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -EBUSY; 323475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 324475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card->ptype == ISDN_PTYPE_EURO) 325475be4d85a274d0961593db41cf85689db1d583cJoe Perches tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1); 326475be4d85a274d0961593db41cf85689db1d583cJoe Perches else 327475be4d85a274d0961593db41cf85689db1d583cJoe Perches tmp[0] = c->parm.setup.eazmsn[0]; 328475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->fsm_state = ACT2000_STATE_OCALL; 329475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->callref = 0xffff; 330475be4d85a274d0961593db41cf85689db1d583cJoe Perches spin_unlock_irqrestore(&card->lock, flags); 331475be4d85a274d0961593db41cf85689db1d583cJoe Perches ret = actcapi_connect_req(card, chan, c->parm.setup.phone, 332475be4d85a274d0961593db41cf85689db1d583cJoe Perches tmp[0], c->parm.setup.si1, 333475be4d85a274d0961593db41cf85689db1d583cJoe Perches c->parm.setup.si2); 334475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (ret) { 335475be4d85a274d0961593db41cf85689db1d583cJoe Perches cmd.driver = card->myid; 336475be4d85a274d0961593db41cf85689db1d583cJoe Perches cmd.command = ISDN_STAT_DHUP; 337475be4d85a274d0961593db41cf85689db1d583cJoe Perches cmd.arg &= 0x0f; 338475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.statcallb(&cmd); 339475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 340475be4d85a274d0961593db41cf85689db1d583cJoe Perches return ret; 341475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ISDN_CMD_ACCEPTD: 342475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 343475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 344475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(chan = find_channel(card, c->arg & 0x0f))) 345475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 346475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (chan->fsm_state == ACT2000_STATE_ICALL) 347475be4d85a274d0961593db41cf85689db1d583cJoe Perches actcapi_select_b2_protocol_req(card, chan); 348475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 349475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ISDN_CMD_ACCEPTB: 350475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 351475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 352475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 353475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ISDN_CMD_HANGUP: 354475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 355475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 356475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(chan = find_channel(card, c->arg & 0x0f))) 357475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 358475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (chan->fsm_state) { 359475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_STATE_ICALL: 360475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_STATE_BSETUP: 361475be4d85a274d0961593db41cf85689db1d583cJoe Perches actcapi_connect_resp(card, chan, 0x15); 362475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 363475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_STATE_ACTIVE: 364475be4d85a274d0961593db41cf85689db1d583cJoe Perches actcapi_disconnect_b3_req(card, chan); 365475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 366475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 367475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 368475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ISDN_CMD_SETEAZ: 369475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 370475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 371475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(chan = find_channel(card, c->arg & 0x0f))) 372475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 373475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (strlen(c->parm.num)) { 374475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card->ptype == ISDN_PTYPE_EURO) { 375475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->eazmask = act2000_find_msn(card, c->parm.num, 0); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 377475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card->ptype == ISDN_PTYPE_1TR6) { 378475be4d85a274d0961593db41cf85689db1d583cJoe Perches int i; 379475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->eazmask = 0; 380475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (i = 0; i < strlen(c->parm.num); i++) 381475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (isdigit(c->parm.num[i])) 382475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->eazmask |= (1 << (c->parm.num[i] - '0')); 383475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 384475be4d85a274d0961593db41cf85689db1d583cJoe Perches } else 385475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->eazmask = 0x3ff; 386475be4d85a274d0961593db41cf85689db1d583cJoe Perches actcapi_listen_req(card); 387475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 388475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ISDN_CMD_CLREAZ: 389475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 390475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 391475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(chan = find_channel(card, c->arg & 0x0f))) 392475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 393475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->eazmask = 0; 394475be4d85a274d0961593db41cf85689db1d583cJoe Perches actcapi_listen_req(card); 395475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 396475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ISDN_CMD_SETL2: 397475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 398475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 399475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(chan = find_channel(card, c->arg & 0x0f))) 400475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 401475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->l2prot = (c->arg >> 8); 402475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 403475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ISDN_CMD_SETL3: 404475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 405475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 406475be4d85a274d0961593db41cf85689db1d583cJoe Perches if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) { 407475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING "L3 protocol unknown\n"); 408475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -1; 409475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 410475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(chan = find_channel(card, c->arg & 0x0f))) 411475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 412475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->l3prot = (c->arg >> 8); 413475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 414475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 415475be4d85a274d0961593db41cf85689db1d583cJoe Perches 416475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -EINVAL; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsact2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb) 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 422475be4d85a274d0961593db41cf85689db1d583cJoe Perches struct sk_buff *xmit_skb; 423475be4d85a274d0961593db41cf85689db1d583cJoe Perches int len; 424475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_chan *chan; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actcapi_msg *msg; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 427475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(chan = find_channel(card, channel))) 428475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -1; 429475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (chan->fsm_state != ACT2000_STATE_ACTIVE) 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 431475be4d85a274d0961593db41cf85689db1d583cJoe Perches len = skb->len; 432475be4d85a274d0961593db41cf85689db1d583cJoe Perches if ((chan->queued + len) >= ACT2000_MAX_QUEUED) 433475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!len) 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_headroom(skb) < 19) { 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "act2000_sendbuf: Headroom only %d\n", 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_headroom(skb)); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xmit_skb = alloc_skb(len + 19, GFP_ATOMIC); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!xmit_skb) { 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "act2000_sendbuf: Out of memory\n"); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(xmit_skb, 19); 445d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data(skb, skb_put(xmit_skb, len), len); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xmit_skb = skb_clone(skb, GFP_ATOMIC); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!xmit_skb) { 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "act2000_sendbuf: Out of memory\n"); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg = (actcapi_msg *)skb_push(xmit_skb, 19); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->hdr.len = 19 + len; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->hdr.applicationID = 1; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->hdr.cmd.cmd = 0x86; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->hdr.cmd.subcmd = 0x00; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->hdr.msgnum = actcapi_nextsmsg(card); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->msg.data_b3_req.datalen = len; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->msg.data_b3_req.blocknr = (msg->hdr.msgnum & 0xff); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->msg.data_b3_req.fakencci = MAKE_NCCI(chan->plci, 0, chan->ncci); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->msg.data_b3_req.flags = ack; /* Will be set to 0 on actual sending */ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actcapi_debug_msg(xmit_skb, 1); 465475be4d85a274d0961593db41cf85689db1d583cJoe Perches chan->queued += len; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_tail(&card->sndq, xmit_skb); 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds act2000_schedule_tx(card); 468475be4d85a274d0961593db41cf85689db1d583cJoe Perches return len; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Read the Status-replies from the Interface */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 474475be4d85a274d0961593db41cf85689db1d583cJoe Perchesact2000_readstatus(u_char __user *buf, int len, act2000_card *card) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 476475be4d85a274d0961593db41cf85689db1d583cJoe Perches int count; 477475be4d85a274d0961593db41cf85689db1d583cJoe Perches u_char __user *p; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 479475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (p = buf, count = 0; count < len; p++, count++) { 480475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card->status_buf_read == card->status_buf_write) 481475be4d85a274d0961593db41cf85689db1d583cJoe Perches return count; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_user(*card->status_buf_read++, p); 483475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card->status_buf_read > card->status_buf_end) 484475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->status_buf_read = card->status_buf; 485475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 486475be4d85a274d0961593db41cf85689db1d583cJoe Perches return count; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find card with given driverId 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline act2000_card * 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsact2000_findcard(int driverid) 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 495475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_card *p = cards; 496475be4d85a274d0961593db41cf85689db1d583cJoe Perches 497475be4d85a274d0961593db41cf85689db1d583cJoe Perches while (p) { 498475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (p->myid == driverid) 499475be4d85a274d0961593db41cf85689db1d583cJoe Perches return p; 500475be4d85a274d0961593db41cf85689db1d583cJoe Perches p = p->next; 501475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 502475be4d85a274d0961593db41cf85689db1d583cJoe Perches return (act2000_card *) 0; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wrapper functions for interface to linklevel 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 509475be4d85a274d0961593db41cf85689db1d583cJoe Perchesif_command(isdn_ctrl *c) 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 511475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_card *card = act2000_findcard(c->driver); 512475be4d85a274d0961593db41cf85689db1d583cJoe Perches 513475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card) 514475be4d85a274d0961593db41cf85689db1d583cJoe Perches return (act2000_command(card, c)); 515475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_ERR 516475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: if_command %d called with invalid driverId %d!\n", 517475be4d85a274d0961593db41cf85689db1d583cJoe Perches c->command, c->driver); 518475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsif_writecmd(const u_char __user *buf, int len, int id, int channel) 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 524475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_card *card = act2000_findcard(id); 525475be4d85a274d0961593db41cf85689db1d583cJoe Perches 526475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card) { 527475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 528475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 529475be4d85a274d0961593db41cf85689db1d583cJoe Perches return (len); 530475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 531475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_ERR 532475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: if_writecmd called with invalid driverId!\n"); 533475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 537475be4d85a274d0961593db41cf85689db1d583cJoe Perchesif_readstatus(u_char __user *buf, int len, int id, int channel) 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 539475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_card *card = act2000_findcard(id); 540475be4d85a274d0961593db41cf85689db1d583cJoe Perches 541475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card) { 542475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 543475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 544475be4d85a274d0961593db41cf85689db1d583cJoe Perches return (act2000_readstatus(buf, len, card)); 545475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 546475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_ERR 547475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: if_readstatus called with invalid driverId!\n"); 548475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsif_sendbuf(int id, int channel, int ack, struct sk_buff *skb) 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 554475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_card *card = act2000_findcard(id); 555475be4d85a274d0961593db41cf85689db1d583cJoe Perches 556475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (card) { 557475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card->flags & ACT2000_FLAGS_RUNNING)) 558475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (act2000_sendbuf(card, channel, ack, skb)); 560475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 561475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_ERR 562475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: if_sendbuf called with invalid driverId!\n"); 563475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a new card-struct, initialize it 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * link it into cards-list. 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsact2000_alloccard(int bus, int port, int irq, char *id) 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 575475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_card *card; 576475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!(card = kzalloc(sizeof(act2000_card), GFP_KERNEL))) { 577475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "act2000: (%s) Could not allocate card-struct.\n", id); 579475be4d85a274d0961593db41cf85689db1d583cJoe Perches return; 580475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 581475be4d85a274d0961593db41cf85689db1d583cJoe Perches spin_lock_init(&card->lock); 582475be4d85a274d0961593db41cf85689db1d583cJoe Perches spin_lock_init(&card->mnlock); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_head_init(&card->sndq); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_head_init(&card->rcvq); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_head_init(&card->ackq); 586c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_WORK(&card->snd_tq, act2000_transmit); 587c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_WORK(&card->rcv_tq, actcapi_dispatch); 588c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_WORK(&card->poll_tq, act2000_receive); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&card->ptimer); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card->interface.owner = THIS_MODULE; 591475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.channels = ACT2000_BCH; 592475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.maxbufsize = 4000; 593475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.command = if_command; 594475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.writebuf_skb = if_sendbuf; 595475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.writecmd = if_writecmd; 596475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.readstat = if_readstatus; 597475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.features = 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ISDN_FEATURE_L2_X75I | 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ISDN_FEATURE_L2_HDLC | 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ISDN_FEATURE_L3_TRANS | 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ISDN_FEATURE_P_UNKNOWN; 602475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.hl_hdrlen = 20; 603475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->ptype = ISDN_PTYPE_EURO; 604475be4d85a274d0961593db41cf85689db1d583cJoe Perches strlcpy(card->interface.id, id, sizeof(card->interface.id)); 605475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (i = 0; i < ACT2000_BCH; i++) { 606475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->bch[i].plci = 0x8000; 607475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->bch[i].ncci = 0x8000; 608475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->bch[i].l2prot = ISDN_PROTO_L2_X75I; 609475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->bch[i].l3prot = ISDN_PROTO_L3_TRANS; 610475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 611475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->myid = -1; 612475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->bus = bus; 613475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->port = port; 614475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->irq = irq; 615475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->next = cards; 616475be4d85a274d0961593db41cf85689db1d583cJoe Perches cards = card; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register card at linklevel 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 623475be4d85a274d0961593db41cf85689db1d583cJoe Perchesact2000_registercard(act2000_card *card) 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 625475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (card->bus) { 626475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_ISA: 627475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 628475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_MCA: 629475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_PCMCIA: 630475be4d85a274d0961593db41cf85689db1d583cJoe Perches default: 631475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 632475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: Illegal BUS type %d\n", 633475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->bus); 634475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -1; 635475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 636475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!register_isdn(&card->interface)) { 637475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 638475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: Unable to register %s\n", 639475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.id); 640475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -1; 641475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 642475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->myid = card->interface.channels; 643475be4d85a274d0961593db41cf85689db1d583cJoe Perches sprintf(card->regname, "act2000-isdn (%s)", card->interface.id); 644475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 648475be4d85a274d0961593db41cf85689db1d583cJoe Perchesunregister_card(act2000_card *card) 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 650475be4d85a274d0961593db41cf85689db1d583cJoe Perches isdn_ctrl cmd; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 652475be4d85a274d0961593db41cf85689db1d583cJoe Perches cmd.command = ISDN_STAT_UNLOAD; 653475be4d85a274d0961593db41cf85689db1d583cJoe Perches cmd.driver = card->myid; 654475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->interface.statcallb(&cmd); 655475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (card->bus) { 656475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_ISA: 657475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_isa_release(card); 658475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 659475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_MCA: 660475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_PCMCIA: 661475be4d85a274d0961593db41cf85689db1d583cJoe Perches default: 662475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 663475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: Invalid BUS type %d\n", 664475be4d85a274d0961593db41cf85689db1d583cJoe Perches card->bus); 665475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 666475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsact2000_addcard(int bus, int port, int irq, char *id) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds act2000_card *p; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds act2000_card *q = NULL; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int initialized; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int added = 0; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int failed = 0; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bus) 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus = ACT2000_BUS_ISA; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port != -1) { 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Port defined, do fixed setup */ 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds act2000_alloccard(bus, port, irq, id); 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No port defined, perform autoprobing. 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This may result in more than one card detected. 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (bus) { 689ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil case ACT2000_BUS_ISA: 690ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil for (i = 0; i < ARRAY_SIZE(act2000_isa_ports); i++) 691ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil if (act2000_isa_detect(act2000_isa_ports[i])) { 692ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil printk(KERN_INFO "act2000: Detected " 693475be4d85a274d0961593db41cf85689db1d583cJoe Perches "ISA card at port 0x%x\n", 694475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_isa_ports[i]); 695ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil act2000_alloccard(bus, 696475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_isa_ports[i], irq, id); 697ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil } 698ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil break; 699ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil case ACT2000_BUS_MCA: 700ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil case ACT2000_BUS_PCMCIA: 701ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil default: 702ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil printk(KERN_WARNING 703475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: addcard: Invalid BUS type %d\n", bus); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cards) 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 708475be4d85a274d0961593db41cf85689db1d583cJoe Perches p = cards; 709475be4d85a274d0961593db41cf85689db1d583cJoe Perches while (p) { 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initialized = 0; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!p->interface.statcallb) { 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Not yet registered. 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to register and activate it. 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds added++; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (p->bus) { 717475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_ISA: 718475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (act2000_isa_detect(p->port)) { 719475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (act2000_registercard(p)) 720475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 721475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (act2000_isa_config_port(p, p->port)) { 722475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 723475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: Could not request port 0x%04x\n", 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p->port); 725475be4d85a274d0961593db41cf85689db1d583cJoe Perches unregister_card(p); 726475be4d85a274d0961593db41cf85689db1d583cJoe Perches p->interface.statcallb = NULL; 727475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 728475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 729475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (act2000_isa_config_irq(p, p->irq)) { 730475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_INFO 731475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: No IRQ available, fallback to polling\n"); 732475be4d85a274d0961593db41cf85689db1d583cJoe Perches /* Fall back to polled operation */ 733475be4d85a274d0961593db41cf85689db1d583cJoe Perches p->irq = 0; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 735475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_INFO 736475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: ISA" 737475be4d85a274d0961593db41cf85689db1d583cJoe Perches "-type card at port " 738475be4d85a274d0961593db41cf85689db1d583cJoe Perches "0x%04x ", 739475be4d85a274d0961593db41cf85689db1d583cJoe Perches p->port); 740475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (p->irq) 741475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk("irq %d\n", p->irq); 742475be4d85a274d0961593db41cf85689db1d583cJoe Perches else 743475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk("polled\n"); 744475be4d85a274d0961593db41cf85689db1d583cJoe Perches initialized = 1; 745475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 746475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 747475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_MCA: 748475be4d85a274d0961593db41cf85689db1d583cJoe Perches case ACT2000_BUS_PCMCIA: 749475be4d85a274d0961593db41cf85689db1d583cJoe Perches default: 750475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 751475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: addcard: Invalid BUS type %d\n", 752475be4d85a274d0961593db41cf85689db1d583cJoe Perches p->bus); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Card already initialized */ 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initialized = 1; 757475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (initialized) { 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Init OK, next card ... */ 759475be4d85a274d0961593db41cf85689db1d583cJoe Perches q = p; 760475be4d85a274d0961593db41cf85689db1d583cJoe Perches p = p->next; 761475be4d85a274d0961593db41cf85689db1d583cJoe Perches } else { 762475be4d85a274d0961593db41cf85689db1d583cJoe Perches /* Init failed, remove card from list, free memory */ 763475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_WARNING 764475be4d85a274d0961593db41cf85689db1d583cJoe Perches "act2000: Initialization of %s failed\n", 765475be4d85a274d0961593db41cf85689db1d583cJoe Perches p->interface.id); 766475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (q) { 767475be4d85a274d0961593db41cf85689db1d583cJoe Perches q->next = p->next; 768475be4d85a274d0961593db41cf85689db1d583cJoe Perches kfree(p); 769475be4d85a274d0961593db41cf85689db1d583cJoe Perches p = q->next; 770475be4d85a274d0961593db41cf85689db1d583cJoe Perches } else { 771475be4d85a274d0961593db41cf85689db1d583cJoe Perches cards = p->next; 772475be4d85a274d0961593db41cf85689db1d583cJoe Perches kfree(p); 773475be4d85a274d0961593db41cf85689db1d583cJoe Perches p = cards; 774475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed++; 776475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 778475be4d85a274d0961593db41cf85689db1d583cJoe Perches return (added - failed); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVERNAME "IBM Active 2000 ISDN driver" 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init act2000_init(void) 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 785475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_INFO "%s\n", DRIVERNAME); 786475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!cards) 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds act2000_addcard(act_bus, act_port, act_irq, act_id); 788475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!cards) 789475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_INFO "act2000: No cards defined yet\n"); 790475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit act2000_exit(void) 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 795475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_card *card = cards; 796475be4d85a274d0961593db41cf85689db1d583cJoe Perches act2000_card *last; 797475be4d85a274d0961593db41cf85689db1d583cJoe Perches while (card) { 798475be4d85a274d0961593db41cf85689db1d583cJoe Perches unregister_card(card); 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer(&card->ptimer); 800475be4d85a274d0961593db41cf85689db1d583cJoe Perches card = card->next; 801475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 802475be4d85a274d0961593db41cf85689db1d583cJoe Perches card = cards; 803475be4d85a274d0961593db41cf85689db1d583cJoe Perches while (card) { 804475be4d85a274d0961593db41cf85689db1d583cJoe Perches last = card; 805475be4d85a274d0961593db41cf85689db1d583cJoe Perches card = card->next; 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds act2000_clear_msn(last); 807475be4d85a274d0961593db41cf85689db1d583cJoe Perches kfree(last); 808475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 809475be4d85a274d0961593db41cf85689db1d583cJoe Perches printk(KERN_INFO "%s unloaded\n", DRIVERNAME); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(act2000_init); 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(act2000_exit); 814