static int __init is_active(int s)
{
    u_short scf1, ioctl, base, num;
    u_char pwr, sstat;
    u_int addr;
    
    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT)
	      | TCIC_ADDR_INDREG | TCIC_SCF1(s));
    scf1 = tcic_getw(TCIC_DATA);
    pwr = tcic_getb(TCIC_PWR);
    sstat = tcic_getb(TCIC_SSTAT);
    addr = TCIC_IWIN(s, 0);
    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
    base = tcic_getw(TCIC_DATA);
    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
    ioctl = tcic_getw(TCIC_DATA);

    if (ioctl & TCIC_ICTL_TINY)
	num = 1;
    else {
	num = (base ^ (base-1));
	base = base & (base-1);
    }

    if ((sstat & TCIC_SSTAT_CD) && (pwr & TCIC_PWR_VCC(s)) &&
	(scf1 & TCIC_SCF1_IOSTS) && (ioctl & TCIC_ICTL_ENA) &&
	((base & 0xfeef) != 0x02e8)) {
	struct resource *res = request_region(base, num, "tcic-2");
	if (!res) /* region is busy */
	    return 1;
	release_region(base, num);
    }

    return 0;
}
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;

    pr_debug("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;
    
    pr_debug("interrupt done\n");
    return IRQ_HANDLED;
} /* tcic_interrupt */
static int __init init_tcic(void)
{
    int i, sock, ret = 0;
    u_int mask, scan;

    if (platform_driver_register(&tcic_driver))
	return -1;
    
    printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: ");
    sock = 0;

    if (!request_region(tcic_base, 16, "tcic-2")) {
	printk("could not allocate ports,\n ");
	platform_driver_unregister(&tcic_driver);
	return -ENODEV;
    }
    else {
	tcic_setw(TCIC_ADDR, 0);
	if (tcic_getw(TCIC_ADDR) == 0) {
	    tcic_setw(TCIC_ADDR, 0xc3a5);
	    if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
	}
	if (sock == 0) {
	    /* See if resetting the controller does any good */
	    tcic_setb(TCIC_SCTRL, TCIC_SCTRL_RESET);
	    tcic_setb(TCIC_SCTRL, 0);
	    tcic_setw(TCIC_ADDR, 0);
	    if (tcic_getw(TCIC_ADDR) == 0) {
		tcic_setw(TCIC_ADDR, 0xc3a5);
		if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
	    }
	}
    }
    if (sock == 0) {
	printk("not found.\n");
	release_region(tcic_base, 16);
	platform_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(KERN_CONT ", %d sockets\n", sockets);
    printk(KERN_INFO "  irq list (");
    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 u_short tcic_aux_getw(u_short reg)
{
    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
    tcic_setb(TCIC_MODE, mode);
    return tcic_getw(TCIC_AUX);
}
Example #5
0
	*value |= SS_POWERON;
    debug(1, "GetStatus(%d) = %#2.2x\n", psock, *value);
    return 0;
} /* tcic_get_status */
  
/*====================================================================*/

static int tcic_get_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;
    
    tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
	      | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
    scf1 = tcic_getw(TCIC_DATA);
    state->flags = (scf1 & TCIC_SCF1_IOSTS) ? SS_IOCARD : 0;
    state->flags |= (scf1 & TCIC_SCF1_DMA_MASK) ? SS_DMA_MODE : 0;
    state->flags |= (scf1 & TCIC_SCF1_SPKR) ? SS_SPKR_ENA : 0;
    if (tcic_getb(TCIC_SCTRL) & TCIC_SCTRL_ENA)
	state->flags |= SS_OUTPUT_ENA;
    state->io_irq = scf1 & TCIC_SCF1_IRQ_MASK;
    if (state->io_irq == 1) state->io_irq = 11;

    reg = tcic_getb(TCIC_PWR);
    state->Vcc = state->Vpp = 0;
    if (reg & TCIC_PWR_VCC(psock)) {
	if (reg & TCIC_PWR_VPP(psock))
	    state->Vcc = 50;
	else
	    state->Vcc = state->Vpp = 50;