⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i82365.c

📁 pcmcia source code
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Pause at least 50 ms */	mdelay(50);    }        if ((val = i365_get(s, I365_IDENT)) & 0x70)	return -1;    switch (val) {    case 0x82:	type = IS_I82365A; break;    case 0x83:	type = IS_I82365B; break;    case 0x84:	type = IS_I82365DF; break;    case 0x88: case 0x89: case 0x8a:	type = IS_IBM; break;    }        /* Check for Vadem VG-468 chips */    outb(0x0e, port);    outb(0x37, port);    i365_bset(s, VG468_MISC, VG468_MISC_VADEMREV);    val = i365_get(s, I365_IDENT);    if (val & I365_IDENT_VADEM) {	i365_bclr(s, VG468_MISC, VG468_MISC_VADEMREV);	type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;    }    /* Check for Ricoh chips */    val = i365_get(s, RF5C_CHIP_ID);    if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))	type = IS_RF5Cx96;        /* Check for Cirrus CL-PD67xx chips */    i365_set(s, PD67_CHIP_INFO, 0);    val = i365_get(s, PD67_CHIP_INFO);    if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {	val = i365_get(s, PD67_CHIP_INFO);	if ((val & PD67_INFO_CHIP_ID) == 0) {	    type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;	    i365_set(s, PD67_EXT_INDEX, 0xe5);	    if (i365_get(s, PD67_EXT_INDEX) != 0xe5)		type = IS_VT83C469;	}    }    return type;} /* isa_identify */#endif/*======================================================================    See if a card is present, powered up, in IO mode, and already    bound to a (non PC Card) Linux driver.  We leave these alone.    We make an exception for cards that seem to be serial devices.    ======================================================================*/static int __init is_alive(socket_info_t *s){    u_char stat;    u_short start, stop;        stat = i365_get(s, I365_STATUS);    start = i365_get_pair(s, I365_IO(0)+I365_W_START);    stop = i365_get_pair(s, I365_IO(0)+I365_W_STOP);    if ((stop - start < 0x40) && (stop - start >= 0x07) &&	((start & 0xfeef) != 0x02e8) && (start >= 0x100) &&	(stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&	(i365_get(s, I365_INTCTL) & I365_PC_IOCARD) &&	(i365_get(s, I365_ADDRWIN) & I365_ENA_IO(0)) &&	(check_region(start, stop-start+1) != 0))	return 1;    else	return 0;}/*====================================================================*/static void __init add_socket(u_short port, int psock, int type){    socket_info_t *s = socket+sockets;    s->ioaddr = port;    s->psock = psock;    s->type = type;    s->flags = pcic[type].flags;    if (is_alive(s))	s->flags |= IS_ALIVE;    sockets++;}static void __init add_pcic(int ns, int type){    u_int mask = 0, i;    int use_pci = 0, isa_irq = 0;    socket_info_t *s = &socket[sockets-ns];    if (s->ioaddr > 0) request_region(s->ioaddr, 2, "i82365");        printk(KERN_INFO "  %s", pcic[type].name);#ifdef CONFIG_PCI    if (s->flags & IS_UNKNOWN)	printk(" [%04x %04x]", s->vendor, s->device);    printk(" rev %02x", s->revision);    if (s->flags & IS_CARDBUS)	printk(" PCI-to-CardBus at slot %02x:%02x, mem %#08x\n",	       s->bus, PCI_SLOT(s->devfn), s->cb_phys);    else if (s->flags & IS_PCI)	printk(" PCI-to-PCMCIA at slot %02x:%02x, port %#x\n",	       s->bus, PCI_SLOT(s->devfn), s->ioaddr);    else#endif	printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x\n",	       s->ioaddr, s->psock*0x40);#ifdef CONFIG_ISA    if (irq_list[0] == -1)	mask = irq_mask;    else	for (i = mask = 0; i < 16; i++)	    mask |= (1<<irq_list[i]);#endif    /* Set host options, build basic interrupt mask */    mask &= I365_ISA_IRQ_MASK & set_bridge_opts(s, ns);#ifdef CONFIG_PCI    /* Can we use PCI interrupts for card status changes? */    if (pci_csc || pci_int) {	for (i = 0; i < ns; i++)	    if (!s[i].cap.pci_irq || !pci_scan(&s[i])) break;	use_pci = (i == ns);    }#endif#ifdef CONFIG_ISA    /* Scan, report ISA card interrupts */    if (mask)	mask = isa_scan(s, mask);#endif#ifdef CONFIG_PCI    if (!mask)	printk(KERN_INFO "    %s card interrupts,",	       (use_pci && pci_int) ? "PCI" : "*NO*");    if (use_pci && pci_csc)	printk(" PCI status changes\n");#endif#ifdef CONFIG_ISA    /* Poll if only two sensible interrupts available */    if (!(use_pci && pci_csc) && !poll_interval) {	u_int tmp = (mask & 0xff20);	tmp = tmp & (tmp-1);	if ((tmp & (tmp-1)) == 0)	    poll_interval = HZ;    }    /* Only try an ISA cs_irq if this is the first controller */    if (!(use_pci && pci_csc) && !grab_irq &&	(cs_irq || !poll_interval)) {	/* Avoid irq 12 unless it is explicitly requested */	u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));	for (isa_irq = 15; isa_irq > 0; isa_irq--)	    if (cs_mask & (1 << isa_irq)) break;	if (isa_irq) {	    grab_irq = 1;	    cs_irq = isa_irq;	    printk(" status change on irq %d\n", isa_irq);	}    }#endif        if (!(use_pci && pci_csc) && !isa_irq) {	if (poll_interval == 0)	    poll_interval = HZ;	printk(" polling interval = %d ms\n", poll_interval*1000/HZ);    }        /* Update socket interrupt information, capabilities */    for (i = 0; i < ns; i++) {	s[i].cap.features |= SS_CAP_PCCARD;	s[i].cap.map_size = 0x1000;	s[i].cap.irq_mask = mask;	if (!use_pci)	    s[i].cap.pci_irq = 0;	s[i].cs_irq = isa_irq;#ifdef CONFIG_PCI	if (s[i].flags & IS_CARDBUS) {	    s[i].cap.features |= SS_CAP_CARDBUS;	    cb_set_irq_mode(s+i, pci_csc && s[i].cap.pci_irq, 0);	}#endif    }} /* add_pcic *//*====================================================================*/#ifdef CONFIG_PCIstatic int __init pci_lookup(u_int class, struct pci_dev **id,			     u_char *bus, u_char *devfn){    if ((*id = pci_find_class(class<<8, *id)) != NULL) {	*bus = (*id)->bus->number;	*devfn = (*id)->devfn;	return 0;    } else return -1;}static void __init add_pci_bridge(int type, u_short v, u_short d){    socket_info_t *s = &socket[sockets];    u_int addr, ns;    pci_enable_device(pci_find_slot(s->bus, s->devfn));    if (type == PCIC_COUNT) type = IS_UNK_PCI;    pci_readl(s, PCI_BASE_ADDRESS_0, &addr);    addr &= ~0x1;    for (ns = 0; ns < ((type == IS_I82092AA) ? 4 : 2); ns++) {	s[ns].bus = s->bus; s[ns].devfn = s->devfn;	s[ns].vendor = v; s[ns].device = d;	add_socket(addr, ns, type);    }    add_pcic(ns, type);}static int check_cb_mapping(socket_info_t *s){    u_int state = cb_readl(s, CB_SOCKET_STATE) >> 16;    /* A few sanity checks to validate the bridge mapping */    if ((cb_readb(s, 0x800+I365_IDENT) & 0x70) ||	(cb_readb(s, 0x800+I365_CSC) && cb_readb(s, 0x800+I365_CSC) &&	 cb_readb(s, 0x800+I365_CSC)) || cb_readl(s, CB_SOCKET_FORCE) ||	((state & ~0x3000) || !(state & 0x3000)))	return 1;    return 0;}static void __init add_cb_bridge(int type, u_short v, u_short d0){    socket_info_t *s = &socket[sockets];    u_char bus = s->bus, devfn = s->devfn;    u_short d, ns;    u_char a, r, max;        /* PCI bus enumeration is broken on some systems */    for (ns = 0; ns < sockets; ns++)	if ((socket[ns].bus == bus) &&	    (socket[ns].devfn == devfn))	    return;        if (type == PCIC_COUNT) type = IS_UNK_CARDBUS;    pci_readb(s, PCI_HEADER_TYPE, &a);    pci_readb(s, PCI_CLASS_REVISION, &r);    max = (a & 0x80) ? 8 : 1;    for (ns = 0; ns < max; ns++, s++, devfn++) {	s->bus = bus; s->devfn = devfn;	if (pci_readw(s, PCI_DEVICE_ID, &d) || (d != d0))	    break;	s->vendor = v; s->device = d; s->revision = r;	pci_enable_device(pci_find_slot(bus, devfn));	pci_set_power_state(pci_find_slot(bus, devfn), 0);	/* Set up CardBus register mapping */	pci_writel(s, CB_LEGACY_MODE_BASE, 0);	pci_readl(s, PCI_BASE_ADDRESS_0, &s->cb_phys);	if (s->cb_phys == 0) {	    printk("\n" KERN_NOTICE "  Bridge register mapping failed:"		   " check cb_mem_base setting\n");	    break;	}	s->cb_virt = ioremap(s->cb_phys, 0x1000);	if (check_cb_mapping(s) != 0) {	    printk("\n" KERN_NOTICE "  Bad bridge mapping at "		   "0x%08x!\n", s->cb_phys);	    break;	}	request_mem_region(s->cb_phys, 0x1000, "i82365");	add_socket(0, 0, type);    }    if (ns == 0) return;        add_pcic(ns, type);    /* Look up PCI bus bridge structures if needed */    s -= ns;    for (a = 0; a < ns; a++) {	struct pci_dev *self = pci_find_slot(bus, s[a].devfn);#if (LINUX_VERSION_CODE >= VERSION(2,3,40))	s[a].cap.cb_bus = self->subordinate;#else	struct pci_bus *child;	for (child = self->bus->children; child; child = child->next)	    if (child->number == s[a].cap.cardbus) break;	s[a].cap.cb_bus = child;#endif    }}static void __init pci_probe(u_int class){    socket_info_t *s = &socket[sockets];    u_short i, v, d;    struct pci_dev *id;        id = 0;    while (pci_lookup(class, &id, &s->bus, &s->devfn) == 0) {	if (PCI_FUNC(s->devfn) != 0) continue;	pci_readw(s, PCI_VENDOR_ID, &v);	pci_readw(s, PCI_DEVICE_ID, &d);	for (i = 0; i < PCIC_COUNT; i++)	    if ((pcic[i].vendor == v) && (pcic[i].device == d)) break;	/* The "ToPIC95-A" is unusable as a CardBus bridge */	if (i == IS_TOPIC95_A)	    continue;	if (((i < PCIC_COUNT) && (pcic[i].flags & IS_CARDBUS)) ||	    (class == PCI_CLASS_BRIDGE_CARDBUS))	    add_cb_bridge(i, v, d);	else	    add_pci_bridge(i, v, d);	s = &socket[sockets];    }}#endif/*====================================================================*/#ifdef CONFIG_ISAstatic void __init isa_probe(ioaddr_t base){    int i, j, sock, k, ns, id;    ioaddr_t port;    if (check_region(base, 2) != 0) {	if (sockets == 0)	    printk("port conflict at %#x\n", base);	return;    }    id = isa_identify(base, 0);    if ((id == IS_I82365DF) && (isa_identify(base, 1) != id)) {	for (i = 0; i < 4; i++) {	    if (i == ignore) continue;	    port = base + ((i & 1) << 2) + ((i & 2) << 1);	    sock = (i & 1) << 1;	    if (isa_identify(port, sock) == IS_I82365DF) {		add_socket(port, sock, IS_VLSI);		add_pcic(1, IS_VLSI);	    }	}    } else {	for (i = 0; i < 4; i += 2) {	    port = base + 2*(i>>2);	    sock = (i & 3);	    id = isa_identify(port, sock);	    if (id < 0) continue;	    for (j = ns = 0; j < 2; j++) {		/* Does the socket exist? */		if ((ignore == i+j) || (isa_identify(port, sock+j) < 0))		    continue;		/* Check for bad socket decode */		for (k = 0; k <= sockets; k++)		    i365_set(socket+k, I365_MEM(0)+I365_W_OFF, k);		for (k = 0; k <= sockets; k++)		    if (i365_get(socket+k, I365_MEM(0)+I365_W_OFF) != k)			break;		if (k <= sockets) break;		add_socket(port, sock+j, id); ns++;	    }	    if (ns != 0) add_pcic(ns, id);	}    }}#endif/*======================================================================    The card status event handler.  This may either be interrupt    driven or polled.  It monitors mainly for card insert and eject    events; there are various other kinds of events that can be    monitored (ready/busy, status change, etc), but they are almost    never used.    ======================================================================*/static void pcic_interrupt(int irq, void *dev, struct pt_regs *regs){    int i, j, csc;    u_int events, active;#ifdef CONFIG_ISA    u_long flags = 0;#endif        DEBUG(2, "i82365: pcic_interrupt(%d)\n", irq);    for (j = 0; j < 20; j++) {	active = 0;	for (i = 0; i < sockets; i++) {	    socket_info_t *s = &socket[i];	    if ((s->cs_irq != irq) && (s->cap.pci_irq != irq))		continue;	    ISA_LOCK(s, flags);	    csc = i365_get(s, I365_CSC);#ifdef CONFIG_PCI	    if ((s->flags & IS_CARDBUS) &&		(cb_readl(s, CB_SOCKET_EVENT) & CB_SE_CCD)) {		cb_writel(s, CB_SOCKET_EVENT, CB_SE_CCD);		csc |= I365_CSC_DETECT;	    }#endif	    if ((csc == 0) || (!s->handler) ||		(i365_get(s, I365_IDENT) & 0x70)) {		ISA_UNLOCK(s, flags);		continue;	    }	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;	    if (i365_get(s, I365_INTCTL) & I365_PC_IOCARD) {		events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;	    } else {		events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;		events |= (csc & I365_CSC_READY) ? SS_READY : 0;	    }	    ISA_UNLOCK(s, flags);	    DEBUG(1, "i82365: socket %d event 0x%04x\n", i, events);	    if (events)		s->handler(s->info, events);	    active |= events;	}

⌨️ 快捷键说明

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