1/* $Id: b1pcmcia.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ 2 * 3 * Module for AVM B1/M1/M2 PCMCIA-card. 4 * 5 * Copyright 1999 by Carsten Paeth <calle@calle.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#include <linux/kernel.h> 14#include <linux/skbuff.h> 15#include <linux/delay.h> 16#include <linux/mm.h> 17#include <linux/interrupt.h> 18#include <linux/ioport.h> 19#include <linux/init.h> 20#include <asm/io.h> 21#include <linux/capi.h> 22#include <linux/b1pcmcia.h> 23#include <linux/isdn/capicmd.h> 24#include <linux/isdn/capiutil.h> 25#include <linux/isdn/capilli.h> 26#include "avmcard.h" 27 28/* ------------------------------------------------------------- */ 29 30static char *revision = "$Revision: 1.1.2.2 $"; 31 32/* ------------------------------------------------------------- */ 33 34MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM PCMCIA cards"); 35MODULE_AUTHOR("Carsten Paeth"); 36MODULE_LICENSE("GPL"); 37 38/* ------------------------------------------------------------- */ 39 40static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl) 41{ 42 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); 43 avmcard *card = cinfo->card; 44 unsigned int port = card->port; 45 46 b1_reset(port); 47 b1_reset(port); 48 49 detach_capi_ctr(ctrl); 50 free_irq(card->irq, card); 51 b1_free_card(card); 52} 53 54/* ------------------------------------------------------------- */ 55 56static LIST_HEAD(cards); 57 58static char *b1pcmcia_procinfo(struct capi_ctr *ctrl); 59 60static int b1pcmcia_add_card(unsigned int port, unsigned irq, 61 enum avmcardtype cardtype) 62{ 63 avmctrl_info *cinfo; 64 avmcard *card; 65 char *cardname; 66 int retval; 67 68 card = b1_alloc_card(1); 69 if (!card) { 70 printk(KERN_WARNING "b1pcmcia: no memory.\n"); 71 retval = -ENOMEM; 72 goto err; 73 } 74 cinfo = card->ctrlinfo; 75 76 switch (cardtype) { 77 case avm_m1: sprintf(card->name, "m1-%x", port); break; 78 case avm_m2: sprintf(card->name, "m2-%x", port); break; 79 default: sprintf(card->name, "b1pcmcia-%x", port); break; 80 } 81 card->port = port; 82 card->irq = irq; 83 card->cardtype = cardtype; 84 85 retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card); 86 if (retval) { 87 printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n", 88 card->irq); 89 retval = -EBUSY; 90 goto err_free; 91 } 92 b1_reset(card->port); 93 if ((retval = b1_detect(card->port, card->cardtype)) != 0) { 94 printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n", 95 card->port, retval); 96 retval = -ENODEV; 97 goto err_free_irq; 98 } 99 b1_reset(card->port); 100 b1_getrevision(card); 101 102 cinfo->capi_ctrl.owner = THIS_MODULE; 103 cinfo->capi_ctrl.driver_name = "b1pcmcia"; 104 cinfo->capi_ctrl.driverdata = cinfo; 105 cinfo->capi_ctrl.register_appl = b1_register_appl; 106 cinfo->capi_ctrl.release_appl = b1_release_appl; 107 cinfo->capi_ctrl.send_message = b1_send_message; 108 cinfo->capi_ctrl.load_firmware = b1_load_firmware; 109 cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; 110 cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo; 111 cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; 112 strcpy(cinfo->capi_ctrl.name, card->name); 113 114 retval = attach_capi_ctr(&cinfo->capi_ctrl); 115 if (retval) { 116 printk(KERN_ERR "b1pcmcia: attach controller failed.\n"); 117 goto err_free_irq; 118 } 119 switch (cardtype) { 120 case avm_m1: cardname = "M1"; break; 121 case avm_m2: cardname = "M2"; break; 122 default: cardname = "B1 PCMCIA"; break; 123 } 124 125 printk(KERN_INFO "b1pcmcia: AVM %s at i/o %#x, irq %d, revision %d\n", 126 cardname, card->port, card->irq, card->revision); 127 128 list_add(&card->list, &cards); 129 return cinfo->capi_ctrl.cnr; 130 131err_free_irq: 132 free_irq(card->irq, card); 133err_free: 134 b1_free_card(card); 135err: 136 return retval; 137} 138 139/* ------------------------------------------------------------- */ 140 141static char *b1pcmcia_procinfo(struct capi_ctr *ctrl) 142{ 143 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); 144 145 if (!cinfo) 146 return ""; 147 sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", 148 cinfo->cardname[0] ? cinfo->cardname : "-", 149 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", 150 cinfo->card ? cinfo->card->port : 0x0, 151 cinfo->card ? cinfo->card->irq : 0, 152 cinfo->card ? cinfo->card->revision : 0 153 ); 154 return cinfo->infobuf; 155} 156 157/* ------------------------------------------------------------- */ 158 159int b1pcmcia_addcard_b1(unsigned int port, unsigned irq) 160{ 161 return b1pcmcia_add_card(port, irq, avm_b1pcmcia); 162} 163 164int b1pcmcia_addcard_m1(unsigned int port, unsigned irq) 165{ 166 return b1pcmcia_add_card(port, irq, avm_m1); 167} 168 169int b1pcmcia_addcard_m2(unsigned int port, unsigned irq) 170{ 171 return b1pcmcia_add_card(port, irq, avm_m2); 172} 173 174int b1pcmcia_delcard(unsigned int port, unsigned irq) 175{ 176 struct list_head *l; 177 avmcard *card; 178 179 list_for_each(l, &cards) { 180 card = list_entry(l, avmcard, list); 181 if (card->port == port && card->irq == irq) { 182 b1pcmcia_remove_ctr(&card->ctrlinfo[0].capi_ctrl); 183 return 0; 184 } 185 } 186 return -ESRCH; 187} 188 189EXPORT_SYMBOL(b1pcmcia_addcard_b1); 190EXPORT_SYMBOL(b1pcmcia_addcard_m1); 191EXPORT_SYMBOL(b1pcmcia_addcard_m2); 192EXPORT_SYMBOL(b1pcmcia_delcard); 193 194static struct capi_driver capi_driver_b1pcmcia = { 195 .name = "b1pcmcia", 196 .revision = "1.0", 197}; 198 199static int __init b1pcmcia_init(void) 200{ 201 char *p; 202 char rev[32]; 203 204 if ((p = strchr(revision, ':')) != NULL && p[1]) { 205 strlcpy(rev, p + 2, 32); 206 if ((p = strchr(rev, '$')) != NULL && p > rev) 207 *(p - 1) = 0; 208 } else 209 strcpy(rev, "1.0"); 210 211 strlcpy(capi_driver_b1pcmcia.revision, rev, 32); 212 register_capi_driver(&capi_driver_b1pcmcia); 213 printk(KERN_INFO "b1pci: revision %s\n", rev); 214 215 return 0; 216} 217 218static void __exit b1pcmcia_exit(void) 219{ 220 unregister_capi_driver(&capi_driver_b1pcmcia); 221} 222 223module_init(b1pcmcia_init); 224module_exit(b1pcmcia_exit); 225