1/* $Id: b1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ 2 * 3 * Module for AVM B1 ISA-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/capi.h> 20#include <linux/init.h> 21#include <linux/pci.h> 22#include <asm/io.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.3 $"; 31 32/* ------------------------------------------------------------- */ 33 34MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 ISA card"); 35MODULE_AUTHOR("Carsten Paeth"); 36MODULE_LICENSE("GPL"); 37 38/* ------------------------------------------------------------- */ 39 40static void b1isa_remove(struct pci_dev *pdev) 41{ 42 avmctrl_info *cinfo = pci_get_drvdata(pdev); 43 avmcard *card; 44 45 if (!cinfo) 46 return; 47 48 card = cinfo->card; 49 50 b1_reset(card->port); 51 b1_reset(card->port); 52 53 detach_capi_ctr(&cinfo->capi_ctrl); 54 free_irq(card->irq, card); 55 release_region(card->port, AVMB1_PORTLEN); 56 b1_free_card(card); 57} 58 59/* ------------------------------------------------------------- */ 60 61static char *b1isa_procinfo(struct capi_ctr *ctrl); 62 63static int b1isa_probe(struct pci_dev *pdev) 64{ 65 avmctrl_info *cinfo; 66 avmcard *card; 67 int retval; 68 69 card = b1_alloc_card(1); 70 if (!card) { 71 printk(KERN_WARNING "b1isa: no memory.\n"); 72 retval = -ENOMEM; 73 goto err; 74 } 75 76 cinfo = card->ctrlinfo; 77 78 card->port = pci_resource_start(pdev, 0); 79 card->irq = pdev->irq; 80 card->cardtype = avm_b1isa; 81 sprintf(card->name, "b1isa-%x", card->port); 82 83 if (card->port != 0x150 && card->port != 0x250 84 && card->port != 0x300 && card->port != 0x340) { 85 printk(KERN_WARNING "b1isa: invalid port 0x%x.\n", card->port); 86 retval = -EINVAL; 87 goto err_free; 88 } 89 if (b1_irq_table[card->irq & 0xf] == 0) { 90 printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq); 91 retval = -EINVAL; 92 goto err_free; 93 } 94 if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { 95 printk(KERN_WARNING "b1isa: ports 0x%03x-0x%03x in use.\n", 96 card->port, card->port + AVMB1_PORTLEN); 97 retval = -EBUSY; 98 goto err_free; 99 } 100 retval = request_irq(card->irq, b1_interrupt, 0, card->name, card); 101 if (retval) { 102 printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq); 103 goto err_release_region; 104 } 105 b1_reset(card->port); 106 if ((retval = b1_detect(card->port, card->cardtype)) != 0) { 107 printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n", 108 card->port, retval); 109 retval = -ENODEV; 110 goto err_free_irq; 111 } 112 b1_reset(card->port); 113 b1_getrevision(card); 114 115 cinfo->capi_ctrl.owner = THIS_MODULE; 116 cinfo->capi_ctrl.driver_name = "b1isa"; 117 cinfo->capi_ctrl.driverdata = cinfo; 118 cinfo->capi_ctrl.register_appl = b1_register_appl; 119 cinfo->capi_ctrl.release_appl = b1_release_appl; 120 cinfo->capi_ctrl.send_message = b1_send_message; 121 cinfo->capi_ctrl.load_firmware = b1_load_firmware; 122 cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; 123 cinfo->capi_ctrl.procinfo = b1isa_procinfo; 124 cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; 125 strcpy(cinfo->capi_ctrl.name, card->name); 126 127 retval = attach_capi_ctr(&cinfo->capi_ctrl); 128 if (retval) { 129 printk(KERN_ERR "b1isa: attach controller failed.\n"); 130 goto err_free_irq; 131 } 132 133 printk(KERN_INFO "b1isa: AVM B1 ISA at i/o %#x, irq %d, revision %d\n", 134 card->port, card->irq, card->revision); 135 136 pci_set_drvdata(pdev, cinfo); 137 return 0; 138 139err_free_irq: 140 free_irq(card->irq, card); 141err_release_region: 142 release_region(card->port, AVMB1_PORTLEN); 143err_free: 144 b1_free_card(card); 145err: 146 return retval; 147} 148 149static char *b1isa_procinfo(struct capi_ctr *ctrl) 150{ 151 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); 152 153 if (!cinfo) 154 return ""; 155 sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", 156 cinfo->cardname[0] ? cinfo->cardname : "-", 157 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", 158 cinfo->card ? cinfo->card->port : 0x0, 159 cinfo->card ? cinfo->card->irq : 0, 160 cinfo->card ? cinfo->card->revision : 0 161 ); 162 return cinfo->infobuf; 163} 164 165/* ------------------------------------------------------------- */ 166 167#define MAX_CARDS 4 168static struct pci_dev isa_dev[MAX_CARDS]; 169static int io[MAX_CARDS]; 170static int irq[MAX_CARDS]; 171 172module_param_array(io, int, NULL, 0); 173module_param_array(irq, int, NULL, 0); 174MODULE_PARM_DESC(io, "I/O base address(es)"); 175MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); 176 177static int b1isa_add_card(struct capi_driver *driver, capicardparams *data) 178{ 179 int i; 180 181 for (i = 0; i < MAX_CARDS; i++) { 182 if (isa_dev[i].resource[0].start) 183 continue; 184 185 isa_dev[i].resource[0].start = data->port; 186 isa_dev[i].irq = data->irq; 187 188 if (b1isa_probe(&isa_dev[i]) == 0) 189 return 0; 190 } 191 return -ENODEV; 192} 193 194static struct capi_driver capi_driver_b1isa = { 195 .name = "b1isa", 196 .revision = "1.0", 197 .add_card = b1isa_add_card, 198}; 199 200static int __init b1isa_init(void) 201{ 202 char *p; 203 char rev[32]; 204 int i; 205 206 if ((p = strchr(revision, ':')) != NULL && p[1]) { 207 strlcpy(rev, p + 2, 32); 208 if ((p = strchr(rev, '$')) != NULL && p > rev) 209 *(p - 1) = 0; 210 } else 211 strcpy(rev, "1.0"); 212 213 for (i = 0; i < MAX_CARDS; i++) { 214 if (!io[i]) 215 break; 216 217 isa_dev[i].resource[0].start = io[i]; 218 isa_dev[i].irq = irq[i]; 219 220 if (b1isa_probe(&isa_dev[i]) != 0) 221 return -ENODEV; 222 } 223 224 strlcpy(capi_driver_b1isa.revision, rev, 32); 225 register_capi_driver(&capi_driver_b1isa); 226 printk(KERN_INFO "b1isa: revision %s\n", rev); 227 228 return 0; 229} 230 231static void __exit b1isa_exit(void) 232{ 233 int i; 234 235 for (i = 0; i < MAX_CARDS; i++) { 236 if (isa_dev[i].resource[0].start) 237 b1isa_remove(&isa_dev[i]); 238 } 239 unregister_capi_driver(&capi_driver_b1isa); 240} 241 242module_init(b1isa_init); 243module_exit(b1isa_exit); 244