patch-2.3.23 linux/drivers/pcmcia/i82365.c

Next file: linux/drivers/pcmcia/o2micro.h
Previous file: linux/drivers/pcmcia/cs.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
@@ -3,7 +3,7 @@
     Device driver for Intel 82365 and compatible PC Card controllers,
     and Yenta-compatible PCI-to-CardBus controllers.
 
-    i82365.c 1.254 1999/09/15 15:32:19
+    i82365.c 1.260 1999/10/21 00:56:07
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -76,7 +76,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static const char *version =
-"i82365.c 1.254 1999/09/15 15:32:19 (David Hinds)";
+"i82365.c 1.260 1999/10/21 00:56:07 (David Hinds)";
 #else
 #define DEBUG(n, args...) do { } while (0)
 #endif
@@ -189,7 +189,7 @@
 #ifdef CONFIG_ISA
 #ifdef CONFIG_PCI
 /* PCI card status change interrupts? */
-static int pci_csc = 0;
+static int pci_csc = 1;
 /* PCI IO card functional interrupts? */
 static int pci_int = 0;
 MODULE_PARM(pci_csc, "i");
@@ -240,7 +240,7 @@
 typedef struct socket_info_t {
     u_short		type, flags;
     socket_cap_t	cap;
-    u_short		ioaddr;
+    ioaddr_t		ioaddr;
     u_short		psock;
     u_char		cs_irq, intr;
     void		(*handler)(void *info, u_int events);
@@ -278,18 +278,18 @@
 /* Default ISA interrupt mask */
 #define I365_MASK	0xdeb8	/* irq 15,14,12,11,10,9,7,5,4,3 */
 
-static void pcic_interrupt_wrapper(u_long);
-static void pcic_interrupt(int irq, void *dev,
-				    struct pt_regs *regs);
-static int pcic_service(u_int sock, u_int cmd, void *arg);
-#ifdef CONFIG_PROC_FS
-static void pcic_proc_remove(u_short sock);
-#endif
-
 #ifdef CONFIG_ISA
 static int grab_irq;
 static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED;
+#define ISA_LOCK(n, f) \
+    if (!(socket[n].flags & IS_CARDBUS)) spin_lock_irqsave(&isa_lock, f)
+#define ISA_UNLOCK(n, f) \
+    if (!(socket[n].flags & IS_CARDBUS)) spin_unlock_irqrestore(&isa_lock, f)
+#else
+#define ISA_LOCK(n, f) do { } while (0)
+#define ISA_UNLOCK(n, f) do { } while (0)
 #endif
+
 static struct timer_list poll_timer;
 
 /*====================================================================*/
@@ -322,7 +322,7 @@
 #ifdef CONFIG_PCI
     IS_PD6729, IS_PD6730, IS_OZ6729, IS_OZ6730,
     IS_I82092AA, IS_OM82C092G,
-    IS_PD6832, IS_OZ6832, IS_OZ6836,
+    IS_PD6832, IS_OZ6832, IS_OZ6836, IS_OZ6812,
     IS_RL5C465, IS_RL5C466, IS_RL5C475, IS_RL5C476, IS_RL5C478,
     IS_SMC34C90,
     IS_TI1130, IS_TI1131, IS_TI1250A, IS_TI1220, IS_TI1221, IS_TI1210,
@@ -388,6 +388,8 @@
       PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6832 },
     { "O2Micro OZ6836/OZ6860", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
       PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6836 },
+    { "O2Micro OZ6812", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6812 },
     { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
       PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465 },
     { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
@@ -441,8 +443,6 @@
 
 /* Some PCI shortcuts */
 
-#ifdef CONFIG_PCI
-
 #define pci_readb		pcibios_read_config_byte
 #define pci_writeb		pcibios_write_config_byte
 #define pci_readw		pcibios_read_config_word
@@ -457,7 +457,6 @@
 
 static void cb_get_power(u_short sock, socket_state_t *state);
 static void cb_set_power(u_short sock, socket_state_t *state);
-#endif
 
 /*====================================================================*/
 
@@ -469,7 +468,7 @@
     else
 #endif
     {
-	u_short port = socket[sock].ioaddr;
+	ioaddr_t port = socket[sock].ioaddr;
 	u_char val;
 	reg = I365_REG(socket[sock].psock, reg);
 	outb(reg, port); val = inb(port+1);
@@ -485,7 +484,7 @@
     else
 #endif
     {
-	u_short port = socket[sock].ioaddr;
+	ioaddr_t port = socket[sock].ioaddr;
 	u_char val = I365_REG(socket[sock].psock, reg);
 	outb(val, port); outb(data, port+1);
     }
@@ -954,6 +953,8 @@
 	p->mode_e &= ~O2_MODE_E_MHPG_DMA;
 	p->mhpg |= O2_MHPG_CINT_ENA | O2_MHPG_CSC_ENA;
 	p->mhpg &= ~O2_MHPG_CHANNEL;
+	if (t->revision == 0x34)
+	    p->mode_c = 0x20;
     } else {
 	if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000;
     }
@@ -1125,7 +1126,7 @@
     
 ======================================================================*/
 
-static void get_host_state(u_short s)
+static void get_bridge_state(u_short s)
 {
     socket_info_t *t = &socket[s];
     if (t->flags & IS_CIRRUS)
@@ -1148,7 +1149,7 @@
 #endif
 }
 
-static void set_host_state(u_short s)
+static void set_bridge_state(u_short s)
 {
     socket_info_t *t = &socket[s];
 #ifdef CONFIG_PCI
@@ -1178,7 +1179,7 @@
 #endif
 }
 
-static u_int __init set_host_opts(u_short s, u_short ns)
+static u_int __init set_bridge_opts(u_short s, u_short ns)
 {
     u_short i;
     u_int m = 0xffff;
@@ -1190,7 +1191,7 @@
 	    continue;
 	}
 	buf[0] = '\0';
-	get_host_state(i);
+	get_bridge_state(i);
 	if (socket[i].flags & IS_CIRRUS)
 	    m = cirrus_set_opts(i, buf);
 #ifdef CONFIG_ISA
@@ -1209,7 +1210,7 @@
 	if (socket[i].flags & IS_CARDBUS)
 	    cb_set_opts(i, buf+strlen(buf));
 #endif
-	set_host_state(i);
+	set_bridge_state(i);
 	printk(KERN_INFO "    host opts [%d]:%s\n", i,
 	       (*buf) ? buf : " none");
     }
@@ -1255,7 +1256,7 @@
     if (request_irq(irq, irq_count, (pci?SA_SHIRQ:0), "scan", NULL) != 0)
 	return 1;
     irq_hits = 0; irq_sock = sock;
-    current->state = TASK_INTERRUPTIBLE;
+    __set_current_state(TASK_UNINTERRUPTIBLE);
     schedule_timeout(HZ/100);
     if (irq_hits) {
 	free_irq(irq, NULL);
@@ -1310,7 +1311,7 @@
 	(cb_set_irq_mode(sock, 0, 0) == 0))
 #endif
     if (do_scan) {
-	set_host_state(sock);
+	set_bridge_state(sock);
 	i365_set(sock, I365_CSCINT, 0);
 	for (i = 0; i < 16; i++)
 	    if ((mask0 & (1 << i)) && (test_irq(sock, i, 0) == 0))
@@ -1351,7 +1352,7 @@
     u_int i;
 
     cb_set_irq_mode(sock, 1, 0);
-    set_host_state(sock);
+    set_bridge_state(sock);
     i365_set(sock, I365_CSCINT, 0);
     /* Only probe irq's 9..11, to be conservative */
     for (i = 9; i < 12; i++) {
@@ -1371,7 +1372,7 @@
 static int to_cycles(int ns)
 {
     return ns/cycle_time;
-} /* speed_convert */
+}
 
 static int to_ns(int cycles)
 {
@@ -1517,7 +1518,7 @@
 	for (i = mask = 0; i < 16; i++)
 	    mask |= (1<<irq_list[i]);
 #endif
-    mask &= I365_MASK & set_host_opts(base, ns);
+    mask &= I365_MASK & set_bridge_opts(base, ns);
 #ifdef CONFIG_ISA
     /* Scan for ISA interrupts */
     mask = isa_scan(base, mask);
@@ -1672,8 +1673,7 @@
 		s->cb_virt = ioremap(s->cb_phys, 0x1000);
 		pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, s->cb_phys);
 		/* Simple sanity checks */
-		if (((readb(s->cb_virt+0x800+I365_IDENT) & 0xf0)
-		     == 0x80) &&
+		if (!(readb(s->cb_virt+0x800+I365_IDENT) & 0x70) &&
 		    !(readb(s->cb_virt+0x800+I365_CSC) &&
 		      readb(s->cb_virt+0x800+I365_CSC) &&
 		      readb(s->cb_virt+0x800+I365_CSC)))
@@ -1712,7 +1712,7 @@
 
     /* Re-do card type & voltage detection */
     cb_writel(sockets-ns, CB_SOCKET_FORCE, CB_SF_CVSTEST);
-    current->state = TASK_INTERRUPTIBLE;
+    __set_current_state(TASK_UNINTERRUPTIBLE);
     schedule_timeout(HZ/5);
 
     /* Set up PCI bus bridge structures if needed */
@@ -1762,9 +1762,8 @@
 
 static void __init isa_probe(void)
 {
-    int i, j, sock, k;
-    int ns, id;
-    u_short port;
+    int i, j, sock, k, ns, id;
+    ioaddr_t port;
 
     if (check_region(i365_base, 2) != 0) {
 	if (sockets == 0)
@@ -1812,115 +1811,6 @@
 
 /*====================================================================*/
 
-static int __init init_i82365(void)
-{
-    servinfo_t serv;
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "i82365: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    DEBUG(0, "%s\n", version);
-    printk(KERN_INFO "Intel PCIC probe: ");
-    sockets = 0;
-
-#ifdef CONFIG_PCI
-    if (do_pci_probe && pcibios_present()) {
-	pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge);
-	pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge);
-    }
-#endif
-
-#ifdef CONFIG_ISA
-    isa_probe();
-#endif
-
-    if (sockets == 0) {
-	printk("not found.\n");
-	return -ENODEV;
-    }
-
-    /* Set up interrupt handler(s) */
-#ifdef CONFIG_ISA
-    if (grab_irq != 0)
-	request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL);
-#endif
-#ifdef CONFIG_PCI
-    if (pci_csc) {
-	u_int i, irq, mask = 0;
-	for (i = 0; i < sockets; i++) {
-	    irq = socket[i].cap.pci_irq;
-	    if (irq && !(mask & (1<<irq)))
-		request_irq(irq, pcic_interrupt, SA_SHIRQ, "i82365", NULL);
-	    mask |= (1<<irq);
-	}
-    }
-#endif
-    
-    if (register_ss_entry(sockets, &pcic_service) != 0)
-	printk(KERN_NOTICE "i82365: register_ss_entry() failed\n");
-
-    /* Finally, schedule a polling interrupt */
-    if (poll_interval != 0) {
-	poll_timer.function = pcic_interrupt_wrapper;
-	poll_timer.data = 0;
-	poll_timer.prev = poll_timer.next = NULL;
-    	poll_timer.expires = jiffies + poll_interval;
-	add_timer(&poll_timer);
-    }
-    
-    return 0;
-    
-} /* init_i82365 */
-  
-/*====================================================================*/
-
-static void __exit exit_i82365(void)
-{
-    int i;
-#ifdef CONFIG_PROC_FS
-    for (i = 0; i < sockets; i++) pcic_proc_remove(i);
-#endif
-    unregister_ss_entry(&pcic_service);
-    if (poll_interval != 0)
-	del_timer(&poll_timer);
-#ifdef CONFIG_ISA
-    if (grab_irq != 0)
-	free_irq(cs_irq, NULL);
-#endif
-#ifdef CONFIG_PCI
-    if (pci_csc) {
-	u_int irq, mask = 0;
-	for (i = 0; i < sockets; i++) {
-	    irq = socket[i].cap.pci_irq;
-	    if (irq && !(mask & (1<<irq)))
-		free_irq(irq, NULL);
-	    mask |= (1<<irq);
-	}
-    }
-#endif
-    for (i = 0; i < sockets; i++) {
-	i365_set(i, I365_CSCINT, 0);
-#ifdef CONFIG_PCI
-	if (socket[i].cb_virt) {
-	    iounmap(socket[i].cb_virt);
-	    release_mem_region(socket[i].cb_phys, 0x1000);
-	} else
-#endif
-	    release_region(socket[i].ioaddr, 2);
-    }
-} /* exit_i82365 */
-
-/*====================================================================*/
-
-static void pcic_interrupt_wrapper(u_long data)
-{
-    pcic_interrupt(0, NULL, NULL);
-    poll_timer.expires = jiffies + poll_interval;
-    add_timer(&poll_timer);
-}
-
 static void pcic_interrupt(int irq, void *dev,
 				    struct pt_regs *regs)
 {
@@ -1938,17 +1828,18 @@
 	    if ((socket[i].cs_irq != irq) &&
 		(socket[i].cap.pci_irq != irq))
 		continue;
-#ifdef CONFIG_ISA
-	    if (!(socket[i].flags & IS_CARDBUS))
-		spin_lock_irqsave(&isa_lock, flags);
-#endif
+	    ISA_LOCK(i, flags);
 	    csc = i365_get(i, I365_CSC);
+#ifdef CONFIG_PCI
+	    if ((socket[i].flags & IS_CARDBUS) &&
+		(cb_readl(i,CB_SOCKET_EVENT) & (CB_SE_CCD1|CB_SE_CCD2))) {
+		cb_writel(i, CB_SOCKET_EVENT, CB_SE_CCD1|CB_SE_CCD2);
+		csc |= I365_CSC_DETECT;
+	    }
+#endif
 	    if ((csc == 0) || (!socket[i].handler) ||
 		(i365_get(i, I365_IDENT) & 0x70)) {
-#ifdef CONFIG_ISA
-		if (!(socket[i].flags & IS_CARDBUS))
-		    spin_unlock_irqrestore(&isa_lock, flags);
-#endif
+		ISA_UNLOCK(i, flags);
 		continue;
 	    }
 	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
@@ -1959,10 +1850,7 @@
 		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
 		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
 	    }
-#ifdef CONFIG_ISA
-	    if (!(socket[i].flags & IS_CARDBUS))
-		spin_unlock_irqrestore(&isa_lock, flags);
-#endif
+	    ISA_UNLOCK(i, flags);
 	    DEBUG(2, "i82365: socket %d event 0x%02x\n", i, events);
 	    if (events)
 		socket[i].handler(socket[i].info, events);
@@ -1976,6 +1864,13 @@
     DEBUG(4, "i82365: interrupt done\n");
 } /* pcic_interrupt */
 
+static void pcic_interrupt_wrapper(u_long data)
+{
+    pcic_interrupt(0, NULL, NULL);
+    poll_timer.expires = jiffies + poll_interval;
+    add_timer(&poll_timer);
+}
+
 /*====================================================================*/
 
 static int pcic_register_callback(u_short sock, ss_callback_t *call)
@@ -2149,7 +2044,7 @@
 			(t->cap.pci_irq == state->io_irq));
     t->bcr &= ~CB_BCR_CB_RESET;
 #endif
-    set_host_state(sock);
+    set_bridge_state(sock);
     
     /* IO card, RESET flag, IO interrupt */
     reg = t->intr;
@@ -2250,6 +2145,13 @@
     }
     i365_set(sock, I365_CSCINT, reg);
     i365_get(sock, I365_CSC);
+#ifdef CONFIG_PCI
+    if (t->flags & IS_CARDBUS) {
+	if (t->cs_irq || (pci_csc && t->cap.pci_irq))
+	    cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD);
+	cb_writel(sock, CB_SOCKET_EVENT, -1);
+    }
+#endif
     
     return 0;
 } /* i365_set_socket */
@@ -2428,7 +2330,7 @@
     case CB_SC_VCC_3V:		state->Vcc = 33; break;
     case CB_SC_VCC_5V:		state->Vcc = 50; break;
     }
-    switch (reg & CB_SC_VCC_MASK) {
+    switch (reg & CB_SC_VPP_MASK) {
     case CB_SC_VPP_3V:		state->Vpp = 33; break;
     case CB_SC_VPP_5V:		state->Vpp = 50; break;
     case CB_SC_VPP_12V:		state->Vpp = 120; break;
@@ -2509,12 +2411,12 @@
 			(s->cap.pci_irq == state->io_irq));
     s->bcr &= ~CB_BCR_CB_RESET;
     s->bcr |= (state->flags & SS_RESET) ? CB_BCR_CB_RESET : 0;
-    set_host_state(sock);
+    set_bridge_state(sock);
     
     cb_set_power(sock, state);
     
     /* Handle IO interrupt using ISA routing */
-    reg = i365_get(sock, I365_INTCTL) & ~I365_IRQ_MASK;
+    reg = s->intr;
     if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq;
     i365_set(sock, I365_INTCTL, reg);
     
@@ -2523,6 +2425,9 @@
     if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
     i365_set(sock, I365_CSCINT, reg);
     i365_get(sock, I365_CSC);
+    if (s->cs_irq || (pci_csc && s->cap.pci_irq))
+	cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD);
+    cb_writel(sock, CB_SOCKET_EVENT, -1);
     
     return 0;
 } /* cb_set_socket */
@@ -2623,9 +2528,8 @@
     
 #ifdef CONFIG_ISA
     u_long flags = 0;
-    if (!(socket[sock].flags & IS_CARDBUS))
-	spin_lock_irqsave(&isa_lock, flags);
 #endif
+    ISA_LOCK(sock, flags);
     top = 0x40;
     if (socket[sock].flags & IS_CARDBUS)
 	top = (socket[sock].flags & IS_CIRRUS) ? 0x140 : 0x50;
@@ -2639,10 +2543,7 @@
 		     i365_get(sock,i+2), i365_get(sock,i+3),
 		     ((i % 16) == 12) ? "\n" : " ");
     }
-#ifdef CONFIG_ISA
-    if (!(socket[sock].flags & IS_CARDBUS))
-	spin_unlock_irqrestore(&isa_lock, flags);
-#endif
+    ISA_UNLOCK(sock, flags);
     return (p - buf);
 }
 
@@ -2672,13 +2573,15 @@
 			     int count, int *eof, void *data)
 {
     u_short sock = (socket_info_t *)data - socket;
-    int len;
-    
-    len = sprintf(buf, "%08x %08x %08x %08x %08x %08x\n",
-		  cb_readl(sock,0), cb_readl(sock,4),
-		  cb_readl(sock,8), cb_readl(sock,12),
-		  cb_readl(sock,16), cb_readl(sock,32));
-    return len;
+    char *p = buf;
+    int i, top;
+
+    top = (socket[sock].flags & IS_O2MICRO) ? 0x30 : 0x20;
+    for (i = 0; i < top; i += 0x10)
+	p += sprintf(p, "%08x %08x %08x %08x\n",
+		     cb_readl(sock,i+0x00), cb_readl(sock,i+0x04),
+		     cb_readl(sock,i+0x08), cb_readl(sock,i+0x0c));
+    return (p - buf);
 }
 #endif
 
@@ -2757,7 +2660,11 @@
 static int pcic_service(u_int sock, u_int cmd, void *arg)
 {
     subfn_t fn;
-
+    int ret;
+#ifdef CONFIG_ISA
+    u_long flags = 0;
+#endif
+    
     DEBUG(2, "pcic_ioctl(%d, %d, 0x%p)\n", sock, cmd, arg);
 
     if (cmd >= NFUNC)
@@ -2782,20 +2689,114 @@
     }
 #endif
 
+    ISA_LOCK(sock, flags);
+    ret = (fn == NULL) ? -EINVAL : fn(sock, arg);
+    ISA_UNLOCK(sock, flags);
+    return ret;
+} /* pcic_service */
+
+/*====================================================================*/
+
+static int __init init_i82365(void)
+{
+    servinfo_t serv;
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "i82365: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    DEBUG(0, "%s\n", version);
+    printk(KERN_INFO "Intel PCIC probe: ");
+    sockets = 0;
+
+#ifdef CONFIG_PCI
+    if (do_pci_probe && pcibios_present()) {
+	pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge);
+	pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge);
+    }
+#endif
+
 #ifdef CONFIG_ISA
-    if (!(socket[sock].flags & IS_CARDBUS)) {
-	int ret;
-	u_long flags;
-	spin_lock_irqsave(&isa_lock, flags);
-	ret = (fn == NULL) ? -EINVAL : fn(sock, arg);
-	spin_unlock_irqrestore(&isa_lock, flags);
-	return ret;
+    isa_probe();
+#endif
+
+    if (sockets == 0) {
+	printk("not found.\n");
+	return -ENODEV;
     }
+
+    /* Set up interrupt handler(s) */
+#ifdef CONFIG_ISA
+    if (grab_irq != 0)
+	request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL);
 #endif
-    return (fn == NULL) ? -EINVAL : fn(sock, arg);
-} /* pcic_service */
+#ifdef CONFIG_PCI
+    if (pci_csc) {
+	u_int i, irq, mask = 0;
+	for (i = 0; i < sockets; i++) {
+	    irq = socket[i].cap.pci_irq;
+	    if (irq && !(mask & (1<<irq)))
+		request_irq(irq, pcic_interrupt, SA_SHIRQ, "i82365", NULL);
+	    mask |= (1<<irq);
+	}
+    }
+#endif
+    
+    if (register_ss_entry(sockets, &pcic_service) != 0)
+	printk(KERN_NOTICE "i82365: register_ss_entry() failed\n");
 
-/*====================================================================*/
+    /* Finally, schedule a polling interrupt */
+    if (poll_interval != 0) {
+	poll_timer.function = pcic_interrupt_wrapper;
+	poll_timer.data = 0;
+	poll_timer.prev = poll_timer.next = NULL;
+    	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+    }
+    
+    return 0;
+    
+} /* init_i82365 */
+
+static void __exit exit_i82365(void)
+{
+    int i;
+#ifdef CONFIG_PROC_FS
+    for (i = 0; i < sockets; i++) pcic_proc_remove(i);
+#endif
+    unregister_ss_entry(&pcic_service);
+    if (poll_interval != 0)
+	del_timer(&poll_timer);
+#ifdef CONFIG_ISA
+    if (grab_irq != 0)
+	free_irq(cs_irq, NULL);
+#endif
+#ifdef CONFIG_PCI
+    if (pci_csc) {
+	u_int irq, mask = 0;
+	for (i = 0; i < sockets; i++) {
+	    irq = socket[i].cap.pci_irq;
+	    if (irq && !(mask & (1<<irq)))
+		free_irq(irq, NULL);
+	    mask |= (1<<irq);
+	}
+    }
+#endif
+    for (i = 0; i < sockets; i++) {
+	/* Turn off all interrupt sources! */
+	i365_set(i, I365_CSCINT, 0);
+#ifdef CONFIG_PCI
+	if (socket[i].flags & IS_CARDBUS)
+	    cb_writel(i, CB_SOCKET_MASK, 0);
+	if (socket[i].cb_virt) {
+	    iounmap(socket[i].cb_virt);
+	    release_mem_region(socket[i].cb_phys, 0x1000);
+	} else
+#endif
+	    release_region(socket[i].ioaddr, 2);
+    }
+} /* exit_i82365 */
 
 module_init(init_i82365);
 module_exit(exit_i82365);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)