t1isa.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /* $Id: t1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
  2. *
  3. * Module for AVM T1 HEMA-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. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/skbuff.h>
  14. #include <linux/delay.h>
  15. #include <linux/mm.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/ioport.h>
  18. #include <linux/capi.h>
  19. #include <linux/netdevice.h>
  20. #include <linux/kernelcapi.h>
  21. #include <linux/init.h>
  22. #include <linux/pci.h>
  23. #include <asm/io.h>
  24. #include <linux/isdn/capicmd.h>
  25. #include <linux/isdn/capiutil.h>
  26. #include <linux/isdn/capilli.h>
  27. #include "avmcard.h"
  28. /* ------------------------------------------------------------- */
  29. static char *revision = "$Revision: 1.1.2.3 $";
  30. /* ------------------------------------------------------------- */
  31. MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 HEMA ISA card");
  32. MODULE_AUTHOR("Carsten Paeth");
  33. MODULE_LICENSE("GPL");
  34. /* ------------------------------------------------------------- */
  35. static int hema_irq_table[16] =
  36. {0,
  37. 0,
  38. 0,
  39. 0x80, /* irq 3 */
  40. 0,
  41. 0x90, /* irq 5 */
  42. 0,
  43. 0xA0, /* irq 7 */
  44. 0,
  45. 0xB0, /* irq 9 */
  46. 0xC0, /* irq 10 */
  47. 0xD0, /* irq 11 */
  48. 0xE0, /* irq 12 */
  49. 0,
  50. 0,
  51. 0xF0, /* irq 15 */
  52. };
  53. static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
  54. {
  55. unsigned char cregs[8];
  56. unsigned char reverse_cardnr;
  57. unsigned char dummy;
  58. int i;
  59. reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1)
  60. | ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3);
  61. cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf);
  62. cregs[1] = 0x00; /* fast & slow link connected to CON1 */
  63. cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */
  64. cregs[3] = 0;
  65. cregs[4] = 0x11; /* zero wait state */
  66. cregs[5] = hema_irq_table[irq & 0xf];
  67. cregs[6] = 0;
  68. cregs[7] = 0;
  69. /*
  70. * no one else should use the ISA bus in this moment,
  71. * but no function there to prevent this :-(
  72. * save_flags(flags); cli();
  73. */
  74. /* board reset */
  75. t1outp(base, T1_RESETBOARD, 0xf);
  76. mdelay(100);
  77. dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */
  78. /* write config */
  79. dummy = (base >> 4) & 0xff;
  80. for (i=1;i<=0xf;i++) t1outp(base, i, dummy);
  81. t1outp(base, HEMA_PAL_ID & 0xf, dummy);
  82. t1outp(base, HEMA_PAL_ID >> 4, cregs[0]);
  83. for(i=1;i<7;i++) t1outp(base, 0, cregs[i]);
  84. t1outp(base, ((base >> 4)) & 0x3, cregs[7]);
  85. /* restore_flags(flags); */
  86. mdelay(100);
  87. t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
  88. t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
  89. mdelay(10);
  90. t1outp(base, T1_FASTLINK+T1_RESETLINK, 1);
  91. t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1);
  92. mdelay(100);
  93. t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
  94. t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
  95. mdelay(10);
  96. t1outp(base, T1_FASTLINK+T1_ANALYSE, 0);
  97. mdelay(5);
  98. t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0);
  99. if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */
  100. return 1;
  101. if (t1inp(base, T1_FASTLINK+T1_INSTAT) != 0x0) /* rx empty */
  102. return 2;
  103. if (t1inp(base, T1_FASTLINK+T1_IRQENABLE) != 0x0)
  104. return 3;
  105. if ((t1inp(base, T1_FASTLINK+T1_FIFOSTAT) & 0xf0) != 0x70)
  106. return 4;
  107. if ((t1inp(base, T1_FASTLINK+T1_IRQMASTER) & 0x0e) != 0)
  108. return 5;
  109. if ((t1inp(base, T1_FASTLINK+T1_IDENT) & 0x7d) != 1)
  110. return 6;
  111. if (t1inp(base, T1_SLOWLINK+T1_OUTSTAT) != 0x1) /* tx empty */
  112. return 7;
  113. if ((t1inp(base, T1_SLOWLINK+T1_IRQMASTER) & 0x0e) != 0)
  114. return 8;
  115. if ((t1inp(base, T1_SLOWLINK+T1_IDENT) & 0x7d) != 0)
  116. return 9;
  117. return 0;
  118. }
  119. static irqreturn_t t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
  120. {
  121. avmcard *card = devptr;
  122. avmctrl_info *cinfo = &card->ctrlinfo[0];
  123. struct capi_ctr *ctrl = &cinfo->capi_ctrl;
  124. unsigned char b1cmd;
  125. struct sk_buff *skb;
  126. unsigned ApplId;
  127. unsigned MsgLen;
  128. unsigned DataB3Len;
  129. unsigned NCCI;
  130. unsigned WindowSize;
  131. unsigned long flags;
  132. spin_lock_irqsave(&card->lock, flags);
  133. while (b1_rx_full(card->port)) {
  134. b1cmd = b1_get_byte(card->port);
  135. switch (b1cmd) {
  136. case RECEIVE_DATA_B3_IND:
  137. ApplId = (unsigned) b1_get_word(card->port);
  138. MsgLen = t1_get_slice(card->port, card->msgbuf);
  139. DataB3Len = t1_get_slice(card->port, card->databuf);
  140. spin_unlock_irqrestore(&card->lock, flags);
  141. if (MsgLen < 30) { /* not CAPI 64Bit */
  142. memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
  143. MsgLen = 30;
  144. CAPIMSG_SETLEN(card->msgbuf, 30);
  145. }
  146. if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
  147. printk(KERN_ERR "%s: incoming packet dropped\n",
  148. card->name);
  149. } else {
  150. memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
  151. memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
  152. capi_ctr_handle_message(ctrl, ApplId, skb);
  153. }
  154. break;
  155. case RECEIVE_MESSAGE:
  156. ApplId = (unsigned) b1_get_word(card->port);
  157. MsgLen = t1_get_slice(card->port, card->msgbuf);
  158. spin_unlock_irqrestore(&card->lock, flags);
  159. if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
  160. printk(KERN_ERR "%s: incoming packet dropped\n",
  161. card->name);
  162. } else {
  163. memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
  164. if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3)
  165. capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
  166. CAPIMSG_NCCI(skb->data),
  167. CAPIMSG_MSGID(skb->data));
  168. capi_ctr_handle_message(ctrl, ApplId, skb);
  169. }
  170. break;
  171. case RECEIVE_NEW_NCCI:
  172. ApplId = b1_get_word(card->port);
  173. NCCI = b1_get_word(card->port);
  174. WindowSize = b1_get_word(card->port);
  175. spin_unlock_irqrestore(&card->lock, flags);
  176. capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
  177. break;
  178. case RECEIVE_FREE_NCCI:
  179. ApplId = b1_get_word(card->port);
  180. NCCI = b1_get_word(card->port);
  181. spin_unlock_irqrestore(&card->lock, flags);
  182. if (NCCI != 0xffffffff)
  183. capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
  184. break;
  185. case RECEIVE_START:
  186. b1_put_byte(card->port, SEND_POLLACK);
  187. spin_unlock_irqrestore(&card->lock, flags);
  188. capi_ctr_resume_output(ctrl);
  189. break;
  190. case RECEIVE_STOP:
  191. spin_unlock_irqrestore(&card->lock, flags);
  192. capi_ctr_suspend_output(ctrl);
  193. break;
  194. case RECEIVE_INIT:
  195. cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf);
  196. spin_unlock_irqrestore(&card->lock, flags);
  197. b1_parse_version(cinfo);
  198. printk(KERN_INFO "%s: %s-card (%s) now active\n",
  199. card->name,
  200. cinfo->version[VER_CARDTYPE],
  201. cinfo->version[VER_DRIVER]);
  202. capi_ctr_ready(ctrl);
  203. break;
  204. case RECEIVE_TASK_READY:
  205. ApplId = (unsigned) b1_get_word(card->port);
  206. MsgLen = t1_get_slice(card->port, card->msgbuf);
  207. spin_unlock_irqrestore(&card->lock, flags);
  208. card->msgbuf[MsgLen] = 0;
  209. while ( MsgLen > 0
  210. && ( card->msgbuf[MsgLen-1] == '\n'
  211. || card->msgbuf[MsgLen-1] == '\r')) {
  212. card->msgbuf[MsgLen-1] = 0;
  213. MsgLen--;
  214. }
  215. printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
  216. card->name, ApplId, card->msgbuf);
  217. break;
  218. case RECEIVE_DEBUGMSG:
  219. MsgLen = t1_get_slice(card->port, card->msgbuf);
  220. spin_unlock_irqrestore(&card->lock, flags);
  221. card->msgbuf[MsgLen] = 0;
  222. while ( MsgLen > 0
  223. && ( card->msgbuf[MsgLen-1] == '\n'
  224. || card->msgbuf[MsgLen-1] == '\r')) {
  225. card->msgbuf[MsgLen-1] = 0;
  226. MsgLen--;
  227. }
  228. printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
  229. break;
  230. case 0xff:
  231. spin_unlock_irqrestore(&card->lock, flags);
  232. printk(KERN_ERR "%s: card reseted ?\n", card->name);
  233. return IRQ_HANDLED;
  234. default:
  235. spin_unlock_irqrestore(&card->lock, flags);
  236. printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
  237. card->name, b1cmd);
  238. return IRQ_NONE;
  239. }
  240. }
  241. return IRQ_HANDLED;
  242. }
  243. /* ------------------------------------------------------------- */
  244. static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
  245. {
  246. avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
  247. avmcard *card = cinfo->card;
  248. unsigned int port = card->port;
  249. unsigned long flags;
  250. int retval;
  251. t1_disable_irq(port);
  252. b1_reset(port);
  253. if ((retval = b1_load_t4file(card, &data->firmware))) {
  254. b1_reset(port);
  255. printk(KERN_ERR "%s: failed to load t4file!!\n",
  256. card->name);
  257. return retval;
  258. }
  259. if (data->configuration.len > 0 && data->configuration.data) {
  260. if ((retval = b1_load_config(card, &data->configuration))) {
  261. b1_reset(port);
  262. printk(KERN_ERR "%s: failed to load config!!\n",
  263. card->name);
  264. return retval;
  265. }
  266. }
  267. if (!b1_loaded(card)) {
  268. printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
  269. return -EIO;
  270. }
  271. spin_lock_irqsave(&card->lock, flags);
  272. b1_setinterrupt(port, card->irq, card->cardtype);
  273. b1_put_byte(port, SEND_INIT);
  274. b1_put_word(port, CAPI_MAXAPPL);
  275. b1_put_word(port, AVM_NCCI_PER_CHANNEL*30);
  276. b1_put_word(port, ctrl->cnr - 1);
  277. spin_unlock_irqrestore(&card->lock, flags);
  278. return 0;
  279. }
  280. static void t1isa_reset_ctr(struct capi_ctr *ctrl)
  281. {
  282. avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
  283. avmcard *card = cinfo->card;
  284. unsigned int port = card->port;
  285. t1_disable_irq(port);
  286. b1_reset(port);
  287. b1_reset(port);
  288. memset(cinfo->version, 0, sizeof(cinfo->version));
  289. capilib_release(&cinfo->ncci_head);
  290. capi_ctr_reseted(ctrl);
  291. }
  292. static void t1isa_remove(struct pci_dev *pdev)
  293. {
  294. avmctrl_info *cinfo = pci_get_drvdata(pdev);
  295. avmcard *card;
  296. if (!cinfo)
  297. return;
  298. card = cinfo->card;
  299. t1_disable_irq(card->port);
  300. b1_reset(card->port);
  301. b1_reset(card->port);
  302. t1_reset(card->port);
  303. detach_capi_ctr(&cinfo->capi_ctrl);
  304. free_irq(card->irq, card);
  305. release_region(card->port, AVMB1_PORTLEN);
  306. b1_free_card(card);
  307. }
  308. /* ------------------------------------------------------------- */
  309. static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
  310. static char *t1isa_procinfo(struct capi_ctr *ctrl);
  311. static int t1isa_probe(struct pci_dev *pdev, int cardnr)
  312. {
  313. avmctrl_info *cinfo;
  314. avmcard *card;
  315. int retval;
  316. card = b1_alloc_card(1);
  317. if (!card) {
  318. printk(KERN_WARNING "t1isa: no memory.\n");
  319. retval = -ENOMEM;
  320. goto err;
  321. }
  322. cinfo = card->ctrlinfo;
  323. card->port = pci_resource_start(pdev, 0);
  324. card->irq = pdev->irq;
  325. card->cardtype = avm_t1isa;
  326. card->cardnr = cardnr;
  327. sprintf(card->name, "t1isa-%x", card->port);
  328. if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
  329. printk(KERN_WARNING "t1isa: invalid port 0x%x.\n", card->port);
  330. retval = -EINVAL;
  331. goto err_free;
  332. }
  333. if (hema_irq_table[card->irq & 0xf] == 0) {
  334. printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq);
  335. retval = -EINVAL;
  336. goto err_free;
  337. }
  338. if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
  339. printk(KERN_INFO "t1isa: ports 0x%03x-0x%03x in use.\n",
  340. card->port, card->port + AVMB1_PORTLEN);
  341. retval = -EBUSY;
  342. goto err_free;
  343. }
  344. retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
  345. if (retval) {
  346. printk(KERN_INFO "t1isa: unable to get IRQ %d.\n", card->irq);
  347. retval = -EBUSY;
  348. goto err_release_region;
  349. }
  350. if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
  351. printk(KERN_INFO "t1isa: NO card at 0x%x (%d)\n",
  352. card->port, retval);
  353. retval = -ENODEV;
  354. goto err_free_irq;
  355. }
  356. t1_disable_irq(card->port);
  357. b1_reset(card->port);
  358. cinfo->capi_ctrl.owner = THIS_MODULE;
  359. cinfo->capi_ctrl.driver_name = "t1isa";
  360. cinfo->capi_ctrl.driverdata = cinfo;
  361. cinfo->capi_ctrl.register_appl = b1_register_appl;
  362. cinfo->capi_ctrl.release_appl = b1_release_appl;
  363. cinfo->capi_ctrl.send_message = t1isa_send_message;
  364. cinfo->capi_ctrl.load_firmware = t1isa_load_firmware;
  365. cinfo->capi_ctrl.reset_ctr = t1isa_reset_ctr;
  366. cinfo->capi_ctrl.procinfo = t1isa_procinfo;
  367. cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
  368. strcpy(cinfo->capi_ctrl.name, card->name);
  369. retval = attach_capi_ctr(&cinfo->capi_ctrl);
  370. if (retval) {
  371. printk(KERN_INFO "t1isa: attach controller failed.\n");
  372. goto err_free_irq;
  373. }
  374. printk(KERN_INFO "t1isa: AVM T1 ISA at i/o %#x, irq %d, card %d\n",
  375. card->port, card->irq, card->cardnr);
  376. pci_set_drvdata(pdev, cinfo);
  377. return 0;
  378. err_free_irq:
  379. free_irq(card->irq, card);
  380. err_release_region:
  381. release_region(card->port, AVMB1_PORTLEN);
  382. err_free:
  383. b1_free_card(card);
  384. err:
  385. return retval;
  386. }
  387. static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
  388. {
  389. avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
  390. avmcard *card = cinfo->card;
  391. unsigned int port = card->port;
  392. unsigned long flags;
  393. u16 len = CAPIMSG_LEN(skb->data);
  394. u8 cmd = CAPIMSG_COMMAND(skb->data);
  395. u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
  396. u16 dlen, retval;
  397. if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
  398. retval = capilib_data_b3_req(&cinfo->ncci_head,
  399. CAPIMSG_APPID(skb->data),
  400. CAPIMSG_NCCI(skb->data),
  401. CAPIMSG_MSGID(skb->data));
  402. if (retval != CAPI_NOERROR)
  403. return retval;
  404. dlen = CAPIMSG_DATALEN(skb->data);
  405. spin_lock_irqsave(&card->lock, flags);
  406. b1_put_byte(port, SEND_DATA_B3_REQ);
  407. t1_put_slice(port, skb->data, len);
  408. t1_put_slice(port, skb->data + len, dlen);
  409. spin_unlock_irqrestore(&card->lock, flags);
  410. } else {
  411. spin_lock_irqsave(&card->lock, flags);
  412. b1_put_byte(port, SEND_MESSAGE);
  413. t1_put_slice(port, skb->data, len);
  414. spin_unlock_irqrestore(&card->lock, flags);
  415. }
  416. dev_kfree_skb_any(skb);
  417. return CAPI_NOERROR;
  418. }
  419. /* ------------------------------------------------------------- */
  420. static char *t1isa_procinfo(struct capi_ctr *ctrl)
  421. {
  422. avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
  423. if (!cinfo)
  424. return "";
  425. sprintf(cinfo->infobuf, "%s %s 0x%x %d %d",
  426. cinfo->cardname[0] ? cinfo->cardname : "-",
  427. cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
  428. cinfo->card ? cinfo->card->port : 0x0,
  429. cinfo->card ? cinfo->card->irq : 0,
  430. cinfo->card ? cinfo->card->cardnr : 0
  431. );
  432. return cinfo->infobuf;
  433. }
  434. /* ------------------------------------------------------------- */
  435. #define MAX_CARDS 4
  436. static struct pci_dev isa_dev[MAX_CARDS];
  437. static int io[MAX_CARDS];
  438. static int irq[MAX_CARDS];
  439. static int cardnr[MAX_CARDS];
  440. MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
  441. MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
  442. MODULE_PARM(cardnr, "1-" __MODULE_STRING(MAX_CARDS) "i");
  443. MODULE_PARM_DESC(io, "I/O base address(es)");
  444. MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
  445. MODULE_PARM_DESC(cardnr, "Card number(s) (as jumpered)");
  446. static int t1isa_add_card(struct capi_driver *driver, capicardparams *data)
  447. {
  448. int i;
  449. for (i = 0; i < MAX_CARDS; i++) {
  450. if (isa_dev[i].resource[0].start)
  451. continue;
  452. isa_dev[i].resource[0].start = data->port;
  453. isa_dev[i].irq = data->irq;
  454. if (t1isa_probe(&isa_dev[i], data->cardnr) == 0)
  455. return 0;
  456. }
  457. return -ENODEV;
  458. }
  459. static struct capi_driver capi_driver_t1isa = {
  460. .name = "t1isa",
  461. .revision = "1.0",
  462. .add_card = t1isa_add_card,
  463. };
  464. static int __init t1isa_init(void)
  465. {
  466. char rev[32];
  467. char *p;
  468. int i;
  469. if ((p = strchr(revision, ':')) != 0 && p[1]) {
  470. strlcpy(rev, p + 2, 32);
  471. if ((p = strchr(rev, '$')) != 0 && p > rev)
  472. *(p-1) = 0;
  473. } else
  474. strcpy(rev, "1.0");
  475. for (i = 0; i < MAX_CARDS; i++) {
  476. if (!io[i])
  477. break;
  478. isa_dev[i].resource[0].start = io[i];
  479. isa_dev[i].irq = irq[i];
  480. if (t1isa_probe(&isa_dev[i], cardnr[i]) != 0)
  481. return -ENODEV;
  482. }
  483. strlcpy(capi_driver_t1isa.revision, rev, 32);
  484. register_capi_driver(&capi_driver_t1isa);
  485. printk(KERN_INFO "t1isa: revision %s\n", rev);
  486. return 0;
  487. }
  488. static void __exit t1isa_exit(void)
  489. {
  490. int i;
  491. for (i = 0; i < MAX_CARDS; i++) {
  492. if (!io[i])
  493. break;
  494. t1isa_remove(&isa_dev[i]);
  495. }
  496. }
  497. module_init(t1isa_init);
  498. module_exit(t1isa_exit);