1/* 2 * PCMCIA client driver for AVM A1 / Fritz!PCMCIA 3 * 4 * Author Carsten Paeth 5 * Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.de> 6 * 7 * This software may be used and distributed according to the terms 8 * of the GNU General Public License, incorporated herein by reference. 9 * 10 */ 11 12#include <linux/module.h> 13 14 15#include <linux/kernel.h> 16#include <linux/init.h> 17#include <linux/ptrace.h> 18#include <linux/slab.h> 19#include <linux/string.h> 20#include <asm/io.h> 21 22#include <pcmcia/cistpl.h> 23#include <pcmcia/ds.h> 24#include "hisax_cfg.h" 25 26MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards"); 27MODULE_AUTHOR("Carsten Paeth"); 28MODULE_LICENSE("GPL"); 29 30 31/*====================================================================*/ 32 33/* Parameters that can be set with 'insmod' */ 34 35static int isdnprot = 2; 36 37module_param(isdnprot, int, 0); 38 39/*====================================================================*/ 40 41static int avma1cs_config(struct pcmcia_device *link); 42static void avma1cs_release(struct pcmcia_device *link); 43static void avma1cs_detach(struct pcmcia_device *p_dev); 44 45static int avma1cs_probe(struct pcmcia_device *p_dev) 46{ 47 dev_dbg(&p_dev->dev, "avma1cs_attach()\n"); 48 49 /* General socket configuration */ 50 p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 51 p_dev->config_index = 1; 52 p_dev->config_regs = PRESENT_OPTION; 53 54 return avma1cs_config(p_dev); 55} /* avma1cs_attach */ 56 57static void avma1cs_detach(struct pcmcia_device *link) 58{ 59 dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link); 60 avma1cs_release(link); 61 kfree(link->priv); 62} /* avma1cs_detach */ 63 64static int avma1cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) 65{ 66 p_dev->resource[0]->end = 16; 67 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 68 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; 69 p_dev->io_lines = 5; 70 71 return pcmcia_request_io(p_dev); 72} 73 74 75static int avma1cs_config(struct pcmcia_device *link) 76{ 77 int i = -1; 78 char devname[128]; 79 IsdnCard_t icard; 80 int busy = 0; 81 82 dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link); 83 84 devname[0] = 0; 85 if (link->prod_id[1]) 86 strlcpy(devname, link->prod_id[1], sizeof(devname)); 87 88 if (pcmcia_loop_config(link, avma1cs_configcheck, NULL)) 89 return -ENODEV; 90 91 do { 92 /* 93 * allocate an interrupt line 94 */ 95 if (!link->irq) { 96 /* undo */ 97 pcmcia_disable_device(link); 98 break; 99 } 100 101 /* 102 * configure the PCMCIA socket 103 */ 104 i = pcmcia_enable_device(link); 105 if (i != 0) { 106 pcmcia_disable_device(link); 107 break; 108 } 109 110 } while (0); 111 112 /* If any step failed, release any partially configured state */ 113 if (i != 0) { 114 avma1cs_release(link); 115 return -ENODEV; 116 } 117 118 icard.para[0] = link->irq; 119 icard.para[1] = link->resource[0]->start; 120 icard.protocol = isdnprot; 121 icard.typ = ISDN_CTYPE_A1_PCMCIA; 122 123 i = hisax_init_pcmcia(link, &busy, &icard); 124 if (i < 0) { 125 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 " 126 "PCMCIA %d at i/o %#x\n", i, 127 (unsigned int) link->resource[0]->start); 128 avma1cs_release(link); 129 return -ENODEV; 130 } 131 link->priv = (void *) (unsigned long) i; 132 133 return 0; 134} /* avma1cs_config */ 135 136static void avma1cs_release(struct pcmcia_device *link) 137{ 138 unsigned long minor = (unsigned long) link->priv; 139 140 dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link); 141 142 /* now unregister function with hisax */ 143 HiSax_closecard(minor); 144 145 pcmcia_disable_device(link); 146} /* avma1cs_release */ 147 148static const struct pcmcia_device_id avma1cs_ids[] = { 149 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), 150 PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b), 151 PCMCIA_DEVICE_NULL 152}; 153MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids); 154 155static struct pcmcia_driver avma1cs_driver = { 156 .owner = THIS_MODULE, 157 .name = "avma1_cs", 158 .probe = avma1cs_probe, 159 .remove = avma1cs_detach, 160 .id_table = avma1cs_ids, 161}; 162module_pcmcia_driver(avma1cs_driver); 163