avma1_cs.c 4.1 KB

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