18c2ecf20Sopenharmony_ci/*====================================================================== 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci Device driver for Intel 82365 and compatible PC Card controllers. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci i82365.c 1.265 1999/11/10 18:36:21 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci The contents of this file are subject to the Mozilla Public 88c2ecf20Sopenharmony_ci License Version 1.1 (the "License"); you may not use this file 98c2ecf20Sopenharmony_ci except in compliance with the License. You may obtain a copy of 108c2ecf20Sopenharmony_ci the License at http://www.mozilla.org/MPL/ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci Software distributed under the License is distributed on an "AS 138c2ecf20Sopenharmony_ci IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 148c2ecf20Sopenharmony_ci implied. See the License for the specific language governing 158c2ecf20Sopenharmony_ci rights and limitations under the License. 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci The initial developer of the original code is David A. Hinds 188c2ecf20Sopenharmony_ci <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 198c2ecf20Sopenharmony_ci are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci Alternatively, the contents of this file may be used under the 228c2ecf20Sopenharmony_ci terms of the GNU General Public License version 2 (the "GPL"), in which 238c2ecf20Sopenharmony_ci case the provisions of the GPL are applicable instead of the 248c2ecf20Sopenharmony_ci above. If you wish to allow the use of your version of this file 258c2ecf20Sopenharmony_ci only under the terms of the GPL and not to allow others to use 268c2ecf20Sopenharmony_ci your version of this file under the MPL, indicate your decision 278c2ecf20Sopenharmony_ci by deleting the provisions above and replace them with the notice 288c2ecf20Sopenharmony_ci and other provisions required by the GPL. If you do not delete 298c2ecf20Sopenharmony_ci the provisions above, a recipient may use your version of this 308c2ecf20Sopenharmony_ci file under either the MPL or the GPL. 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci======================================================================*/ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/module.h> 358c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 368c2ecf20Sopenharmony_ci#include <linux/init.h> 378c2ecf20Sopenharmony_ci#include <linux/types.h> 388c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 398c2ecf20Sopenharmony_ci#include <linux/string.h> 408c2ecf20Sopenharmony_ci#include <linux/kernel.h> 418c2ecf20Sopenharmony_ci#include <linux/errno.h> 428c2ecf20Sopenharmony_ci#include <linux/timer.h> 438c2ecf20Sopenharmony_ci#include <linux/ioport.h> 448c2ecf20Sopenharmony_ci#include <linux/delay.h> 458c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 468c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 478c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 488c2ecf20Sopenharmony_ci#include <linux/bitops.h> 498c2ecf20Sopenharmony_ci#include <asm/irq.h> 508c2ecf20Sopenharmony_ci#include <asm/io.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#include <pcmcia/ss.h> 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#include <linux/isapnp.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* ISA-bus controllers */ 578c2ecf20Sopenharmony_ci#include "i82365.h" 588c2ecf20Sopenharmony_ci#include "cirrus.h" 598c2ecf20Sopenharmony_ci#include "vg468.h" 608c2ecf20Sopenharmony_ci#include "ricoh.h" 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic irqreturn_t i365_count_irq(int, void *); 648c2ecf20Sopenharmony_cistatic inline int _check_irq(int irq, int flags) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0) 678c2ecf20Sopenharmony_ci return -1; 688c2ecf20Sopenharmony_ci free_irq(irq, i365_count_irq); 698c2ecf20Sopenharmony_ci return 0; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/*====================================================================*/ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Parameters that can be set with 'insmod' */ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* Default base address for i82365sl and other ISA chips */ 778c2ecf20Sopenharmony_cistatic unsigned long i365_base = 0x3e0; 788c2ecf20Sopenharmony_ci/* Should we probe at 0x3e2 for an extra ISA controller? */ 798c2ecf20Sopenharmony_cistatic int extra_sockets = 0; 808c2ecf20Sopenharmony_ci/* Specify a socket number to ignore */ 818c2ecf20Sopenharmony_cistatic int ignore = -1; 828c2ecf20Sopenharmony_ci/* Bit map or list of interrupts to choose from */ 838c2ecf20Sopenharmony_cistatic u_int irq_mask = 0xffff; 848c2ecf20Sopenharmony_cistatic int irq_list[16]; 858c2ecf20Sopenharmony_cistatic unsigned int irq_list_count; 868c2ecf20Sopenharmony_ci/* The card status change interrupt -- 0 means autoselect */ 878c2ecf20Sopenharmony_cistatic int cs_irq = 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* Probe for safe interrupts? */ 908c2ecf20Sopenharmony_cistatic int do_scan = 1; 918c2ecf20Sopenharmony_ci/* Poll status interval -- 0 means default to interrupt */ 928c2ecf20Sopenharmony_cistatic int poll_interval = 0; 938c2ecf20Sopenharmony_ci/* External clock time, in nanoseconds. 120 ns = 8.33 MHz */ 948c2ecf20Sopenharmony_cistatic int cycle_time = 120; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* Cirrus options */ 978c2ecf20Sopenharmony_cistatic int has_dma = -1; 988c2ecf20Sopenharmony_cistatic int has_led = -1; 998c2ecf20Sopenharmony_cistatic int has_ring = -1; 1008c2ecf20Sopenharmony_cistatic int dynamic_mode = 0; 1018c2ecf20Sopenharmony_cistatic int freq_bypass = -1; 1028c2ecf20Sopenharmony_cistatic int setup_time = -1; 1038c2ecf20Sopenharmony_cistatic int cmd_time = -1; 1048c2ecf20Sopenharmony_cistatic int recov_time = -1; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Vadem options */ 1078c2ecf20Sopenharmony_cistatic int async_clock = -1; 1088c2ecf20Sopenharmony_cistatic int cable_mode = -1; 1098c2ecf20Sopenharmony_cistatic int wakeup = 0; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cimodule_param_hw(i365_base, ulong, ioport, 0444); 1128c2ecf20Sopenharmony_cimodule_param(ignore, int, 0444); 1138c2ecf20Sopenharmony_cimodule_param(extra_sockets, int, 0444); 1148c2ecf20Sopenharmony_cimodule_param_hw(irq_mask, int, other, 0444); 1158c2ecf20Sopenharmony_cimodule_param_hw_array(irq_list, int, irq, &irq_list_count, 0444); 1168c2ecf20Sopenharmony_cimodule_param_hw(cs_irq, int, irq, 0444); 1178c2ecf20Sopenharmony_cimodule_param(async_clock, int, 0444); 1188c2ecf20Sopenharmony_cimodule_param(cable_mode, int, 0444); 1198c2ecf20Sopenharmony_cimodule_param(wakeup, int, 0444); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cimodule_param(do_scan, int, 0444); 1228c2ecf20Sopenharmony_cimodule_param(poll_interval, int, 0444); 1238c2ecf20Sopenharmony_cimodule_param(cycle_time, int, 0444); 1248c2ecf20Sopenharmony_cimodule_param(has_dma, int, 0444); 1258c2ecf20Sopenharmony_cimodule_param(has_led, int, 0444); 1268c2ecf20Sopenharmony_cimodule_param(has_ring, int, 0444); 1278c2ecf20Sopenharmony_cimodule_param(dynamic_mode, int, 0444); 1288c2ecf20Sopenharmony_cimodule_param(freq_bypass, int, 0444); 1298c2ecf20Sopenharmony_cimodule_param(setup_time, int, 0444); 1308c2ecf20Sopenharmony_cimodule_param(cmd_time, int, 0444); 1318c2ecf20Sopenharmony_cimodule_param(recov_time, int, 0444); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/*====================================================================*/ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistruct cirrus_state { 1368c2ecf20Sopenharmony_ci u_char misc1, misc2; 1378c2ecf20Sopenharmony_ci u_char timer[6]; 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistruct vg46x_state { 1418c2ecf20Sopenharmony_ci u_char ctl, ema; 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistruct i82365_socket { 1458c2ecf20Sopenharmony_ci u_short type, flags; 1468c2ecf20Sopenharmony_ci struct pcmcia_socket socket; 1478c2ecf20Sopenharmony_ci unsigned int number; 1488c2ecf20Sopenharmony_ci unsigned int ioaddr; 1498c2ecf20Sopenharmony_ci u_short psock; 1508c2ecf20Sopenharmony_ci u_char cs_irq, intr; 1518c2ecf20Sopenharmony_ci union { 1528c2ecf20Sopenharmony_ci struct cirrus_state cirrus; 1538c2ecf20Sopenharmony_ci struct vg46x_state vg46x; 1548c2ecf20Sopenharmony_ci } state; 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* Where we keep track of our sockets... */ 1588c2ecf20Sopenharmony_cistatic int sockets = 0; 1598c2ecf20Sopenharmony_cistatic struct i82365_socket socket[8] = { 1608c2ecf20Sopenharmony_ci { 0, }, /* ... */ 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/* Default ISA interrupt mask */ 1648c2ecf20Sopenharmony_ci#define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */ 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int grab_irq; 1678c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(isa_lock); 1688c2ecf20Sopenharmony_ci#define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f) 1698c2ecf20Sopenharmony_ci#define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic struct timer_list poll_timer; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/*====================================================================*/ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* These definitions must match the pcic table! */ 1768c2ecf20Sopenharmony_cienum pcic_id { 1778c2ecf20Sopenharmony_ci IS_I82365A, IS_I82365B, IS_I82365DF, 1788c2ecf20Sopenharmony_ci IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469, 1798c2ecf20Sopenharmony_ci IS_PD6710, IS_PD672X, IS_VT83C469, 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* Flags for classifying groups of controllers */ 1838c2ecf20Sopenharmony_ci#define IS_VADEM 0x0001 1848c2ecf20Sopenharmony_ci#define IS_CIRRUS 0x0002 1858c2ecf20Sopenharmony_ci#define IS_VIA 0x0010 1868c2ecf20Sopenharmony_ci#define IS_UNKNOWN 0x0400 1878c2ecf20Sopenharmony_ci#define IS_VG_PWR 0x0800 1888c2ecf20Sopenharmony_ci#define IS_DF_PWR 0x1000 1898c2ecf20Sopenharmony_ci#define IS_REGISTERED 0x2000 1908c2ecf20Sopenharmony_ci#define IS_ALIVE 0x8000 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistruct pcic { 1938c2ecf20Sopenharmony_ci char *name; 1948c2ecf20Sopenharmony_ci u_short flags; 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic struct pcic pcic[] = { 1988c2ecf20Sopenharmony_ci { "Intel i82365sl A step", 0 }, 1998c2ecf20Sopenharmony_ci { "Intel i82365sl B step", 0 }, 2008c2ecf20Sopenharmony_ci { "Intel i82365sl DF", IS_DF_PWR }, 2018c2ecf20Sopenharmony_ci { "IBM Clone", 0 }, 2028c2ecf20Sopenharmony_ci { "Ricoh RF5C296/396", 0 }, 2038c2ecf20Sopenharmony_ci { "VLSI 82C146", 0 }, 2048c2ecf20Sopenharmony_ci { "Vadem VG-468", IS_VADEM }, 2058c2ecf20Sopenharmony_ci { "Vadem VG-469", IS_VADEM|IS_VG_PWR }, 2068c2ecf20Sopenharmony_ci { "Cirrus PD6710", IS_CIRRUS }, 2078c2ecf20Sopenharmony_ci { "Cirrus PD672x", IS_CIRRUS }, 2088c2ecf20Sopenharmony_ci { "VIA VT83C469", IS_CIRRUS|IS_VIA }, 2098c2ecf20Sopenharmony_ci}; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci#define PCIC_COUNT ARRAY_SIZE(pcic) 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/*====================================================================*/ 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(bus_lock); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic u_char i365_get(u_short sock, u_short reg) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci unsigned long flags; 2208c2ecf20Sopenharmony_ci spin_lock_irqsave(&bus_lock,flags); 2218c2ecf20Sopenharmony_ci { 2228c2ecf20Sopenharmony_ci unsigned int port = socket[sock].ioaddr; 2238c2ecf20Sopenharmony_ci u_char val; 2248c2ecf20Sopenharmony_ci reg = I365_REG(socket[sock].psock, reg); 2258c2ecf20Sopenharmony_ci outb(reg, port); val = inb(port+1); 2268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bus_lock,flags); 2278c2ecf20Sopenharmony_ci return val; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic void i365_set(u_short sock, u_short reg, u_char data) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci unsigned long flags; 2348c2ecf20Sopenharmony_ci spin_lock_irqsave(&bus_lock,flags); 2358c2ecf20Sopenharmony_ci { 2368c2ecf20Sopenharmony_ci unsigned int port = socket[sock].ioaddr; 2378c2ecf20Sopenharmony_ci u_char val = I365_REG(socket[sock].psock, reg); 2388c2ecf20Sopenharmony_ci outb(val, port); outb(data, port+1); 2398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bus_lock,flags); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void i365_bset(u_short sock, u_short reg, u_char mask) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci u_char d = i365_get(sock, reg); 2468c2ecf20Sopenharmony_ci d |= mask; 2478c2ecf20Sopenharmony_ci i365_set(sock, reg, d); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void i365_bclr(u_short sock, u_short reg, u_char mask) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci u_char d = i365_get(sock, reg); 2538c2ecf20Sopenharmony_ci d &= ~mask; 2548c2ecf20Sopenharmony_ci i365_set(sock, reg, d); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void i365_bflip(u_short sock, u_short reg, u_char mask, int b) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci u_char d = i365_get(sock, reg); 2608c2ecf20Sopenharmony_ci if (b) 2618c2ecf20Sopenharmony_ci d |= mask; 2628c2ecf20Sopenharmony_ci else 2638c2ecf20Sopenharmony_ci d &= ~mask; 2648c2ecf20Sopenharmony_ci i365_set(sock, reg, d); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic u_short i365_get_pair(u_short sock, u_short reg) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci u_short a, b; 2708c2ecf20Sopenharmony_ci a = i365_get(sock, reg); 2718c2ecf20Sopenharmony_ci b = i365_get(sock, reg+1); 2728c2ecf20Sopenharmony_ci return (a + (b<<8)); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void i365_set_pair(u_short sock, u_short reg, u_short data) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci i365_set(sock, reg, data & 0xff); 2788c2ecf20Sopenharmony_ci i365_set(sock, reg+1, data >> 8); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci/*====================================================================== 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci Code to save and restore global state information for Cirrus 2848c2ecf20Sopenharmony_ci PD67xx controllers, and to set and report global configuration 2858c2ecf20Sopenharmony_ci options. 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci The VIA controllers also use these routines, as they are mostly 2888c2ecf20Sopenharmony_ci Cirrus lookalikes, without the timing registers. 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci======================================================================*/ 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b)))) 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void cirrus_get_state(u_short s) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci int i; 2978c2ecf20Sopenharmony_ci struct cirrus_state *p = &socket[s].state.cirrus; 2988c2ecf20Sopenharmony_ci p->misc1 = i365_get(s, PD67_MISC_CTL_1); 2998c2ecf20Sopenharmony_ci p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA); 3008c2ecf20Sopenharmony_ci p->misc2 = i365_get(s, PD67_MISC_CTL_2); 3018c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 3028c2ecf20Sopenharmony_ci p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic void cirrus_set_state(u_short s) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci int i; 3088c2ecf20Sopenharmony_ci u_char misc; 3098c2ecf20Sopenharmony_ci struct cirrus_state *p = &socket[s].state.cirrus; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci misc = i365_get(s, PD67_MISC_CTL_2); 3128c2ecf20Sopenharmony_ci i365_set(s, PD67_MISC_CTL_2, p->misc2); 3138c2ecf20Sopenharmony_ci if (misc & PD67_MC2_SUSPEND) mdelay(50); 3148c2ecf20Sopenharmony_ci misc = i365_get(s, PD67_MISC_CTL_1); 3158c2ecf20Sopenharmony_ci misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA); 3168c2ecf20Sopenharmony_ci i365_set(s, PD67_MISC_CTL_1, misc | p->misc1); 3178c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 3188c2ecf20Sopenharmony_ci i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic u_int __init cirrus_set_opts(u_short s, char *buf) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct i82365_socket *t = &socket[s]; 3248c2ecf20Sopenharmony_ci struct cirrus_state *p = &socket[s].state.cirrus; 3258c2ecf20Sopenharmony_ci u_int mask = 0xffff; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (has_ring == -1) has_ring = 1; 3288c2ecf20Sopenharmony_ci flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring); 3298c2ecf20Sopenharmony_ci flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode); 3308c2ecf20Sopenharmony_ci flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass); 3318c2ecf20Sopenharmony_ci if (p->misc2 & PD67_MC2_IRQ15_RI) 3328c2ecf20Sopenharmony_ci strcat(buf, " [ring]"); 3338c2ecf20Sopenharmony_ci if (p->misc2 & PD67_MC2_DYNAMIC_MODE) 3348c2ecf20Sopenharmony_ci strcat(buf, " [dyn mode]"); 3358c2ecf20Sopenharmony_ci if (p->misc2 & PD67_MC2_FREQ_BYPASS) 3368c2ecf20Sopenharmony_ci strcat(buf, " [freq bypass]"); 3378c2ecf20Sopenharmony_ci if (p->misc1 & PD67_MC1_INPACK_ENA) 3388c2ecf20Sopenharmony_ci strcat(buf, " [inpack]"); 3398c2ecf20Sopenharmony_ci if (p->misc2 & PD67_MC2_IRQ15_RI) 3408c2ecf20Sopenharmony_ci mask &= ~0x8000; 3418c2ecf20Sopenharmony_ci if (has_led > 0) { 3428c2ecf20Sopenharmony_ci strcat(buf, " [led]"); 3438c2ecf20Sopenharmony_ci mask &= ~0x1000; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci if (has_dma > 0) { 3468c2ecf20Sopenharmony_ci strcat(buf, " [dma]"); 3478c2ecf20Sopenharmony_ci mask &= ~0x0600; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci if (!(t->flags & IS_VIA)) { 3508c2ecf20Sopenharmony_ci if (setup_time >= 0) 3518c2ecf20Sopenharmony_ci p->timer[0] = p->timer[3] = setup_time; 3528c2ecf20Sopenharmony_ci if (cmd_time > 0) { 3538c2ecf20Sopenharmony_ci p->timer[1] = cmd_time; 3548c2ecf20Sopenharmony_ci p->timer[4] = cmd_time*2+4; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci if (p->timer[1] == 0) { 3578c2ecf20Sopenharmony_ci p->timer[1] = 6; p->timer[4] = 16; 3588c2ecf20Sopenharmony_ci if (p->timer[0] == 0) 3598c2ecf20Sopenharmony_ci p->timer[0] = p->timer[3] = 1; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci if (recov_time >= 0) 3628c2ecf20Sopenharmony_ci p->timer[2] = p->timer[5] = recov_time; 3638c2ecf20Sopenharmony_ci buf += strlen(buf); 3648c2ecf20Sopenharmony_ci sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1], 3658c2ecf20Sopenharmony_ci p->timer[2], p->timer[3], p->timer[4], p->timer[5]); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci return mask; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/*====================================================================== 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci Code to save and restore global state information for Vadem VG468 3738c2ecf20Sopenharmony_ci and VG469 controllers, and to set and report global configuration 3748c2ecf20Sopenharmony_ci options. 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci======================================================================*/ 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic void vg46x_get_state(u_short s) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct vg46x_state *p = &socket[s].state.vg46x; 3818c2ecf20Sopenharmony_ci p->ctl = i365_get(s, VG468_CTL); 3828c2ecf20Sopenharmony_ci if (socket[s].type == IS_VG469) 3838c2ecf20Sopenharmony_ci p->ema = i365_get(s, VG469_EXT_MODE); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic void vg46x_set_state(u_short s) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct vg46x_state *p = &socket[s].state.vg46x; 3898c2ecf20Sopenharmony_ci i365_set(s, VG468_CTL, p->ctl); 3908c2ecf20Sopenharmony_ci if (socket[s].type == IS_VG469) 3918c2ecf20Sopenharmony_ci i365_set(s, VG469_EXT_MODE, p->ema); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic u_int __init vg46x_set_opts(u_short s, char *buf) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct vg46x_state *p = &socket[s].state.vg46x; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci flip(p->ctl, VG468_CTL_ASYNC, async_clock); 3998c2ecf20Sopenharmony_ci flip(p->ema, VG469_MODE_CABLE, cable_mode); 4008c2ecf20Sopenharmony_ci if (p->ctl & VG468_CTL_ASYNC) 4018c2ecf20Sopenharmony_ci strcat(buf, " [async]"); 4028c2ecf20Sopenharmony_ci if (p->ctl & VG468_CTL_INPACK) 4038c2ecf20Sopenharmony_ci strcat(buf, " [inpack]"); 4048c2ecf20Sopenharmony_ci if (socket[s].type == IS_VG469) { 4058c2ecf20Sopenharmony_ci u_char vsel = i365_get(s, VG469_VSELECT); 4068c2ecf20Sopenharmony_ci if (vsel & VG469_VSEL_EXT_STAT) { 4078c2ecf20Sopenharmony_ci strcat(buf, " [ext mode]"); 4088c2ecf20Sopenharmony_ci if (vsel & VG469_VSEL_EXT_BUS) 4098c2ecf20Sopenharmony_ci strcat(buf, " [isa buf]"); 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci if (p->ema & VG469_MODE_CABLE) 4128c2ecf20Sopenharmony_ci strcat(buf, " [cable]"); 4138c2ecf20Sopenharmony_ci if (p->ema & VG469_MODE_COMPAT) 4148c2ecf20Sopenharmony_ci strcat(buf, " [c step]"); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci return 0xffff; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/*====================================================================== 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci Generic routines to get and set controller options 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci======================================================================*/ 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic void get_bridge_state(u_short s) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct i82365_socket *t = &socket[s]; 4288c2ecf20Sopenharmony_ci if (t->flags & IS_CIRRUS) 4298c2ecf20Sopenharmony_ci cirrus_get_state(s); 4308c2ecf20Sopenharmony_ci else if (t->flags & IS_VADEM) 4318c2ecf20Sopenharmony_ci vg46x_get_state(s); 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic void set_bridge_state(u_short s) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct i82365_socket *t = &socket[s]; 4378c2ecf20Sopenharmony_ci if (t->flags & IS_CIRRUS) 4388c2ecf20Sopenharmony_ci cirrus_set_state(s); 4398c2ecf20Sopenharmony_ci else { 4408c2ecf20Sopenharmony_ci i365_set(s, I365_GBLCTL, 0x00); 4418c2ecf20Sopenharmony_ci i365_set(s, I365_GENCTL, 0x00); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr); 4448c2ecf20Sopenharmony_ci if (t->flags & IS_VADEM) 4458c2ecf20Sopenharmony_ci vg46x_set_state(s); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic u_int __init set_bridge_opts(u_short s, u_short ns) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci u_short i; 4518c2ecf20Sopenharmony_ci u_int m = 0xffff; 4528c2ecf20Sopenharmony_ci char buf[128]; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci for (i = s; i < s+ns; i++) { 4558c2ecf20Sopenharmony_ci if (socket[i].flags & IS_ALIVE) { 4568c2ecf20Sopenharmony_ci printk(KERN_INFO " host opts [%d]: already alive!\n", i); 4578c2ecf20Sopenharmony_ci continue; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci buf[0] = '\0'; 4608c2ecf20Sopenharmony_ci get_bridge_state(i); 4618c2ecf20Sopenharmony_ci if (socket[i].flags & IS_CIRRUS) 4628c2ecf20Sopenharmony_ci m = cirrus_set_opts(i, buf); 4638c2ecf20Sopenharmony_ci else if (socket[i].flags & IS_VADEM) 4648c2ecf20Sopenharmony_ci m = vg46x_set_opts(i, buf); 4658c2ecf20Sopenharmony_ci set_bridge_state(i); 4668c2ecf20Sopenharmony_ci printk(KERN_INFO " host opts [%d]:%s\n", i, 4678c2ecf20Sopenharmony_ci (*buf) ? buf : " none"); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci return m; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/*====================================================================== 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci Interrupt testing code, for ISA and PCI interrupts 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci======================================================================*/ 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic volatile u_int irq_hits; 4798c2ecf20Sopenharmony_cistatic u_short irq_sock; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic irqreturn_t i365_count_irq(int irq, void *dev) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci i365_get(irq_sock, I365_CSC); 4848c2ecf20Sopenharmony_ci irq_hits++; 4858c2ecf20Sopenharmony_ci pr_debug("i82365: -> hit on irq %d\n", irq); 4868c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic u_int __init test_irq(u_short sock, int irq) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci pr_debug("i82365: testing ISA irq %d\n", irq); 4928c2ecf20Sopenharmony_ci if (request_irq(irq, i365_count_irq, IRQF_PROBE_SHARED, "scan", 4938c2ecf20Sopenharmony_ci i365_count_irq) != 0) 4948c2ecf20Sopenharmony_ci return 1; 4958c2ecf20Sopenharmony_ci irq_hits = 0; irq_sock = sock; 4968c2ecf20Sopenharmony_ci msleep(10); 4978c2ecf20Sopenharmony_ci if (irq_hits) { 4988c2ecf20Sopenharmony_ci free_irq(irq, i365_count_irq); 4998c2ecf20Sopenharmony_ci pr_debug("i82365: spurious hit!\n"); 5008c2ecf20Sopenharmony_ci return 1; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* Generate one interrupt */ 5048c2ecf20Sopenharmony_ci i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4)); 5058c2ecf20Sopenharmony_ci i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); 5068c2ecf20Sopenharmony_ci udelay(1000); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci free_irq(irq, i365_count_irq); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* mask all interrupts */ 5118c2ecf20Sopenharmony_ci i365_set(sock, I365_CSCINT, 0); 5128c2ecf20Sopenharmony_ci pr_debug("i82365: hits = %d\n", irq_hits); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return (irq_hits != 1); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic u_int __init isa_scan(u_short sock, u_int mask0) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci u_int mask1 = 0; 5208c2ecf20Sopenharmony_ci int i; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci#ifdef __alpha__ 5238c2ecf20Sopenharmony_ci#define PIC 0x4d0 5248c2ecf20Sopenharmony_ci /* Don't probe level-triggered interrupts -- reserved for PCI */ 5258c2ecf20Sopenharmony_ci mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8)); 5268c2ecf20Sopenharmony_ci#endif 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (do_scan) { 5298c2ecf20Sopenharmony_ci set_bridge_state(sock); 5308c2ecf20Sopenharmony_ci i365_set(sock, I365_CSCINT, 0); 5318c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 5328c2ecf20Sopenharmony_ci if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0)) 5338c2ecf20Sopenharmony_ci mask1 |= (1 << i); 5348c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 5358c2ecf20Sopenharmony_ci if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0)) 5368c2ecf20Sopenharmony_ci mask1 ^= (1 << i); 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci printk(KERN_INFO " ISA irqs ("); 5408c2ecf20Sopenharmony_ci if (mask1) { 5418c2ecf20Sopenharmony_ci printk("scanned"); 5428c2ecf20Sopenharmony_ci } else { 5438c2ecf20Sopenharmony_ci /* Fallback: just find interrupts that aren't in use */ 5448c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 5458c2ecf20Sopenharmony_ci if ((mask0 & (1 << i)) && (_check_irq(i, IRQF_PROBE_SHARED) == 0)) 5468c2ecf20Sopenharmony_ci mask1 |= (1 << i); 5478c2ecf20Sopenharmony_ci printk("default"); 5488c2ecf20Sopenharmony_ci /* If scan failed, default to polled status */ 5498c2ecf20Sopenharmony_ci if (!cs_irq && (poll_interval == 0)) poll_interval = HZ; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci printk(") = "); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 5548c2ecf20Sopenharmony_ci if (mask1 & (1<<i)) 5558c2ecf20Sopenharmony_ci printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i); 5568c2ecf20Sopenharmony_ci if (mask1 == 0) printk("none!"); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return mask1; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci/*====================================================================*/ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci/* Time conversion functions */ 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int to_cycles(int ns) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci return ns/cycle_time; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci/*====================================================================*/ 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int __init identify(unsigned int port, u_short sock) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci u_char val; 5758c2ecf20Sopenharmony_ci int type = -1; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* Use the next free entry in the socket table */ 5788c2ecf20Sopenharmony_ci socket[sockets].ioaddr = port; 5798c2ecf20Sopenharmony_ci socket[sockets].psock = sock; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* Wake up a sleepy Cirrus controller */ 5828c2ecf20Sopenharmony_ci if (wakeup) { 5838c2ecf20Sopenharmony_ci i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND); 5848c2ecf20Sopenharmony_ci /* Pause at least 50 ms */ 5858c2ecf20Sopenharmony_ci mdelay(50); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if ((val = i365_get(sockets, I365_IDENT)) & 0x70) 5898c2ecf20Sopenharmony_ci return -1; 5908c2ecf20Sopenharmony_ci switch (val) { 5918c2ecf20Sopenharmony_ci case 0x82: 5928c2ecf20Sopenharmony_ci type = IS_I82365A; break; 5938c2ecf20Sopenharmony_ci case 0x83: 5948c2ecf20Sopenharmony_ci type = IS_I82365B; break; 5958c2ecf20Sopenharmony_ci case 0x84: 5968c2ecf20Sopenharmony_ci type = IS_I82365DF; break; 5978c2ecf20Sopenharmony_ci case 0x88: case 0x89: case 0x8a: 5988c2ecf20Sopenharmony_ci type = IS_IBM; break; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* Check for Vadem VG-468 chips */ 6028c2ecf20Sopenharmony_ci outb(0x0e, port); 6038c2ecf20Sopenharmony_ci outb(0x37, port); 6048c2ecf20Sopenharmony_ci i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV); 6058c2ecf20Sopenharmony_ci val = i365_get(sockets, I365_IDENT); 6068c2ecf20Sopenharmony_ci if (val & I365_IDENT_VADEM) { 6078c2ecf20Sopenharmony_ci i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV); 6088c2ecf20Sopenharmony_ci type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* Check for Ricoh chips */ 6128c2ecf20Sopenharmony_ci val = i365_get(sockets, RF5C_CHIP_ID); 6138c2ecf20Sopenharmony_ci if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396)) 6148c2ecf20Sopenharmony_ci type = IS_RF5Cx96; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* Check for Cirrus CL-PD67xx chips */ 6178c2ecf20Sopenharmony_ci i365_set(sockets, PD67_CHIP_INFO, 0); 6188c2ecf20Sopenharmony_ci val = i365_get(sockets, PD67_CHIP_INFO); 6198c2ecf20Sopenharmony_ci if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) { 6208c2ecf20Sopenharmony_ci val = i365_get(sockets, PD67_CHIP_INFO); 6218c2ecf20Sopenharmony_ci if ((val & PD67_INFO_CHIP_ID) == 0) { 6228c2ecf20Sopenharmony_ci type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710; 6238c2ecf20Sopenharmony_ci i365_set(sockets, PD67_EXT_INDEX, 0xe5); 6248c2ecf20Sopenharmony_ci if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5) 6258c2ecf20Sopenharmony_ci type = IS_VT83C469; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci return type; 6298c2ecf20Sopenharmony_ci} /* identify */ 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci/*====================================================================== 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci See if a card is present, powered up, in IO mode, and already 6348c2ecf20Sopenharmony_ci bound to a (non PC Card) Linux driver. We leave these alone. 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci We make an exception for cards that seem to be serial devices. 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci======================================================================*/ 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic int __init is_alive(u_short sock) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci u_char stat; 6438c2ecf20Sopenharmony_ci unsigned int start, stop; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci stat = i365_get(sock, I365_STATUS); 6468c2ecf20Sopenharmony_ci start = i365_get_pair(sock, I365_IO(0)+I365_W_START); 6478c2ecf20Sopenharmony_ci stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP); 6488c2ecf20Sopenharmony_ci if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) && 6498c2ecf20Sopenharmony_ci (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) && 6508c2ecf20Sopenharmony_ci (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) && 6518c2ecf20Sopenharmony_ci ((start & 0xfeef) != 0x02e8)) { 6528c2ecf20Sopenharmony_ci if (!request_region(start, stop-start+1, "i82365")) 6538c2ecf20Sopenharmony_ci return 1; 6548c2ecf20Sopenharmony_ci release_region(start, stop-start+1); 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/*====================================================================*/ 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic void __init add_socket(unsigned int port, int psock, int type) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci socket[sockets].ioaddr = port; 6658c2ecf20Sopenharmony_ci socket[sockets].psock = psock; 6668c2ecf20Sopenharmony_ci socket[sockets].type = type; 6678c2ecf20Sopenharmony_ci socket[sockets].flags = pcic[type].flags; 6688c2ecf20Sopenharmony_ci if (is_alive(sockets)) 6698c2ecf20Sopenharmony_ci socket[sockets].flags |= IS_ALIVE; 6708c2ecf20Sopenharmony_ci sockets++; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic void __init add_pcic(int ns, int type) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci u_int mask = 0, i, base; 6768c2ecf20Sopenharmony_ci int isa_irq = 0; 6778c2ecf20Sopenharmony_ci struct i82365_socket *t = &socket[sockets-ns]; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci base = sockets-ns; 6808c2ecf20Sopenharmony_ci if (base == 0) printk("\n"); 6818c2ecf20Sopenharmony_ci printk(KERN_INFO " %s", pcic[type].name); 6828c2ecf20Sopenharmony_ci printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x", 6838c2ecf20Sopenharmony_ci t->ioaddr, t->psock*0x40); 6848c2ecf20Sopenharmony_ci printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : "")); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* Set host options, build basic interrupt mask */ 6878c2ecf20Sopenharmony_ci if (irq_list_count == 0) 6888c2ecf20Sopenharmony_ci mask = irq_mask; 6898c2ecf20Sopenharmony_ci else 6908c2ecf20Sopenharmony_ci for (i = mask = 0; i < irq_list_count; i++) 6918c2ecf20Sopenharmony_ci mask |= (1<<irq_list[i]); 6928c2ecf20Sopenharmony_ci mask &= I365_MASK & set_bridge_opts(base, ns); 6938c2ecf20Sopenharmony_ci /* Scan for ISA interrupts */ 6948c2ecf20Sopenharmony_ci mask = isa_scan(base, mask); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* Poll if only two interrupts available */ 6978c2ecf20Sopenharmony_ci if (!poll_interval) { 6988c2ecf20Sopenharmony_ci u_int tmp = (mask & 0xff20); 6998c2ecf20Sopenharmony_ci tmp = tmp & (tmp-1); 7008c2ecf20Sopenharmony_ci if ((tmp & (tmp-1)) == 0) 7018c2ecf20Sopenharmony_ci poll_interval = HZ; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci /* Only try an ISA cs_irq if this is the first controller */ 7048c2ecf20Sopenharmony_ci if (!grab_irq && (cs_irq || !poll_interval)) { 7058c2ecf20Sopenharmony_ci /* Avoid irq 12 unless it is explicitly requested */ 7068c2ecf20Sopenharmony_ci u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12)); 7078c2ecf20Sopenharmony_ci for (cs_irq = 15; cs_irq > 0; cs_irq--) 7088c2ecf20Sopenharmony_ci if ((cs_mask & (1 << cs_irq)) && 7098c2ecf20Sopenharmony_ci (_check_irq(cs_irq, IRQF_PROBE_SHARED) == 0)) 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci if (cs_irq) { 7128c2ecf20Sopenharmony_ci grab_irq = 1; 7138c2ecf20Sopenharmony_ci isa_irq = cs_irq; 7148c2ecf20Sopenharmony_ci printk(" status change on irq %d\n", cs_irq); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (!isa_irq) { 7198c2ecf20Sopenharmony_ci if (poll_interval == 0) 7208c2ecf20Sopenharmony_ci poll_interval = HZ; 7218c2ecf20Sopenharmony_ci printk(" polling interval = %d ms\n", 7228c2ecf20Sopenharmony_ci poll_interval * 1000 / HZ); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* Update socket interrupt information, capabilities */ 7278c2ecf20Sopenharmony_ci for (i = 0; i < ns; i++) { 7288c2ecf20Sopenharmony_ci t[i].socket.features |= SS_CAP_PCCARD; 7298c2ecf20Sopenharmony_ci t[i].socket.map_size = 0x1000; 7308c2ecf20Sopenharmony_ci t[i].socket.irq_mask = mask; 7318c2ecf20Sopenharmony_ci t[i].cs_irq = isa_irq; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci} /* add_pcic */ 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci/*====================================================================*/ 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP 7398c2ecf20Sopenharmony_cistatic struct isapnp_device_id id_table[] __initdata = { 7408c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'), 7418c2ecf20Sopenharmony_ci ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" }, 7428c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'), 7438c2ecf20Sopenharmony_ci ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" }, 7448c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'), 7458c2ecf20Sopenharmony_ci ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" }, 7468c2ecf20Sopenharmony_ci { 0 } 7478c2ecf20Sopenharmony_ci}; 7488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(isapnp, id_table); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic struct pnp_dev *i82365_pnpdev; 7518c2ecf20Sopenharmony_ci#endif 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic void __init isa_probe(void) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci int i, j, sock, k, ns, id; 7568c2ecf20Sopenharmony_ci unsigned int port; 7578c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP 7588c2ecf20Sopenharmony_ci struct isapnp_device_id *devid; 7598c2ecf20Sopenharmony_ci struct pnp_dev *dev; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci for (devid = id_table; devid->vendor; devid++) { 7628c2ecf20Sopenharmony_ci if ((dev = pnp_find_dev(NULL, devid->vendor, devid->function, NULL))) { 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (pnp_device_attach(dev) < 0) 7658c2ecf20Sopenharmony_ci continue; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (pnp_activate_dev(dev) < 0) { 7688c2ecf20Sopenharmony_ci printk("activate failed\n"); 7698c2ecf20Sopenharmony_ci pnp_device_detach(dev); 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (!pnp_port_valid(dev, 0)) { 7748c2ecf20Sopenharmony_ci printk("invalid resources ?\n"); 7758c2ecf20Sopenharmony_ci pnp_device_detach(dev); 7768c2ecf20Sopenharmony_ci break; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci i365_base = pnp_port_start(dev, 0); 7798c2ecf20Sopenharmony_ci i82365_pnpdev = dev; 7808c2ecf20Sopenharmony_ci break; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci#endif 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (!request_region(i365_base, 2, "i82365")) { 7868c2ecf20Sopenharmony_ci if (sockets == 0) 7878c2ecf20Sopenharmony_ci printk("port conflict at %#lx\n", i365_base); 7888c2ecf20Sopenharmony_ci return; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci id = identify(i365_base, 0); 7928c2ecf20Sopenharmony_ci if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) { 7938c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 7948c2ecf20Sopenharmony_ci if (i == ignore) continue; 7958c2ecf20Sopenharmony_ci port = i365_base + ((i & 1) << 2) + ((i & 2) << 1); 7968c2ecf20Sopenharmony_ci sock = (i & 1) << 1; 7978c2ecf20Sopenharmony_ci if (identify(port, sock) == IS_I82365DF) { 7988c2ecf20Sopenharmony_ci add_socket(port, sock, IS_VLSI); 7998c2ecf20Sopenharmony_ci add_pcic(1, IS_VLSI); 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci } else { 8038c2ecf20Sopenharmony_ci for (i = 0; i < 8; i += 2) { 8048c2ecf20Sopenharmony_ci if (sockets && !extra_sockets && (i == 4)) 8058c2ecf20Sopenharmony_ci break; 8068c2ecf20Sopenharmony_ci port = i365_base + 2*(i>>2); 8078c2ecf20Sopenharmony_ci sock = (i & 3); 8088c2ecf20Sopenharmony_ci id = identify(port, sock); 8098c2ecf20Sopenharmony_ci if (id < 0) continue; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci for (j = ns = 0; j < 2; j++) { 8128c2ecf20Sopenharmony_ci /* Does the socket exist? */ 8138c2ecf20Sopenharmony_ci if ((ignore == i+j) || (identify(port, sock+j) < 0)) 8148c2ecf20Sopenharmony_ci continue; 8158c2ecf20Sopenharmony_ci /* Check for bad socket decode */ 8168c2ecf20Sopenharmony_ci for (k = 0; k <= sockets; k++) 8178c2ecf20Sopenharmony_ci i365_set(k, I365_MEM(0)+I365_W_OFF, k); 8188c2ecf20Sopenharmony_ci for (k = 0; k <= sockets; k++) 8198c2ecf20Sopenharmony_ci if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k) 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci if (k <= sockets) break; 8228c2ecf20Sopenharmony_ci add_socket(port, sock+j, id); ns++; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci if (ns != 0) add_pcic(ns, id); 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci/*====================================================================*/ 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic irqreturn_t pcic_interrupt(int irq, void *dev) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci int i, j, csc; 8348c2ecf20Sopenharmony_ci u_int events, active; 8358c2ecf20Sopenharmony_ci u_long flags = 0; 8368c2ecf20Sopenharmony_ci int handled = 0; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci pr_debug("pcic_interrupt(%d)\n", irq); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci for (j = 0; j < 20; j++) { 8418c2ecf20Sopenharmony_ci active = 0; 8428c2ecf20Sopenharmony_ci for (i = 0; i < sockets; i++) { 8438c2ecf20Sopenharmony_ci if (socket[i].cs_irq != irq) 8448c2ecf20Sopenharmony_ci continue; 8458c2ecf20Sopenharmony_ci handled = 1; 8468c2ecf20Sopenharmony_ci ISA_LOCK(i, flags); 8478c2ecf20Sopenharmony_ci csc = i365_get(i, I365_CSC); 8488c2ecf20Sopenharmony_ci if ((csc == 0) || (i365_get(i, I365_IDENT) & 0x70)) { 8498c2ecf20Sopenharmony_ci ISA_UNLOCK(i, flags); 8508c2ecf20Sopenharmony_ci continue; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD) 8558c2ecf20Sopenharmony_ci events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; 8568c2ecf20Sopenharmony_ci else { 8578c2ecf20Sopenharmony_ci events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0; 8588c2ecf20Sopenharmony_ci events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; 8598c2ecf20Sopenharmony_ci events |= (csc & I365_CSC_READY) ? SS_READY : 0; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci ISA_UNLOCK(i, flags); 8628c2ecf20Sopenharmony_ci pr_debug("socket %d event 0x%02x\n", i, events); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (events) 8658c2ecf20Sopenharmony_ci pcmcia_parse_events(&socket[i].socket, events); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci active |= events; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci if (!active) break; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci if (j == 20) 8728c2ecf20Sopenharmony_ci printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n"); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci pr_debug("pcic_interrupt done\n"); 8758c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 8768c2ecf20Sopenharmony_ci} /* pcic_interrupt */ 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic void pcic_interrupt_wrapper(struct timer_list *unused) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci pcic_interrupt(0, NULL); 8818c2ecf20Sopenharmony_ci poll_timer.expires = jiffies + poll_interval; 8828c2ecf20Sopenharmony_ci add_timer(&poll_timer); 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci/*====================================================================*/ 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic int i365_get_status(u_short sock, u_int *value) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci u_int status; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci status = i365_get(sock, I365_STATUS); 8928c2ecf20Sopenharmony_ci *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) 8938c2ecf20Sopenharmony_ci ? SS_DETECT : 0; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) 8968c2ecf20Sopenharmony_ci *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; 8978c2ecf20Sopenharmony_ci else { 8988c2ecf20Sopenharmony_ci *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD; 8998c2ecf20Sopenharmony_ci *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0; 9028c2ecf20Sopenharmony_ci *value |= (status & I365_CS_READY) ? SS_READY : 0; 9038c2ecf20Sopenharmony_ci *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (socket[sock].type == IS_VG469) { 9068c2ecf20Sopenharmony_ci status = i365_get(sock, VG469_VSENSE); 9078c2ecf20Sopenharmony_ci if (socket[sock].psock & 1) { 9088c2ecf20Sopenharmony_ci *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD; 9098c2ecf20Sopenharmony_ci *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD; 9108c2ecf20Sopenharmony_ci } else { 9118c2ecf20Sopenharmony_ci *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD; 9128c2ecf20Sopenharmony_ci *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci pr_debug("GetStatus(%d) = %#4.4x\n", sock, *value); 9178c2ecf20Sopenharmony_ci return 0; 9188c2ecf20Sopenharmony_ci} /* i365_get_status */ 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci/*====================================================================*/ 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic int i365_set_socket(u_short sock, socket_state_t *state) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct i82365_socket *t = &socket[sock]; 9258c2ecf20Sopenharmony_ci u_char reg; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci pr_debug("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " 9288c2ecf20Sopenharmony_ci "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, 9298c2ecf20Sopenharmony_ci state->Vcc, state->Vpp, state->io_irq, state->csc_mask); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* First set global controller options */ 9328c2ecf20Sopenharmony_ci set_bridge_state(sock); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* IO card, RESET flag, IO interrupt */ 9358c2ecf20Sopenharmony_ci reg = t->intr; 9368c2ecf20Sopenharmony_ci reg |= state->io_irq; 9378c2ecf20Sopenharmony_ci reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; 9388c2ecf20Sopenharmony_ci reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; 9398c2ecf20Sopenharmony_ci i365_set(sock, I365_INTCTL, reg); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci reg = I365_PWR_NORESET; 9428c2ecf20Sopenharmony_ci if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; 9438c2ecf20Sopenharmony_ci if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (t->flags & IS_CIRRUS) { 9468c2ecf20Sopenharmony_ci if (state->Vpp != 0) { 9478c2ecf20Sopenharmony_ci if (state->Vpp == 120) 9488c2ecf20Sopenharmony_ci reg |= I365_VPP1_12V; 9498c2ecf20Sopenharmony_ci else if (state->Vpp == state->Vcc) 9508c2ecf20Sopenharmony_ci reg |= I365_VPP1_5V; 9518c2ecf20Sopenharmony_ci else return -EINVAL; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci if (state->Vcc != 0) { 9548c2ecf20Sopenharmony_ci reg |= I365_VCC_5V; 9558c2ecf20Sopenharmony_ci if (state->Vcc == 33) 9568c2ecf20Sopenharmony_ci i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); 9578c2ecf20Sopenharmony_ci else if (state->Vcc == 50) 9588c2ecf20Sopenharmony_ci i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); 9598c2ecf20Sopenharmony_ci else return -EINVAL; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci } else if (t->flags & IS_VG_PWR) { 9628c2ecf20Sopenharmony_ci if (state->Vpp != 0) { 9638c2ecf20Sopenharmony_ci if (state->Vpp == 120) 9648c2ecf20Sopenharmony_ci reg |= I365_VPP1_12V; 9658c2ecf20Sopenharmony_ci else if (state->Vpp == state->Vcc) 9668c2ecf20Sopenharmony_ci reg |= I365_VPP1_5V; 9678c2ecf20Sopenharmony_ci else return -EINVAL; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci if (state->Vcc != 0) { 9708c2ecf20Sopenharmony_ci reg |= I365_VCC_5V; 9718c2ecf20Sopenharmony_ci if (state->Vcc == 33) 9728c2ecf20Sopenharmony_ci i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC); 9738c2ecf20Sopenharmony_ci else if (state->Vcc == 50) 9748c2ecf20Sopenharmony_ci i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC); 9758c2ecf20Sopenharmony_ci else return -EINVAL; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci } else if (t->flags & IS_DF_PWR) { 9788c2ecf20Sopenharmony_ci switch (state->Vcc) { 9798c2ecf20Sopenharmony_ci case 0: break; 9808c2ecf20Sopenharmony_ci case 33: reg |= I365_VCC_3V; break; 9818c2ecf20Sopenharmony_ci case 50: reg |= I365_VCC_5V; break; 9828c2ecf20Sopenharmony_ci default: return -EINVAL; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci switch (state->Vpp) { 9858c2ecf20Sopenharmony_ci case 0: break; 9868c2ecf20Sopenharmony_ci case 50: reg |= I365_VPP1_5V; break; 9878c2ecf20Sopenharmony_ci case 120: reg |= I365_VPP1_12V; break; 9888c2ecf20Sopenharmony_ci default: return -EINVAL; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci } else { 9918c2ecf20Sopenharmony_ci switch (state->Vcc) { 9928c2ecf20Sopenharmony_ci case 0: break; 9938c2ecf20Sopenharmony_ci case 50: reg |= I365_VCC_5V; break; 9948c2ecf20Sopenharmony_ci default: return -EINVAL; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci switch (state->Vpp) { 9978c2ecf20Sopenharmony_ci case 0: break; 9988c2ecf20Sopenharmony_ci case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break; 9998c2ecf20Sopenharmony_ci case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break; 10008c2ecf20Sopenharmony_ci default: return -EINVAL; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (reg != i365_get(sock, I365_POWER)) 10058c2ecf20Sopenharmony_ci i365_set(sock, I365_POWER, reg); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci /* Chipset-specific functions */ 10088c2ecf20Sopenharmony_ci if (t->flags & IS_CIRRUS) { 10098c2ecf20Sopenharmony_ci /* Speaker control */ 10108c2ecf20Sopenharmony_ci i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA, 10118c2ecf20Sopenharmony_ci state->flags & SS_SPKR_ENA); 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci /* Card status change interrupt mask */ 10158c2ecf20Sopenharmony_ci reg = t->cs_irq << 4; 10168c2ecf20Sopenharmony_ci if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; 10178c2ecf20Sopenharmony_ci if (state->flags & SS_IOCARD) { 10188c2ecf20Sopenharmony_ci if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; 10198c2ecf20Sopenharmony_ci } else { 10208c2ecf20Sopenharmony_ci if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1; 10218c2ecf20Sopenharmony_ci if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2; 10228c2ecf20Sopenharmony_ci if (state->csc_mask & SS_READY) reg |= I365_CSC_READY; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci i365_set(sock, I365_CSCINT, reg); 10258c2ecf20Sopenharmony_ci i365_get(sock, I365_CSC); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci return 0; 10288c2ecf20Sopenharmony_ci} /* i365_set_socket */ 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci/*====================================================================*/ 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic int i365_set_io_map(u_short sock, struct pccard_io_map *io) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci u_char map, ioctl; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci pr_debug("SetIOMap(%d, %d, %#2.2x, %d ns, " 10378c2ecf20Sopenharmony_ci "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed, 10388c2ecf20Sopenharmony_ci (unsigned long long)io->start, (unsigned long long)io->stop); 10398c2ecf20Sopenharmony_ci map = io->map; 10408c2ecf20Sopenharmony_ci if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) || 10418c2ecf20Sopenharmony_ci (io->stop < io->start)) return -EINVAL; 10428c2ecf20Sopenharmony_ci /* Turn off the window before changing anything */ 10438c2ecf20Sopenharmony_ci if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map)) 10448c2ecf20Sopenharmony_ci i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map)); 10458c2ecf20Sopenharmony_ci i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start); 10468c2ecf20Sopenharmony_ci i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop); 10478c2ecf20Sopenharmony_ci ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map); 10488c2ecf20Sopenharmony_ci if (io->speed) ioctl |= I365_IOCTL_WAIT(map); 10498c2ecf20Sopenharmony_ci if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); 10508c2ecf20Sopenharmony_ci if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); 10518c2ecf20Sopenharmony_ci if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); 10528c2ecf20Sopenharmony_ci i365_set(sock, I365_IOCTL, ioctl); 10538c2ecf20Sopenharmony_ci /* Turn on the window if necessary */ 10548c2ecf20Sopenharmony_ci if (io->flags & MAP_ACTIVE) 10558c2ecf20Sopenharmony_ci i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map)); 10568c2ecf20Sopenharmony_ci return 0; 10578c2ecf20Sopenharmony_ci} /* i365_set_io_map */ 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci/*====================================================================*/ 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci u_short base, i; 10648c2ecf20Sopenharmony_ci u_char map; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci pr_debug("SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, " 10678c2ecf20Sopenharmony_ci "%#x)\n", sock, mem->map, mem->flags, mem->speed, 10688c2ecf20Sopenharmony_ci (unsigned long long)mem->res->start, 10698c2ecf20Sopenharmony_ci (unsigned long long)mem->res->end, mem->card_start); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci map = mem->map; 10728c2ecf20Sopenharmony_ci if ((map > 4) || (mem->card_start > 0x3ffffff) || 10738c2ecf20Sopenharmony_ci (mem->res->start > mem->res->end) || (mem->speed > 1000)) 10748c2ecf20Sopenharmony_ci return -EINVAL; 10758c2ecf20Sopenharmony_ci if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff)) 10768c2ecf20Sopenharmony_ci return -EINVAL; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* Turn off the window before changing anything */ 10798c2ecf20Sopenharmony_ci if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map)) 10808c2ecf20Sopenharmony_ci i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map)); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci base = I365_MEM(map); 10838c2ecf20Sopenharmony_ci i = (mem->res->start >> 12) & 0x0fff; 10848c2ecf20Sopenharmony_ci if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT; 10858c2ecf20Sopenharmony_ci if (mem->flags & MAP_0WS) i |= I365_MEM_0WS; 10868c2ecf20Sopenharmony_ci i365_set_pair(sock, base+I365_W_START, i); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci i = (mem->res->end >> 12) & 0x0fff; 10898c2ecf20Sopenharmony_ci switch (to_cycles(mem->speed)) { 10908c2ecf20Sopenharmony_ci case 0: break; 10918c2ecf20Sopenharmony_ci case 1: i |= I365_MEM_WS0; break; 10928c2ecf20Sopenharmony_ci case 2: i |= I365_MEM_WS1; break; 10938c2ecf20Sopenharmony_ci default: i |= I365_MEM_WS1 | I365_MEM_WS0; break; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci i365_set_pair(sock, base+I365_W_STOP, i); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff; 10988c2ecf20Sopenharmony_ci if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT; 10998c2ecf20Sopenharmony_ci if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG; 11008c2ecf20Sopenharmony_ci i365_set_pair(sock, base+I365_W_OFF, i); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* Turn on the window if necessary */ 11038c2ecf20Sopenharmony_ci if (mem->flags & MAP_ACTIVE) 11048c2ecf20Sopenharmony_ci i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map)); 11058c2ecf20Sopenharmony_ci return 0; 11068c2ecf20Sopenharmony_ci} /* i365_set_mem_map */ 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci#if 0 /* driver model ordering issue */ 11098c2ecf20Sopenharmony_ci/*====================================================================== 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci Routines for accessing socket information and register dumps via 11128c2ecf20Sopenharmony_ci /sys/class/pcmcia_socket/... 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci======================================================================*/ 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic ssize_t show_info(struct class_device *class_dev, char *buf) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev); 11198c2ecf20Sopenharmony_ci return sprintf(buf, "type: %s\npsock: %d\n", 11208c2ecf20Sopenharmony_ci pcic[s->type].name, s->psock); 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic ssize_t show_exca(struct class_device *class_dev, char *buf) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev); 11268c2ecf20Sopenharmony_ci unsigned short sock; 11278c2ecf20Sopenharmony_ci int i; 11288c2ecf20Sopenharmony_ci ssize_t ret = 0; 11298c2ecf20Sopenharmony_ci unsigned long flags = 0; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci sock = s->number; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci ISA_LOCK(sock, flags); 11348c2ecf20Sopenharmony_ci for (i = 0; i < 0x40; i += 4) { 11358c2ecf20Sopenharmony_ci ret += sprintf(buf, "%02x %02x %02x %02x%s", 11368c2ecf20Sopenharmony_ci i365_get(sock,i), i365_get(sock,i+1), 11378c2ecf20Sopenharmony_ci i365_get(sock,i+2), i365_get(sock,i+3), 11388c2ecf20Sopenharmony_ci ((i % 16) == 12) ? "\n" : " "); 11398c2ecf20Sopenharmony_ci buf += ret; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci ISA_UNLOCK(sock, flags); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci return ret; 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL); 11478c2ecf20Sopenharmony_cistatic CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL); 11488c2ecf20Sopenharmony_ci#endif 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci/*====================================================================*/ 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci/* this is horribly ugly... proper locking needs to be done here at 11538c2ecf20Sopenharmony_ci * some time... */ 11548c2ecf20Sopenharmony_ci#define LOCKED(x) do { \ 11558c2ecf20Sopenharmony_ci int retval; \ 11568c2ecf20Sopenharmony_ci unsigned long flags; \ 11578c2ecf20Sopenharmony_ci spin_lock_irqsave(&isa_lock, flags); \ 11588c2ecf20Sopenharmony_ci retval = x; \ 11598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&isa_lock, flags); \ 11608c2ecf20Sopenharmony_ci return retval; \ 11618c2ecf20Sopenharmony_ci} while (0) 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistatic int pcic_get_status(struct pcmcia_socket *s, u_int *value) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci unsigned int sock = container_of(s, struct i82365_socket, socket)->number; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (socket[sock].flags & IS_ALIVE) { 11698c2ecf20Sopenharmony_ci *value = 0; 11708c2ecf20Sopenharmony_ci return -EINVAL; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci LOCKED(i365_get_status(sock, value)); 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci unsigned int sock = container_of(s, struct i82365_socket, socket)->number; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (socket[sock].flags & IS_ALIVE) 11818c2ecf20Sopenharmony_ci return -EINVAL; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci LOCKED(i365_set_socket(sock, state)); 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic int pcic_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci unsigned int sock = container_of(s, struct i82365_socket, socket)->number; 11898c2ecf20Sopenharmony_ci if (socket[sock].flags & IS_ALIVE) 11908c2ecf20Sopenharmony_ci return -EINVAL; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci LOCKED(i365_set_io_map(sock, io)); 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic int pcic_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci unsigned int sock = container_of(s, struct i82365_socket, socket)->number; 11988c2ecf20Sopenharmony_ci if (socket[sock].flags & IS_ALIVE) 11998c2ecf20Sopenharmony_ci return -EINVAL; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci LOCKED(i365_set_mem_map(sock, mem)); 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_cistatic int pcic_init(struct pcmcia_socket *s) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci int i; 12078c2ecf20Sopenharmony_ci struct resource res = { .start = 0, .end = 0x1000 }; 12088c2ecf20Sopenharmony_ci pccard_io_map io = { 0, 0, 0, 0, 1 }; 12098c2ecf20Sopenharmony_ci pccard_mem_map mem = { .res = &res, }; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 12128c2ecf20Sopenharmony_ci io.map = i; 12138c2ecf20Sopenharmony_ci pcic_set_io_map(s, &io); 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 12168c2ecf20Sopenharmony_ci mem.map = i; 12178c2ecf20Sopenharmony_ci pcic_set_mem_map(s, &mem); 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci return 0; 12208c2ecf20Sopenharmony_ci} 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic struct pccard_operations pcic_operations = { 12248c2ecf20Sopenharmony_ci .init = pcic_init, 12258c2ecf20Sopenharmony_ci .get_status = pcic_get_status, 12268c2ecf20Sopenharmony_ci .set_socket = pcic_set_socket, 12278c2ecf20Sopenharmony_ci .set_io_map = pcic_set_io_map, 12288c2ecf20Sopenharmony_ci .set_mem_map = pcic_set_mem_map, 12298c2ecf20Sopenharmony_ci}; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci/*====================================================================*/ 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic struct platform_driver i82365_driver = { 12348c2ecf20Sopenharmony_ci .driver = { 12358c2ecf20Sopenharmony_ci .name = "i82365", 12368c2ecf20Sopenharmony_ci }, 12378c2ecf20Sopenharmony_ci}; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_cistatic struct platform_device *i82365_device; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cistatic int __init init_i82365(void) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci int i, ret; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci ret = platform_driver_register(&i82365_driver); 12468c2ecf20Sopenharmony_ci if (ret) 12478c2ecf20Sopenharmony_ci goto err_out; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci i82365_device = platform_device_alloc("i82365", 0); 12508c2ecf20Sopenharmony_ci if (i82365_device) { 12518c2ecf20Sopenharmony_ci ret = platform_device_add(i82365_device); 12528c2ecf20Sopenharmony_ci if (ret) 12538c2ecf20Sopenharmony_ci platform_device_put(i82365_device); 12548c2ecf20Sopenharmony_ci } else 12558c2ecf20Sopenharmony_ci ret = -ENOMEM; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (ret) 12588c2ecf20Sopenharmony_ci goto err_driver_unregister; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci printk(KERN_INFO "Intel ISA PCIC probe: "); 12618c2ecf20Sopenharmony_ci sockets = 0; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci isa_probe(); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci if (sockets == 0) { 12668c2ecf20Sopenharmony_ci printk("not found.\n"); 12678c2ecf20Sopenharmony_ci ret = -ENODEV; 12688c2ecf20Sopenharmony_ci goto err_dev_unregister; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci /* Set up interrupt handler(s) */ 12728c2ecf20Sopenharmony_ci if (grab_irq != 0) 12738c2ecf20Sopenharmony_ci ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci if (ret) 12768c2ecf20Sopenharmony_ci goto err_socket_release; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci /* register sockets with the pcmcia core */ 12798c2ecf20Sopenharmony_ci for (i = 0; i < sockets; i++) { 12808c2ecf20Sopenharmony_ci socket[i].socket.dev.parent = &i82365_device->dev; 12818c2ecf20Sopenharmony_ci socket[i].socket.ops = &pcic_operations; 12828c2ecf20Sopenharmony_ci socket[i].socket.resource_ops = &pccard_nonstatic_ops; 12838c2ecf20Sopenharmony_ci socket[i].socket.owner = THIS_MODULE; 12848c2ecf20Sopenharmony_ci socket[i].number = i; 12858c2ecf20Sopenharmony_ci ret = pcmcia_register_socket(&socket[i].socket); 12868c2ecf20Sopenharmony_ci if (!ret) 12878c2ecf20Sopenharmony_ci socket[i].flags |= IS_REGISTERED; 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* Finally, schedule a polling interrupt */ 12918c2ecf20Sopenharmony_ci if (poll_interval != 0) { 12928c2ecf20Sopenharmony_ci timer_setup(&poll_timer, pcic_interrupt_wrapper, 0); 12938c2ecf20Sopenharmony_ci poll_timer.expires = jiffies + poll_interval; 12948c2ecf20Sopenharmony_ci add_timer(&poll_timer); 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci return 0; 12988c2ecf20Sopenharmony_cierr_socket_release: 12998c2ecf20Sopenharmony_ci for (i = 0; i < sockets; i++) { 13008c2ecf20Sopenharmony_ci /* Turn off all interrupt sources! */ 13018c2ecf20Sopenharmony_ci i365_set(i, I365_CSCINT, 0); 13028c2ecf20Sopenharmony_ci release_region(socket[i].ioaddr, 2); 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_cierr_dev_unregister: 13058c2ecf20Sopenharmony_ci platform_device_unregister(i82365_device); 13068c2ecf20Sopenharmony_ci release_region(i365_base, 2); 13078c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP 13088c2ecf20Sopenharmony_ci if (i82365_pnpdev) 13098c2ecf20Sopenharmony_ci pnp_disable_dev(i82365_pnpdev); 13108c2ecf20Sopenharmony_ci#endif 13118c2ecf20Sopenharmony_cierr_driver_unregister: 13128c2ecf20Sopenharmony_ci platform_driver_unregister(&i82365_driver); 13138c2ecf20Sopenharmony_cierr_out: 13148c2ecf20Sopenharmony_ci return ret; 13158c2ecf20Sopenharmony_ci} /* init_i82365 */ 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic void __exit exit_i82365(void) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci int i; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci for (i = 0; i < sockets; i++) { 13228c2ecf20Sopenharmony_ci if (socket[i].flags & IS_REGISTERED) 13238c2ecf20Sopenharmony_ci pcmcia_unregister_socket(&socket[i].socket); 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci platform_device_unregister(i82365_device); 13268c2ecf20Sopenharmony_ci if (poll_interval != 0) 13278c2ecf20Sopenharmony_ci del_timer_sync(&poll_timer); 13288c2ecf20Sopenharmony_ci if (grab_irq != 0) 13298c2ecf20Sopenharmony_ci free_irq(cs_irq, pcic_interrupt); 13308c2ecf20Sopenharmony_ci for (i = 0; i < sockets; i++) { 13318c2ecf20Sopenharmony_ci /* Turn off all interrupt sources! */ 13328c2ecf20Sopenharmony_ci i365_set(i, I365_CSCINT, 0); 13338c2ecf20Sopenharmony_ci release_region(socket[i].ioaddr, 2); 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci release_region(i365_base, 2); 13368c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP 13378c2ecf20Sopenharmony_ci if (i82365_pnpdev) 13388c2ecf20Sopenharmony_ci pnp_disable_dev(i82365_pnpdev); 13398c2ecf20Sopenharmony_ci#endif 13408c2ecf20Sopenharmony_ci platform_driver_unregister(&i82365_driver); 13418c2ecf20Sopenharmony_ci} /* exit_i82365 */ 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cimodule_init(init_i82365); 13448c2ecf20Sopenharmony_cimodule_exit(exit_i82365); 13458c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual MPL/GPL"); 13468c2ecf20Sopenharmony_ci/*====================================================================*/ 1347