11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A PCMCIA client driver for AVM B1/M1/M2 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1999 by Carsten Paeth <calle@calle.de> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cistpl.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ciscode.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ds.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cisreg.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/capi.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/b1lli.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/b1pcmcia.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2"); 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Carsten Paeth"); 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4015b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int avmcs_config(struct pcmcia_device *link); 41fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void avmcs_release(struct pcmcia_device *link); 42cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowskistatic void avmcs_detach(struct pcmcia_device *p_dev); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4415b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int avmcs_probe(struct pcmcia_device *p_dev) 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 46475be4d85a274d0961593db41cf85689db1d583cJoe Perches /* General socket configuration */ 47475be4d85a274d0961593db41cf85689db1d583cJoe Perches p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 48475be4d85a274d0961593db41cf85689db1d583cJoe Perches p_dev->config_index = 1; 49475be4d85a274d0961593db41cf85689db1d583cJoe Perches p_dev->config_regs = PRESENT_OPTION; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51475be4d85a274d0961593db41cf85689db1d583cJoe Perches return avmcs_config(p_dev); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* avmcs_attach */ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void avmcs_detach(struct pcmcia_device *link) 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 57cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski avmcs_release(link); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* avmcs_detach */ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6000990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowskistatic int avmcs_configcheck(struct pcmcia_device *p_dev, void *priv_data) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6200990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski p_dev->resource[0]->end = 16; 6300990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 6400990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; 655fcd4da0090828bd34a1956cb322a483c6bf163cDominik Brodowski 6690abdc3b973229bae98dd96649d9f7106cc177a4Dominik Brodowski return pcmcia_request_io(p_dev); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6915b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int avmcs_config(struct pcmcia_device *link) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 71475be4d85a274d0961593db41cf85689db1d583cJoe Perches int i = -1; 72475be4d85a274d0961593db41cf85689db1d583cJoe Perches char devname[128]; 73475be4d85a274d0961593db41cf85689db1d583cJoe Perches int cardtype; 74475be4d85a274d0961593db41cf85689db1d583cJoe Perches int (*addcard)(unsigned int port, unsigned irq); 75475be4d85a274d0961593db41cf85689db1d583cJoe Perches 76475be4d85a274d0961593db41cf85689db1d583cJoe Perches devname[0] = 0; 77475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (link->prod_id[1]) 78475be4d85a274d0961593db41cf85689db1d583cJoe Perches strlcpy(devname, link->prod_id[1], sizeof(devname)); 7950db3fdbbc98260fb538c1cc3f8cc597ba7bffe7Dominik Brodowski 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 81475be4d85a274d0961593db41cf85689db1d583cJoe Perches * find IO port 82475be4d85a274d0961593db41cf85689db1d583cJoe Perches */ 83475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (pcmcia_loop_config(link, avmcs_configcheck, NULL)) 84475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 85475be4d85a274d0961593db41cf85689db1d583cJoe Perches 86475be4d85a274d0961593db41cf85689db1d583cJoe Perches do { 87475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!link->irq) { 88475be4d85a274d0961593db41cf85689db1d583cJoe Perches /* undo */ 89475be4d85a274d0961593db41cf85689db1d583cJoe Perches pcmcia_disable_device(link); 90475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 91475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 92475be4d85a274d0961593db41cf85689db1d583cJoe Perches 93475be4d85a274d0961593db41cf85689db1d583cJoe Perches /* 94475be4d85a274d0961593db41cf85689db1d583cJoe Perches * configure the PCMCIA socket 95475be4d85a274d0961593db41cf85689db1d583cJoe Perches */ 96475be4d85a274d0961593db41cf85689db1d583cJoe Perches i = pcmcia_enable_device(link); 97475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (i != 0) { 98475be4d85a274d0961593db41cf85689db1d583cJoe Perches pcmcia_disable_device(link); 99475be4d85a274d0961593db41cf85689db1d583cJoe Perches break; 100475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 101475be4d85a274d0961593db41cf85689db1d583cJoe Perches 102475be4d85a274d0961593db41cf85689db1d583cJoe Perches } while (0); 103475be4d85a274d0961593db41cf85689db1d583cJoe Perches 104475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (devname[0]) { 105475be4d85a274d0961593db41cf85689db1d583cJoe Perches char *s = strrchr(devname, ' '); 106475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!s) 107475be4d85a274d0961593db41cf85689db1d583cJoe Perches s = devname; 108475be4d85a274d0961593db41cf85689db1d583cJoe Perches else s++; 109475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (strcmp("M1", s) == 0) { 110475be4d85a274d0961593db41cf85689db1d583cJoe Perches cardtype = AVM_CARDTYPE_M1; 111475be4d85a274d0961593db41cf85689db1d583cJoe Perches } else if (strcmp("M2", s) == 0) { 112475be4d85a274d0961593db41cf85689db1d583cJoe Perches cardtype = AVM_CARDTYPE_M2; 113475be4d85a274d0961593db41cf85689db1d583cJoe Perches } else { 114475be4d85a274d0961593db41cf85689db1d583cJoe Perches cardtype = AVM_CARDTYPE_B1; 115475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 116475be4d85a274d0961593db41cf85689db1d583cJoe Perches } else 117475be4d85a274d0961593db41cf85689db1d583cJoe Perches cardtype = AVM_CARDTYPE_B1; 118475be4d85a274d0961593db41cf85689db1d583cJoe Perches 119475be4d85a274d0961593db41cf85689db1d583cJoe Perches /* If any step failed, release any partially configured state */ 1204c89e88bfde6a3c179790e21004f24e09a058290Dominik Brodowski if (i != 0) { 121475be4d85a274d0961593db41cf85689db1d583cJoe Perches avmcs_release(link); 122475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 126475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (cardtype) { 127475be4d85a274d0961593db41cf85689db1d583cJoe Perches case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break; 128475be4d85a274d0961593db41cf85689db1d583cJoe Perches case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 130475be4d85a274d0961593db41cf85689db1d583cJoe Perches case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break; 131475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 132475be4d85a274d0961593db41cf85689db1d583cJoe Perches if ((i = (*addcard)(link->resource[0]->start, link->irq)) < 0) { 133475be4d85a274d0961593db41cf85689db1d583cJoe Perches dev_err(&link->dev, 134475be4d85a274d0961593db41cf85689db1d583cJoe Perches "avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n", 135475be4d85a274d0961593db41cf85689db1d583cJoe Perches (unsigned int) link->resource[0]->start, link->irq); 136475be4d85a274d0961593db41cf85689db1d583cJoe Perches avmcs_release(link); 137475be4d85a274d0961593db41cf85689db1d583cJoe Perches return -ENODEV; 138475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 139475be4d85a274d0961593db41cf85689db1d583cJoe Perches return 0; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* avmcs_config */ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 144fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void avmcs_release(struct pcmcia_device *link) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1469a017a910346afd88ec2e065989903bf211a7d37Dominik Brodowski b1pcmcia_delcard(link->resource[0]->start, link->irq); 147fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowski pcmcia_disable_device(link); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* avmcs_release */ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15125f8f54f6e178acfd503a95441b0ea05c525f751Joe Perchesstatic const struct pcmcia_device_id avmcs_ids[] = { 152a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335), 153a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430), 154a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a), 155a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski PCMCIA_DEVICE_NULL 156a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski}; 157a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik BrodowskiMODULE_DEVICE_TABLE(pcmcia, avmcs_ids); 158a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pcmcia_driver avmcs_driver = { 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1612e9b981a7c63ee8278df6823f8389d69dad1a499Dominik Brodowski .name = "avm_cs", 16215b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski .probe = avmcs_probe, 163cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski .remove = avmcs_detach, 164a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski .id_table = avmcs_ids, 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init avmcs_init(void) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pcmcia_register_driver(&avmcs_driver); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit avmcs_exit(void) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_unregister_driver(&avmcs_driver); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(avmcs_init); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(avmcs_exit); 179