1/* $Id: b1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ 2 * 3 * Module for AVM B1 PCI-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/pci.h> 20#include <linux/capi.h> 21#include <asm/io.h> 22#include <linux/init.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 34static struct pci_device_id b1pci_pci_tbl[] = { 35 { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID }, 36 { } /* Terminating entry */ 37}; 38 39MODULE_DEVICE_TABLE(pci, b1pci_pci_tbl); 40MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 PCI card"); 41MODULE_AUTHOR("Carsten Paeth"); 42MODULE_LICENSE("GPL"); 43 44/* ------------------------------------------------------------- */ 45 46static char *b1pci_procinfo(struct capi_ctr *ctrl) 47{ 48 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); 49 50 if (!cinfo) 51 return ""; 52 sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", 53 cinfo->cardname[0] ? cinfo->cardname : "-", 54 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", 55 cinfo->card ? cinfo->card->port : 0x0, 56 cinfo->card ? cinfo->card->irq : 0, 57 cinfo->card ? cinfo->card->revision : 0 58 ); 59 return cinfo->infobuf; 60} 61 62/* ------------------------------------------------------------- */ 63 64static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev) 65{ 66 avmcard *card; 67 avmctrl_info *cinfo; 68 int retval; 69 70 card = b1_alloc_card(1); 71 if (!card) { 72 printk(KERN_WARNING "b1pci: no memory.\n"); 73 retval = -ENOMEM; 74 goto err; 75 } 76 77 cinfo = card->ctrlinfo; 78 sprintf(card->name, "b1pci-%x", p->port); 79 card->port = p->port; 80 card->irq = p->irq; 81 card->cardtype = avm_b1pci; 82 83 if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { 84 printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n", 85 card->port, card->port + AVMB1_PORTLEN); 86 retval = -EBUSY; 87 goto err_free; 88 } 89 b1_reset(card->port); 90 retval = b1_detect(card->port, card->cardtype); 91 if (retval) { 92 printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n", 93 card->port, retval); 94 retval = -ENODEV; 95 goto err_release_region; 96 } 97 b1_reset(card->port); 98 b1_getrevision(card); 99 100 retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card); 101 if (retval) { 102 printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq); 103 retval = -EBUSY; 104 goto err_release_region; 105 } 106 107 cinfo->capi_ctrl.driver_name = "b1pci"; 108 cinfo->capi_ctrl.driverdata = cinfo; 109 cinfo->capi_ctrl.register_appl = b1_register_appl; 110 cinfo->capi_ctrl.release_appl = b1_release_appl; 111 cinfo->capi_ctrl.send_message = b1_send_message; 112 cinfo->capi_ctrl.load_firmware = b1_load_firmware; 113 cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; 114 cinfo->capi_ctrl.procinfo = b1pci_procinfo; 115 cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; 116 strcpy(cinfo->capi_ctrl.name, card->name); 117 cinfo->capi_ctrl.owner = THIS_MODULE; 118 119 retval = attach_capi_ctr(&cinfo->capi_ctrl); 120 if (retval) { 121 printk(KERN_ERR "b1pci: attach controller failed.\n"); 122 goto err_free_irq; 123 } 124 125 if (card->revision >= 4) { 126 printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n", 127 card->port, card->irq, card->revision); 128 } else { 129 printk(KERN_INFO "b1pci: AVM B1 PCI at i/o %#x, irq %d, revision %d\n", 130 card->port, card->irq, card->revision); 131 } 132 133 pci_set_drvdata(pdev, card); 134 return 0; 135 136err_free_irq: 137 free_irq(card->irq, card); 138err_release_region: 139 release_region(card->port, AVMB1_PORTLEN); 140err_free: 141 b1_free_card(card); 142err: 143 return retval; 144} 145 146static void b1pci_remove(struct pci_dev *pdev) 147{ 148 avmcard *card = pci_get_drvdata(pdev); 149 avmctrl_info *cinfo = card->ctrlinfo; 150 unsigned int port = card->port; 151 152 b1_reset(port); 153 b1_reset(port); 154 155 detach_capi_ctr(&cinfo->capi_ctrl); 156 free_irq(card->irq, card); 157 release_region(card->port, AVMB1_PORTLEN); 158 b1_free_card(card); 159} 160 161#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 162/* ------------------------------------------------------------- */ 163 164static char *b1pciv4_procinfo(struct capi_ctr *ctrl) 165{ 166 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); 167 168 if (!cinfo) 169 return ""; 170 sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d", 171 cinfo->cardname[0] ? cinfo->cardname : "-", 172 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", 173 cinfo->card ? cinfo->card->port : 0x0, 174 cinfo->card ? cinfo->card->irq : 0, 175 cinfo->card ? cinfo->card->membase : 0, 176 cinfo->card ? cinfo->card->revision : 0 177 ); 178 return cinfo->infobuf; 179} 180 181/* ------------------------------------------------------------- */ 182 183static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev) 184{ 185 avmcard *card; 186 avmctrl_info *cinfo; 187 int retval; 188 189 card = b1_alloc_card(1); 190 if (!card) { 191 printk(KERN_WARNING "b1pci: no memory.\n"); 192 retval = -ENOMEM; 193 goto err; 194 } 195 196 card->dma = avmcard_dma_alloc("b1pci", pdev, 2048 + 128, 2048 + 128); 197 if (!card->dma) { 198 printk(KERN_WARNING "b1pci: dma alloc.\n"); 199 retval = -ENOMEM; 200 goto err_free; 201 } 202 203 cinfo = card->ctrlinfo; 204 sprintf(card->name, "b1pciv4-%x", p->port); 205 card->port = p->port; 206 card->irq = p->irq; 207 card->membase = p->membase; 208 card->cardtype = avm_b1pci; 209 210 if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { 211 printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n", 212 card->port, card->port + AVMB1_PORTLEN); 213 retval = -EBUSY; 214 goto err_free_dma; 215 } 216 217 card->mbase = ioremap(card->membase, 64); 218 if (!card->mbase) { 219 printk(KERN_NOTICE "b1pci: can't remap memory at 0x%lx\n", 220 card->membase); 221 retval = -ENOMEM; 222 goto err_release_region; 223 } 224 225 b1dma_reset(card); 226 227 retval = b1pciv4_detect(card); 228 if (retval) { 229 printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n", 230 card->port, retval); 231 retval = -ENODEV; 232 goto err_unmap; 233 } 234 b1dma_reset(card); 235 b1_getrevision(card); 236 237 retval = request_irq(card->irq, b1dma_interrupt, IRQF_SHARED, card->name, card); 238 if (retval) { 239 printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", 240 card->irq); 241 retval = -EBUSY; 242 goto err_unmap; 243 } 244 245 cinfo->capi_ctrl.owner = THIS_MODULE; 246 cinfo->capi_ctrl.driver_name = "b1pciv4"; 247 cinfo->capi_ctrl.driverdata = cinfo; 248 cinfo->capi_ctrl.register_appl = b1dma_register_appl; 249 cinfo->capi_ctrl.release_appl = b1dma_release_appl; 250 cinfo->capi_ctrl.send_message = b1dma_send_message; 251 cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; 252 cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; 253 cinfo->capi_ctrl.procinfo = b1pciv4_procinfo; 254 cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops; 255 strcpy(cinfo->capi_ctrl.name, card->name); 256 257 retval = attach_capi_ctr(&cinfo->capi_ctrl); 258 if (retval) { 259 printk(KERN_ERR "b1pci: attach controller failed.\n"); 260 goto err_free_irq; 261 } 262 card->cardnr = cinfo->capi_ctrl.cnr; 263 264 printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n", 265 card->port, card->irq, card->membase, card->revision); 266 267 pci_set_drvdata(pdev, card); 268 return 0; 269 270err_free_irq: 271 free_irq(card->irq, card); 272err_unmap: 273 iounmap(card->mbase); 274err_release_region: 275 release_region(card->port, AVMB1_PORTLEN); 276err_free_dma: 277 avmcard_dma_free(card->dma); 278err_free: 279 b1_free_card(card); 280err: 281 return retval; 282 283} 284 285static void b1pciv4_remove(struct pci_dev *pdev) 286{ 287 avmcard *card = pci_get_drvdata(pdev); 288 avmctrl_info *cinfo = card->ctrlinfo; 289 290 b1dma_reset(card); 291 292 detach_capi_ctr(&cinfo->capi_ctrl); 293 free_irq(card->irq, card); 294 iounmap(card->mbase); 295 release_region(card->port, AVMB1_PORTLEN); 296 avmcard_dma_free(card->dma); 297 b1_free_card(card); 298} 299 300#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */ 301 302static int b1pci_pci_probe(struct pci_dev *pdev, 303 const struct pci_device_id *ent) 304{ 305 struct capicardparams param; 306 int retval; 307 308 if (pci_enable_device(pdev) < 0) { 309 printk(KERN_ERR "b1pci: failed to enable AVM-B1\n"); 310 return -ENODEV; 311 } 312 param.irq = pdev->irq; 313 314 if (pci_resource_start(pdev, 2)) { /* B1 PCI V4 */ 315#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 316 pci_set_master(pdev); 317#endif 318 param.membase = pci_resource_start(pdev, 0); 319 param.port = pci_resource_start(pdev, 2); 320 321 printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n", 322 param.port, param.irq, param.membase); 323#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 324 retval = b1pciv4_probe(¶m, pdev); 325#else 326 retval = b1pci_probe(¶m, pdev); 327#endif 328 if (retval != 0) { 329 printk(KERN_ERR "b1pci: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n", 330 param.port, param.irq, param.membase); 331 } 332 } else { 333 param.membase = 0; 334 param.port = pci_resource_start(pdev, 1); 335 336 printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", 337 param.port, param.irq); 338 retval = b1pci_probe(¶m, pdev); 339 if (retval != 0) { 340 printk(KERN_ERR "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n", 341 param.port, param.irq); 342 } 343 } 344 return retval; 345} 346 347static void b1pci_pci_remove(struct pci_dev *pdev) 348{ 349#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 350 avmcard *card = pci_get_drvdata(pdev); 351 352 if (card->dma) 353 b1pciv4_remove(pdev); 354 else 355 b1pci_remove(pdev); 356#else 357 b1pci_remove(pdev); 358#endif 359} 360 361static struct pci_driver b1pci_pci_driver = { 362 .name = "b1pci", 363 .id_table = b1pci_pci_tbl, 364 .probe = b1pci_pci_probe, 365 .remove = b1pci_pci_remove, 366}; 367 368static struct capi_driver capi_driver_b1pci = { 369 .name = "b1pci", 370 .revision = "1.0", 371}; 372#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 373static struct capi_driver capi_driver_b1pciv4 = { 374 .name = "b1pciv4", 375 .revision = "1.0", 376}; 377#endif 378 379static int __init b1pci_init(void) 380{ 381 char *p; 382 char rev[32]; 383 int err; 384 385 if ((p = strchr(revision, ':')) != NULL && p[1]) { 386 strlcpy(rev, p + 2, 32); 387 if ((p = strchr(rev, '$')) != NULL && p > rev) 388 *(p - 1) = 0; 389 } else 390 strcpy(rev, "1.0"); 391 392 393 err = pci_register_driver(&b1pci_pci_driver); 394 if (!err) { 395 strlcpy(capi_driver_b1pci.revision, rev, 32); 396 register_capi_driver(&capi_driver_b1pci); 397#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 398 strlcpy(capi_driver_b1pciv4.revision, rev, 32); 399 register_capi_driver(&capi_driver_b1pciv4); 400#endif 401 printk(KERN_INFO "b1pci: revision %s\n", rev); 402 } 403 return err; 404} 405 406static void __exit b1pci_exit(void) 407{ 408 unregister_capi_driver(&capi_driver_b1pci); 409#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 410 unregister_capi_driver(&capi_driver_b1pciv4); 411#endif 412 pci_unregister_driver(&b1pci_pci_driver); 413} 414 415module_init(b1pci_init); 416module_exit(b1pci_exit); 417