tcic.c

来自「linux 内核源代码」· C语言 代码 · 共 827 行 · 第 1/2 页

C
827
字号
	printk("not found.\n");	release_region(tcic_base, 16);	driver_unregister(&tcic_driver);	return -ENODEV;    }    sockets = 0;    for (i = 0; i < sock; i++) {	if ((i == ignore) || is_active(i)) continue;	socket_table[sockets].psock = i;	socket_table[sockets].id = get_tcic_id();	socket_table[sockets].socket.owner = THIS_MODULE;	/* only 16-bit cards, memory windows must be size-aligned */	/* No PCI or CardBus support */	socket_table[sockets].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN;	/* irq 14, 11, 10, 7, 6, 5, 4, 3 */	socket_table[sockets].socket.irq_mask = 0x4cf8;	/* 4K minimum window size */	socket_table[sockets].socket.map_size = 0x1000;			sockets++;    }    switch (socket_table[0].id) {    case TCIC_ID_DB86082:	printk("DB86082"); break;    case TCIC_ID_DB86082A:	printk("DB86082A"); break;    case TCIC_ID_DB86084:	printk("DB86084"); break;    case TCIC_ID_DB86084A:	printk("DB86084A"); break;    case TCIC_ID_DB86072:	printk("DB86072"); break;    case TCIC_ID_DB86184:	printk("DB86184"); break;    case TCIC_ID_DB86082B:	printk("DB86082B"); break;    default:	printk("Unknown ID 0x%02x", socket_table[0].id);    }        /* Set up polling */    poll_timer.function = &tcic_timer;    poll_timer.data = 0;    init_timer(&poll_timer);    /* Build interrupt mask */    printk(", %d sockets\n" KERN_INFO "  irq list (", sockets);    if (irq_list_count == 0)	mask = irq_mask;    else	for (i = mask = 0; i < irq_list_count; i++)	    mask |= (1<<irq_list[i]);    /* irq 14, 11, 10, 7, 6, 5, 4, 3 */    mask &= 0x4cf8;    /* Scan interrupts */    mask = irq_scan(mask);    for (i=0;i<sockets;i++)	    socket_table[i].socket.irq_mask = mask;        /* Check for only two interrupts available */    scan = (mask & (mask-1));    if (((scan & (scan-1)) == 0) && (poll_interval == 0))	poll_interval = HZ;        if (poll_interval == 0) {	/* Avoid irq 12 unless it is explicitly requested */	u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));	for (i = 15; i > 0; i--)	    if ((cs_mask & (1 << i)) &&		(request_irq(i, tcic_interrupt, 0, "tcic",			     tcic_interrupt) == 0))		break;	cs_irq = i;	if (cs_irq == 0) poll_interval = HZ;    }        if (socket_table[0].socket.irq_mask & (1 << 11))	printk("sktirq is irq 11, ");    if (cs_irq != 0)	printk("status change on irq %d\n", cs_irq);    else	printk("polled status, interval = %d ms\n",	       poll_interval * 1000 / HZ);        for (i = 0; i < sockets; i++) {	tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT);	socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT);    }        /* jump start interrupt handler, if needed */    tcic_interrupt(0, NULL);    platform_device_register(&tcic_device);    for (i = 0; i < sockets; i++) {	    socket_table[i].socket.ops = &tcic_operations;	    socket_table[i].socket.resource_ops = &pccard_nonstatic_ops;	    socket_table[i].socket.dev.parent = &tcic_device.dev;	    ret = pcmcia_register_socket(&socket_table[i].socket);	    if (ret && i)		    pcmcia_unregister_socket(&socket_table[0].socket);    }        return ret;    return 0;    } /* init_tcic *//*====================================================================*/static void __exit exit_tcic(void){    int i;    del_timer_sync(&poll_timer);    if (cs_irq != 0) {	tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);	free_irq(cs_irq, tcic_interrupt);    }    release_region(tcic_base, 16);    for (i = 0; i < sockets; i++) {	    pcmcia_unregister_socket(&socket_table[i].socket);	        }    platform_device_unregister(&tcic_device);    driver_unregister(&tcic_driver);} /* exit_tcic *//*====================================================================*/static irqreturn_t tcic_interrupt(int irq, void *dev){    int i, quick = 0;    u_char latch, sstat;    u_short psock;    u_int events;    static volatile int active = 0;    if (active) {	printk(KERN_NOTICE "tcic: reentered interrupt handler!\n");	return IRQ_NONE;    } else	active = 1;    debug(2, "tcic_interrupt()\n");        for (i = 0; i < sockets; i++) {	psock = socket_table[i].psock;	tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)		  | TCIC_ADDR_INDREG | TCIC_SCF1(psock));	sstat = tcic_getb(TCIC_SSTAT);	latch = sstat ^ socket_table[psock].last_sstat;	socket_table[i].last_sstat = sstat;	if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) {	    tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR);	    quick = 1;	}	if (latch == 0)	    continue;	events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0;	events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0;	if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {	    events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;	} else {	    events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0;	    events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;	    events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;	}	if (events) {		pcmcia_parse_events(&socket_table[i].socket, events);	}    }    /* Schedule next poll, if needed */    if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) {	poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval);	add_timer(&poll_timer);	tcic_timer_pending = 1;    }    active = 0;        debug(2, "interrupt done\n");    return IRQ_HANDLED;} /* tcic_interrupt */static void tcic_timer(u_long data){    debug(2, "tcic_timer()\n");    tcic_timer_pending = 0;    tcic_interrupt(0, NULL);} /* tcic_timer *//*====================================================================*/static int tcic_get_status(struct pcmcia_socket *sock, u_int *value){    u_short psock = container_of(sock, struct tcic_socket, socket)->psock;    u_char reg;    tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)	      | TCIC_ADDR_INDREG | TCIC_SCF1(psock));    reg = tcic_getb(TCIC_SSTAT);    *value  = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0;    *value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0;    if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {	*value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;    } else {	*value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0;	*value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;	*value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;    }    reg = tcic_getb(TCIC_PWR);    if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock)))	*value |= SS_POWERON;    debug(1, "GetStatus(%d) = %#2.2x\n", psock, *value);    return 0;} /* tcic_get_status *//*====================================================================*/static int tcic_set_socket(struct pcmcia_socket *sock, socket_state_t *state){    u_short psock = container_of(sock, struct tcic_socket, socket)->psock;    u_char reg;    u_short scf1, scf2;    debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "	  "io_irq %d, csc_mask %#2.2x)\n", psock, state->flags,	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);    tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG);    reg = tcic_getb(TCIC_PWR);    reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock));    if (state->Vcc == 50) {	switch (state->Vpp) {	case 0:   reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break;	case 50:  reg |= TCIC_PWR_VCC(psock); break;	case 120: reg |= TCIC_PWR_VPP(psock); break;	default:  return -EINVAL;	}    } else if (state->Vcc != 0)	return -EINVAL;    if (reg != tcic_getb(TCIC_PWR))	tcic_setb(TCIC_PWR, reg);    reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT;    if (state->flags & SS_OUTPUT_ENA) {	tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA);	reg |= TCIC_ILOCK_CRESENA;    } else	tcic_setb(TCIC_SCTRL, 0);    if (state->flags & SS_RESET)	reg |= TCIC_ILOCK_CRESET;    tcic_aux_setb(TCIC_AUX_ILOCK, reg);        tcic_setw(TCIC_ADDR, TCIC_SCF1(psock));    scf1 = TCIC_SCF1_FINPACK;    scf1 |= TCIC_IRQ(state->io_irq);    if (state->flags & SS_IOCARD) {	scf1 |= TCIC_SCF1_IOSTS;	if (state->flags & SS_SPKR_ENA)	    scf1 |= TCIC_SCF1_SPKR;	if (state->flags & SS_DMA_MODE)	    scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT;    }    tcic_setw(TCIC_DATA, scf1);    /* Some general setup stuff, and configure status interrupt */    reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250);    tcic_aux_setb(TCIC_AUX_WCTL, reg);    tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00|		  TCIC_IRQ(cs_irq));        /* Card status change interrupt mask */    tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));    scf2 = TCIC_SCF2_MALL;    if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD;    if (state->flags & SS_IOCARD) {	if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1;    } else {	if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1;	if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2;	if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY;    }    tcic_setw(TCIC_DATA, scf2);    /* For the ISA bus, the irq should be active-high totem-pole */    tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH);    return 0;} /* tcic_set_socket */  /*====================================================================*/static int tcic_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io){    u_short psock = container_of(sock, struct tcic_socket, socket)->psock;    u_int addr;    u_short base, len, ioctl;        debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "	  "%#lx-%#lx)\n", psock, io->map, io->flags,	  io->speed, io->start, io->stop);    if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||	(io->stop < io->start)) return -EINVAL;    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));    addr = TCIC_IWIN(psock, io->map);    base = io->start; len = io->stop - io->start;    /* Check to see that len+1 is power of two, etc */    if ((len & (len+1)) || (base & len)) return -EINVAL;    base |= (len+1)>>1;    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);    tcic_setw(TCIC_DATA, base);        ioctl  = (psock << TCIC_ICTL_SS_SHFT);    ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0;    ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0;    ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK;    if (!(io->flags & MAP_AUTOSZ)) {	ioctl |= TCIC_ICTL_QUIET;	ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8;    }    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);    tcic_setw(TCIC_DATA, ioctl);        return 0;} /* tcic_set_io_map *//*====================================================================*/static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem){    u_short psock = container_of(sock, struct tcic_socket, socket)->psock;    u_short addr, ctl;    u_long base, len, mmap;    debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, "	  "%#llx-%#llx, %#x)\n", psock, mem->map, mem->flags,	  mem->speed, (unsigned long long)mem->res->start,	  (unsigned long long)mem->res->end, mem->card_start);    if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||	(mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) ||	(mem->res->start > mem->res->end) || (mem->speed > 1000))	return -EINVAL;    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));    addr = TCIC_MWIN(psock, mem->map);    base = mem->res->start; len = mem->res->end - mem->res->start;    if ((len & (len+1)) || (base & len)) return -EINVAL;    if (len == 0x0fff)	base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT;    else	base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT;    tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);    tcic_setw(TCIC_DATA, base);        mmap = mem->card_start - mem->res->start;    mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK;    if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG;    tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);    tcic_setw(TCIC_DATA, mmap);    ctl  = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT);    ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK;    ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8;    ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0;    ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0;    tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);    tcic_setw(TCIC_DATA, ctl);        return 0;} /* tcic_set_mem_map *//*====================================================================*/static int tcic_init(struct pcmcia_socket *s){	int i;	struct resource res = { .start = 0, .end = 0x1000 };	pccard_io_map io = { 0, 0, 0, 0, 1 };	pccard_mem_map mem = { .res = &res, };	for (i = 0; i < 2; i++) {		io.map = i;		tcic_set_io_map(s, &io);	}	for (i = 0; i < 5; i++) {		mem.map = i;		tcic_set_mem_map(s, &mem);	}	return 0;}static struct pccard_operations tcic_operations = {	.init		   = tcic_init,	.get_status	   = tcic_get_status,	.set_socket	   = tcic_set_socket,	.set_io_map	   = tcic_set_io_map,	.set_mem_map	   = tcic_set_mem_map,};/*====================================================================*/module_init(init_tcic);module_exit(exit_tcic);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?