eicon_isa.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:12k
- /* $Id: eicon_isa.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
- *
- * ISDN low-level module for Eicon active ISDN-Cards.
- * Hardware-specific code for old ISA cards.
- *
- * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
- * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
- #include <linux/config.h>
- #include "eicon.h"
- #include "eicon_isa.h"
- #define check_shmem check_region
- #define release_shmem release_region
- #define request_shmem request_region
- char *eicon_isa_revision = "$Revision: 1.1.4.1 $";
- #undef EICON_MCA_DEBUG
- #ifdef CONFIG_ISDN_DRV_EICON_ISA
- /* Mask for detecting invalid IRQ parameter */
- static int eicon_isa_valid_irq[] = {
- 0x1c1c, /* 2, 3, 4, 10, 11, 12 (S)*/
- 0x1c1c, /* 2, 3, 4, 10, 11, 12 (SX) */
- 0x1cbc, /* 2, 3, 4, 5, 7, 10, 11, 12 (SCOM) */
- 0x1cbc, /* 2, 3, 4, 5, 6, 10, 11, 12 (Quadro) */
- 0x1cbc /* 2, 3, 4, 5, 7, 10, 11, 12 (S2M) */
- };
- static void
- eicon_isa_release_shmem(eicon_isa_card *card) {
- if (card->mvalid) {
- iounmap(card->shmem);
- release_mem_region(card->physmem, card->ramsize);
- }
- card->mvalid = 0;
- }
- static void
- eicon_isa_release_irq(eicon_isa_card *card) {
- if (!card->master)
- return;
- if (card->ivalid)
- free_irq(card->irq, card);
- card->ivalid = 0;
- }
- void
- eicon_isa_release(eicon_isa_card *card) {
- eicon_isa_release_irq(card);
- eicon_isa_release_shmem(card);
- }
- void
- eicon_isa_printpar(eicon_isa_card *card) {
- switch (card->type) {
- case EICON_CTYPE_S:
- case EICON_CTYPE_SX:
- case EICON_CTYPE_SCOM:
- case EICON_CTYPE_QUADRO:
- case EICON_CTYPE_S2M:
- printk(KERN_INFO "Eicon %s at 0x%lx, irq %d.n",
- eicon_ctype_name[card->type],
- card->physmem,
- card->irq);
- }
- }
- int
- eicon_isa_find_card(int Mem, int Irq, char * Id)
- {
- int primary = 1;
- unsigned long amem;
- if (!strlen(Id))
- return -1;
- if (Mem == -1)
- return -1;
- /* Check for valid membase address */
- if ((Mem < 0x0c0000) ||
- (Mem > 0x0fc000) ||
- (Mem & 0xfff)) {
- printk(KERN_WARNING "eicon_isa: illegal membase 0x%x for %sn",
- Mem, Id);
- return -1;
- }
- if (check_mem_region(Mem, RAMSIZE)) {
- printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.n", Mem);
- return -1;
- }
- amem = (unsigned long) ioremap(Mem, RAMSIZE);
- writew(0x55aa, amem + 0x402);
- if (readw(amem + 0x402) != 0x55aa) primary = 0;
- writew(0, amem + 0x402);
- if (readw(amem + 0x402) != 0) primary = 0;
- printk(KERN_INFO "Eicon: Driver-ID: %sn", Id);
- if (primary) {
- printk(KERN_INFO "Eicon: assuming pri card at 0x%xn", Mem);
- writeb(0, amem + 0x3ffe);
- iounmap((unsigned char *)amem);
- return EICON_CTYPE_ISAPRI;
- } else {
- printk(KERN_INFO "Eicon: assuming bri card at 0x%xn", Mem);
- writeb(0, amem + 0x400);
- iounmap((unsigned char *)amem);
- return EICON_CTYPE_ISABRI;
- }
- return -1;
- }
- int
- eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
- int tmp;
- int timeout;
- eicon_isa_codebuf cbuf;
- unsigned char *code;
- eicon_isa_boot *boot;
- if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))
- return -EFAULT;
- /* Allocate code-buffer and copy code from userspace */
- if (cbuf.bootstrap_len > 1024) {
- printk(KERN_WARNING "eicon_isa_boot: Invalid startup-code size %ldn",
- cbuf.bootstrap_len);
- return -EINVAL;
- }
- if (!(code = kmalloc(cbuf.bootstrap_len, GFP_KERNEL))) {
- printk(KERN_WARNING "eicon_isa_boot: Couldn't allocate code buffern");
- return -ENOMEM;
- }
- if (copy_from_user(code, &cb->code, cbuf.bootstrap_len)) {
- kfree(code);
- return -EFAULT;
- }
- if (card->type == EICON_CTYPE_ISAPRI)
- card->ramsize = RAMSIZE_P;
- else
- card->ramsize = RAMSIZE;
- if (check_mem_region(card->physmem, card->ramsize)) {
- printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.n",
- card->physmem);
- kfree(code);
- return -EBUSY;
- }
- request_mem_region(card->physmem, card->ramsize, "Eicon ISA ISDN");
- card->shmem = (eicon_isa_shmem *) ioremap(card->physmem, card->ramsize);
- #ifdef EICON_MCA_DEBUG
- printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.n", card->ramsize);
- #endif
- card->mvalid = 1;
- switch(card->type) {
- case EICON_CTYPE_S:
- case EICON_CTYPE_SX:
- case EICON_CTYPE_SCOM:
- case EICON_CTYPE_QUADRO:
- case EICON_CTYPE_ISABRI:
- card->intack = (__u8 *)card->shmem + INTACK;
- card->startcpu = (__u8 *)card->shmem + STARTCPU;
- card->stopcpu = (__u8 *)card->shmem + STOPCPU;
- break;
- case EICON_CTYPE_S2M:
- case EICON_CTYPE_ISAPRI:
- card->intack = (__u8 *)card->shmem + INTACK_P;
- card->startcpu = (__u8 *)card->shmem + STARTCPU_P;
- card->stopcpu = (__u8 *)card->shmem + STOPCPU_P;
- break;
- default:
- printk(KERN_WARNING "eicon_isa_boot: Invalid card type %dn", card->type);
- eicon_isa_release_shmem(card);
- kfree(code);
- return -EINVAL;
- }
- /* clear any pending irq's */
- readb(card->intack);
- #ifdef CONFIG_MCA
- if (MCA_bus) {
- if (card->type == EICON_CTYPE_SCOM) {
- outb_p(0,card->io+1);
- }
- else {
- printk(KERN_WARNING "eicon_isa_boot: Card type not supported yet.n");
- eicon_isa_release_shmem(card);
- return -EINVAL;
- };
- #ifdef EICON_MCA_DEBUG
- printk(KERN_INFO "eicon_isa_boot: card->io = %x.n", card->io);
- printk(KERN_INFO "eicon_isa_boot: card->irq = %d.n", (int)card->irq);
- #endif
- }
- #else
- /* set reset-line active */
- writeb(0, card->stopcpu);
- #endif /* CONFIG_MCA */
- /* clear irq-requests */
- writeb(0, card->intack);
- readb(card->intack);
- /* Copy code into card */
- memcpy_toio(&card->shmem->c, code, cbuf.bootstrap_len);
- /* Check for properly loaded code */
- if (!check_signature((unsigned long)&card->shmem->c, code, 1020)) {
- printk(KERN_WARNING "eicon_isa_boot: Could not load startup-coden");
- eicon_isa_release_shmem(card);
- kfree(code);
- return -EIO;
- }
- /* if 16k-ramsize, duplicate the reset-jump-code */
- if (card->ramsize == RAMSIZE_P)
- memcpy_toio((__u8 *)card->shmem + 0x3ff0, &code[0x3f0], 12);
- kfree(code);
- boot = &card->shmem->boot;
- /* Delay 0.2 sec. */
- SLEEP(HZ / 5);
- /* Start CPU */
- writeb(cbuf.boot_opt, &boot->ctrl);
- #ifdef CONFIG_MCA
- if (MCA_bus) {
- outb_p(0, card->io);
- }
- #else
- writeb(0, card->startcpu);
- #endif /* CONFIG_MCA */
- /* Delay 0.2 sec. */
- SLEEP(HZ / 5);
- timeout = jiffies + (HZ * 22);
- while (time_before(jiffies, timeout)) {
- if (readb(&boot->ctrl) == 0)
- break;
- SLEEP(10);
- }
- if (readb(&boot->ctrl) != 0) {
- printk(KERN_WARNING "eicon_isa_boot: CPU test failed.n");
- #ifdef EICON_MCA_DEBUG
- printk(KERN_INFO "eicon_isa_boot: &boot->ctrl = %d.n",
- readb(&boot->ctrl));
- #endif
- eicon_isa_release_shmem(card);
- return -EIO;
- }
- /* Check for memory-test errors */
- if (readw(&boot->ebit)) {
- printk(KERN_WARNING "eicon_isa_boot: memory test failed (bit 0x%04x at 0x%08x)n",
- readw(&boot->ebit), readl(&boot->eloc));
- eicon_isa_release_shmem(card);
- return -EIO;
- }
- /* Check card type and memory size */
- tmp = readb(&boot->card);
- if ((tmp < 0) || (tmp > 4)) {
- printk(KERN_WARNING "eicon_isa_boot: Type detect failedn");
- eicon_isa_release_shmem(card);
- return -EIO;
- }
- card->type = tmp;
- ((eicon_card *)card->card)->type = tmp;
- tmp = readb(&boot->msize);
- if (tmp != 8 && tmp != 16 && tmp != 24 &&
- tmp != 32 && tmp != 48 && tmp != 60) {
- printk(KERN_WARNING "eicon_isa_boot: invalid memsizen");
- eicon_isa_release_shmem(card);
- return -EIO;
- }
- printk(KERN_INFO "%s: startup-code loadedn", eicon_ctype_name[card->type]);
- if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {
- tmp = eicon_addcard(card->type, card->physmem, card->irq,
- ((eicon_card *)card->card)->regname, 0);
- printk(KERN_INFO "Eicon: %d adapters addedn", tmp);
- }
- return 0;
- }
- int
- eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) {
- eicon_isa_boot *boot;
- int tmp;
- int timeout;
- int j;
- eicon_isa_codebuf cbuf;
- unsigned char *code;
- unsigned char *p;
- if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))
- return -EFAULT;
- if (!(code = kmalloc(cbuf.firmware_len, GFP_KERNEL))) {
- printk(KERN_WARNING "eicon_isa_load: Couldn't allocate code buffern");
- return -ENOMEM;
- }
- if (copy_from_user(code, &cb->code, cbuf.firmware_len)) {
- kfree(code);
- return -EFAULT;
- }
- boot = &card->shmem->boot;
- if ((!card->ivalid) && card->master) {
- card->irqprobe = 1;
- /* Check for valid IRQ */
- if ((card->irq < 0) || (card->irq > 15) ||
- (!((1 << card->irq) & eicon_isa_valid_irq[card->type & 0x0f]))) {
- printk(KERN_WARNING "eicon_isa_load: illegal irq: %dn", card->irq);
- eicon_isa_release_shmem(card);
- kfree(code);
- return -EINVAL;
- }
- /* Register irq */
- if (!request_irq(card->irq, &eicon_irq, 0, "Eicon ISA ISDN", card))
- card->ivalid = 1;
- else {
- printk(KERN_WARNING "eicon_isa_load: irq %d already in use.n",
- card->irq);
- eicon_isa_release_shmem(card);
- kfree(code);
- return -EBUSY;
- }
- }
- tmp = readb(&boot->msize);
- if (tmp != 8 && tmp != 16 && tmp != 24 &&
- tmp != 32 && tmp != 48 && tmp != 60) {
- printk(KERN_WARNING "eicon_isa_load: invalid memsizen");
- eicon_isa_release_shmem(card);
- return -EIO;
- }
- eicon_isa_printpar(card);
- /* Download firmware */
- printk(KERN_INFO "%s %dkB, loading firmware ...n",
- eicon_ctype_name[card->type],
- tmp * 16);
- tmp = cbuf.firmware_len >> 8;
- p = code;
- while (tmp--) {
- memcpy_toio(&boot->b, p, 256);
- writeb(1, &boot->ctrl);
- timeout = jiffies + HZ / 10;
- while (time_before(jiffies, timeout)) {
- if (readb(&boot->ctrl) == 0)
- break;
- SLEEP(2);
- }
- if (readb(&boot->ctrl)) {
- printk(KERN_WARNING "eicon_isa_load: download timeout at 0x%xn", p-code);
- eicon_isa_release(card);
- kfree(code);
- return -EIO;
- }
- p += 256;
- }
- kfree(code);
- /* Initialize firmware parameters */
- memcpy_toio(&card->shmem->c[8], &cbuf.tei, 14);
- memcpy_toio(&card->shmem->c[32], &cbuf.oad, 96);
- memcpy_toio(&card->shmem->c[128], &cbuf.oad, 96);
-
- /* Start firmware, wait for signature */
- writeb(2, &boot->ctrl);
- timeout = jiffies + (5*HZ);
- while (time_before(jiffies, timeout)) {
- if (readw(&boot->signature) == 0x4447)
- break;
- SLEEP(2);
- }
- if (readw(&boot->signature) != 0x4447) {
- printk(KERN_WARNING "eicon_isa_load: firmware selftest failed %04xn",
- readw(&boot->signature));
- eicon_isa_release(card);
- return -EIO;
- }
- card->channels = readb(&card->shmem->c[0x3f6]);
- /* clear irq-requests, reset irq-count */
- readb(card->intack);
- writeb(0, card->intack);
- if (card->master) {
- card->irqprobe = 1;
- /* Trigger an interrupt and check if it is delivered */
- tmp = readb(&card->shmem->com.ReadyInt);
- tmp ++;
- writeb(tmp, &card->shmem->com.ReadyInt);
- timeout = jiffies + HZ / 5;
- while (time_before(jiffies, timeout)) {
- if (card->irqprobe > 1)
- break;
- SLEEP(2);
- }
- if (card->irqprobe == 1) {
- printk(KERN_WARNING "eicon_isa_load: IRQ # %d test failedn", card->irq);
- eicon_isa_release(card);
- return -EIO;
- }
- }
- #ifdef EICON_MCA_DEBUG
- printk(KERN_INFO "eicon_isa_load: IRQ # %d test succeeded.n", card->irq);
- #endif
- writeb(card->irq, &card->shmem->com.Int);
- /* initializing some variables */
- ((eicon_card *)card->card)->ReadyInt = 0;
- ((eicon_card *)card->card)->ref_in = 1;
- ((eicon_card *)card->card)->ref_out = 1;
- for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
- for(j=0; j< (card->channels + 1); j++) {
- ((eicon_card *)card->card)->bch[j].e.busy = 0;
- ((eicon_card *)card->card)->bch[j].e.D3Id = 0;
- ((eicon_card *)card->card)->bch[j].e.B2Id = 0;
- ((eicon_card *)card->card)->bch[j].e.ref = 0;
- ((eicon_card *)card->card)->bch[j].e.Req = 0;
- ((eicon_card *)card->card)->bch[j].e.complete = 1;
- ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
- }
- printk(KERN_INFO "Eicon: Supported channels: %dn", card->channels);
- printk(KERN_INFO "%s successfully startedn", eicon_ctype_name[card->type]);
- /* Enable normal IRQ processing */
- card->irqprobe = 0;
- return 0;
- }
- #endif /* CONFIG_ISDN_DRV_EICON_ISA */