^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) Device driver for Intel 82365 and compatible PC Card controllers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) i82365.c 1.265 1999/11/10 18:36:21
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) The contents of this file are subject to the Mozilla Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) License Version 1.1 (the "License"); you may not use this file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) except in compliance with the License. You may obtain a copy of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) the License at http://www.mozilla.org/MPL/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) Software distributed under the License is distributed on an "AS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) implied. See the License for the specific language governing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) rights and limitations under the License.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) The initial developer of the original code is David A. Hinds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) Alternatively, the contents of this file may be used under the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) terms of the GNU General Public License version 2 (the "GPL"), in which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) case the provisions of the GPL are applicable instead of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) above. If you wish to allow the use of your version of this file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) only under the terms of the GPL and not to allow others to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) your version of this file under the MPL, indicate your decision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) by deleting the provisions above and replace them with the notice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) and other provisions required by the GPL. If you do not delete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) the provisions above, a recipient may use your version of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) file under either the MPL or the GPL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #include <pcmcia/ss.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #include <linux/isapnp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* ISA-bus controllers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #include "i82365.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #include "cirrus.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #include "vg468.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #include "ricoh.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static irqreturn_t i365_count_irq(int, void *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static inline int _check_irq(int irq, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) free_irq(irq, i365_count_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* Parameters that can be set with 'insmod' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* Default base address for i82365sl and other ISA chips */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static unsigned long i365_base = 0x3e0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Should we probe at 0x3e2 for an extra ISA controller? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static int extra_sockets = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* Specify a socket number to ignore */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int ignore = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* Bit map or list of interrupts to choose from */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static u_int irq_mask = 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int irq_list[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static unsigned int irq_list_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /* The card status change interrupt -- 0 means autoselect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static int cs_irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* Probe for safe interrupts? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int do_scan = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /* Poll status interval -- 0 means default to interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static int poll_interval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* External clock time, in nanoseconds. 120 ns = 8.33 MHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static int cycle_time = 120;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /* Cirrus options */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static int has_dma = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static int has_led = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static int has_ring = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int dynamic_mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int freq_bypass = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static int setup_time = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static int cmd_time = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static int recov_time = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* Vadem options */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static int async_clock = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int cable_mode = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int wakeup = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) module_param_hw(i365_base, ulong, ioport, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) module_param(ignore, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) module_param(extra_sockets, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) module_param_hw(irq_mask, int, other, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) module_param_hw_array(irq_list, int, irq, &irq_list_count, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) module_param_hw(cs_irq, int, irq, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) module_param(async_clock, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) module_param(cable_mode, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) module_param(wakeup, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) module_param(do_scan, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) module_param(poll_interval, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) module_param(cycle_time, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) module_param(has_dma, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) module_param(has_led, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) module_param(has_ring, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) module_param(dynamic_mode, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) module_param(freq_bypass, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) module_param(setup_time, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) module_param(cmd_time, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) module_param(recov_time, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct cirrus_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) u_char misc1, misc2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) u_char timer[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct vg46x_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) u_char ctl, ema;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct i82365_socket {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) u_short type, flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct pcmcia_socket socket;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) unsigned int number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) unsigned int ioaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) u_short psock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) u_char cs_irq, intr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) struct cirrus_state cirrus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) struct vg46x_state vg46x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) } state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* Where we keep track of our sockets... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int sockets = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static struct i82365_socket socket[8] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) { 0, }, /* ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* Default ISA interrupt mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static int grab_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static DEFINE_SPINLOCK(isa_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static struct timer_list poll_timer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* These definitions must match the pcic table! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) enum pcic_id {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) IS_I82365A, IS_I82365B, IS_I82365DF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) IS_PD6710, IS_PD672X, IS_VT83C469,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* Flags for classifying groups of controllers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) #define IS_VADEM 0x0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) #define IS_CIRRUS 0x0002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) #define IS_VIA 0x0010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) #define IS_UNKNOWN 0x0400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) #define IS_VG_PWR 0x0800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) #define IS_DF_PWR 0x1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) #define IS_REGISTERED 0x2000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) #define IS_ALIVE 0x8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct pcic {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) u_short flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static struct pcic pcic[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) { "Intel i82365sl A step", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) { "Intel i82365sl B step", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) { "Intel i82365sl DF", IS_DF_PWR },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) { "IBM Clone", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) { "Ricoh RF5C296/396", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) { "VLSI 82C146", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) { "Vadem VG-468", IS_VADEM },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) { "Cirrus PD6710", IS_CIRRUS },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) { "Cirrus PD672x", IS_CIRRUS },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) { "VIA VT83C469", IS_CIRRUS|IS_VIA },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) #define PCIC_COUNT ARRAY_SIZE(pcic)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) static DEFINE_SPINLOCK(bus_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static u_char i365_get(u_short sock, u_short reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) spin_lock_irqsave(&bus_lock,flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) unsigned int port = socket[sock].ioaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) u_char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) reg = I365_REG(socket[sock].psock, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) outb(reg, port); val = inb(port+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) spin_unlock_irqrestore(&bus_lock,flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static void i365_set(u_short sock, u_short reg, u_char data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) spin_lock_irqsave(&bus_lock,flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) unsigned int port = socket[sock].ioaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) u_char val = I365_REG(socket[sock].psock, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) outb(val, port); outb(data, port+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) spin_unlock_irqrestore(&bus_lock,flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) static void i365_bset(u_short sock, u_short reg, u_char mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) u_char d = i365_get(sock, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) d |= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) i365_set(sock, reg, d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static void i365_bclr(u_short sock, u_short reg, u_char mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) u_char d = i365_get(sock, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) d &= ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) i365_set(sock, reg, d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) u_char d = i365_get(sock, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) d |= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) d &= ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) i365_set(sock, reg, d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static u_short i365_get_pair(u_short sock, u_short reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) u_short a, b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) a = i365_get(sock, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) b = i365_get(sock, reg+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return (a + (b<<8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static void i365_set_pair(u_short sock, u_short reg, u_short data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) i365_set(sock, reg, data & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) i365_set(sock, reg+1, data >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) Code to save and restore global state information for Cirrus
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) PD67xx controllers, and to set and report global configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) options.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) The VIA controllers also use these routines, as they are mostly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) Cirrus lookalikes, without the timing registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) #define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static void cirrus_get_state(u_short s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) struct cirrus_state *p = &socket[s].state.cirrus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) p->misc1 = i365_get(s, PD67_MISC_CTL_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) p->misc2 = i365_get(s, PD67_MISC_CTL_2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) for (i = 0; i < 6; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static void cirrus_set_state(u_short s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) u_char misc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) struct cirrus_state *p = &socket[s].state.cirrus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) misc = i365_get(s, PD67_MISC_CTL_2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) i365_set(s, PD67_MISC_CTL_2, p->misc2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (misc & PD67_MC2_SUSPEND) mdelay(50);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) misc = i365_get(s, PD67_MISC_CTL_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) i365_set(s, PD67_MISC_CTL_1, misc | p->misc1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) for (i = 0; i < 6; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) static u_int __init cirrus_set_opts(u_short s, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) struct i82365_socket *t = &socket[s];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) struct cirrus_state *p = &socket[s].state.cirrus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) u_int mask = 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (has_ring == -1) has_ring = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (p->misc2 & PD67_MC2_IRQ15_RI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) strcat(buf, " [ring]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) strcat(buf, " [dyn mode]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (p->misc2 & PD67_MC2_FREQ_BYPASS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) strcat(buf, " [freq bypass]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (p->misc1 & PD67_MC1_INPACK_ENA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) strcat(buf, " [inpack]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (p->misc2 & PD67_MC2_IRQ15_RI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) mask &= ~0x8000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (has_led > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) strcat(buf, " [led]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) mask &= ~0x1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (has_dma > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) strcat(buf, " [dma]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) mask &= ~0x0600;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (!(t->flags & IS_VIA)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (setup_time >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) p->timer[0] = p->timer[3] = setup_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (cmd_time > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) p->timer[1] = cmd_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) p->timer[4] = cmd_time*2+4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (p->timer[1] == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) p->timer[1] = 6; p->timer[4] = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (p->timer[0] == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) p->timer[0] = p->timer[3] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (recov_time >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) p->timer[2] = p->timer[5] = recov_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) buf += strlen(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) p->timer[2], p->timer[3], p->timer[4], p->timer[5]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) Code to save and restore global state information for Vadem VG468
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) and VG469 controllers, and to set and report global configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) options.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static void vg46x_get_state(u_short s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) struct vg46x_state *p = &socket[s].state.vg46x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) p->ctl = i365_get(s, VG468_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (socket[s].type == IS_VG469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) p->ema = i365_get(s, VG469_EXT_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) static void vg46x_set_state(u_short s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) struct vg46x_state *p = &socket[s].state.vg46x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) i365_set(s, VG468_CTL, p->ctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (socket[s].type == IS_VG469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) i365_set(s, VG469_EXT_MODE, p->ema);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) static u_int __init vg46x_set_opts(u_short s, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct vg46x_state *p = &socket[s].state.vg46x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) flip(p->ctl, VG468_CTL_ASYNC, async_clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) flip(p->ema, VG469_MODE_CABLE, cable_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (p->ctl & VG468_CTL_ASYNC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) strcat(buf, " [async]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (p->ctl & VG468_CTL_INPACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) strcat(buf, " [inpack]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (socket[s].type == IS_VG469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) u_char vsel = i365_get(s, VG469_VSELECT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (vsel & VG469_VSEL_EXT_STAT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) strcat(buf, " [ext mode]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (vsel & VG469_VSEL_EXT_BUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) strcat(buf, " [isa buf]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (p->ema & VG469_MODE_CABLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) strcat(buf, " [cable]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (p->ema & VG469_MODE_COMPAT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) strcat(buf, " [c step]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) Generic routines to get and set controller options
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static void get_bridge_state(u_short s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) struct i82365_socket *t = &socket[s];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (t->flags & IS_CIRRUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) cirrus_get_state(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) else if (t->flags & IS_VADEM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) vg46x_get_state(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) static void set_bridge_state(u_short s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) struct i82365_socket *t = &socket[s];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) if (t->flags & IS_CIRRUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) cirrus_set_state(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) i365_set(s, I365_GBLCTL, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) i365_set(s, I365_GENCTL, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (t->flags & IS_VADEM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) vg46x_set_state(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static u_int __init set_bridge_opts(u_short s, u_short ns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) u_short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) u_int m = 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) char buf[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) for (i = s; i < s+ns; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (socket[i].flags & IS_ALIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) printk(KERN_INFO " host opts [%d]: already alive!\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) buf[0] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) get_bridge_state(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (socket[i].flags & IS_CIRRUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) m = cirrus_set_opts(i, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) else if (socket[i].flags & IS_VADEM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) m = vg46x_set_opts(i, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) set_bridge_state(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) printk(KERN_INFO " host opts [%d]:%s\n", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) (*buf) ? buf : " none");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) return m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) Interrupt testing code, for ISA and PCI interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static volatile u_int irq_hits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) static u_short irq_sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) static irqreturn_t i365_count_irq(int irq, void *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) i365_get(irq_sock, I365_CSC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) irq_hits++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) pr_debug("i82365: -> hit on irq %d\n", irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) static u_int __init test_irq(u_short sock, int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) pr_debug("i82365: testing ISA irq %d\n", irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (request_irq(irq, i365_count_irq, IRQF_PROBE_SHARED, "scan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) i365_count_irq) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) irq_hits = 0; irq_sock = sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) msleep(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (irq_hits) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) free_irq(irq, i365_count_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) pr_debug("i82365: spurious hit!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) /* Generate one interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) udelay(1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) free_irq(irq, i365_count_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /* mask all interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) i365_set(sock, I365_CSCINT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) pr_debug("i82365: hits = %d\n", irq_hits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return (irq_hits != 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) static u_int __init isa_scan(u_short sock, u_int mask0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) u_int mask1 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) #ifdef __alpha__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) #define PIC 0x4d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) /* Don't probe level-triggered interrupts -- reserved for PCI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (do_scan) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) set_bridge_state(sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) i365_set(sock, I365_CSCINT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) for (i = 0; i < 16; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) mask1 |= (1 << i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) for (i = 0; i < 16; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) mask1 ^= (1 << i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) printk(KERN_INFO " ISA irqs (");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (mask1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) printk("scanned");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) /* Fallback: just find interrupts that aren't in use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) for (i = 0; i < 16; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if ((mask0 & (1 << i)) && (_check_irq(i, IRQF_PROBE_SHARED) == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) mask1 |= (1 << i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) printk("default");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) /* If scan failed, default to polled status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) printk(") = ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) for (i = 0; i < 16; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (mask1 & (1<<i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (mask1 == 0) printk("none!");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) return mask1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) /* Time conversion functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) static int to_cycles(int ns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) return ns/cycle_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) static int __init identify(unsigned int port, u_short sock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) u_char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) int type = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) /* Use the next free entry in the socket table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) socket[sockets].ioaddr = port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) socket[sockets].psock = sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) /* Wake up a sleepy Cirrus controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (wakeup) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) /* Pause at least 50 ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) mdelay(50);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) case 0x82:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) type = IS_I82365A; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) case 0x83:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) type = IS_I82365B; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) case 0x84:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) type = IS_I82365DF; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) case 0x88: case 0x89: case 0x8a:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) type = IS_IBM; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) /* Check for Vadem VG-468 chips */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) outb(0x0e, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) outb(0x37, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) val = i365_get(sockets, I365_IDENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) if (val & I365_IDENT_VADEM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) /* Check for Ricoh chips */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) val = i365_get(sockets, RF5C_CHIP_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) type = IS_RF5Cx96;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) /* Check for Cirrus CL-PD67xx chips */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) i365_set(sockets, PD67_CHIP_INFO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) val = i365_get(sockets, PD67_CHIP_INFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) val = i365_get(sockets, PD67_CHIP_INFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if ((val & PD67_INFO_CHIP_ID) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) i365_set(sockets, PD67_EXT_INDEX, 0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) type = IS_VT83C469;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) return type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) } /* identify */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) See if a card is present, powered up, in IO mode, and already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) bound to a (non PC Card) Linux driver. We leave these alone.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) We make an exception for cards that seem to be serial devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) static int __init is_alive(u_short sock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) u_char stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) unsigned int start, stop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) stat = i365_get(sock, I365_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) ((start & 0xfeef) != 0x02e8)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (!request_region(start, stop-start+1, "i82365"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) release_region(start, stop-start+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) static void __init add_socket(unsigned int port, int psock, int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) socket[sockets].ioaddr = port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) socket[sockets].psock = psock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) socket[sockets].type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) socket[sockets].flags = pcic[type].flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (is_alive(sockets))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) socket[sockets].flags |= IS_ALIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) sockets++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) static void __init add_pcic(int ns, int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) u_int mask = 0, i, base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) int isa_irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) struct i82365_socket *t = &socket[sockets-ns];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) base = sockets-ns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (base == 0) printk("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) printk(KERN_INFO " %s", pcic[type].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) t->ioaddr, t->psock*0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) /* Set host options, build basic interrupt mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (irq_list_count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) mask = irq_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) for (i = mask = 0; i < irq_list_count; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) mask |= (1<<irq_list[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) mask &= I365_MASK & set_bridge_opts(base, ns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) /* Scan for ISA interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) mask = isa_scan(base, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) /* Poll if only two interrupts available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) if (!poll_interval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) u_int tmp = (mask & 0xff20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) tmp = tmp & (tmp-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if ((tmp & (tmp-1)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) poll_interval = HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) /* Only try an ISA cs_irq if this is the first controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) if (!grab_irq && (cs_irq || !poll_interval)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) /* Avoid irq 12 unless it is explicitly requested */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) for (cs_irq = 15; cs_irq > 0; cs_irq--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if ((cs_mask & (1 << cs_irq)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) (_check_irq(cs_irq, IRQF_PROBE_SHARED) == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if (cs_irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) grab_irq = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) isa_irq = cs_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) printk(" status change on irq %d\n", cs_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (!isa_irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) if (poll_interval == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) poll_interval = HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) printk(" polling interval = %d ms\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) poll_interval * 1000 / HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) /* Update socket interrupt information, capabilities */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) for (i = 0; i < ns; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) t[i].socket.features |= SS_CAP_PCCARD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) t[i].socket.map_size = 0x1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) t[i].socket.irq_mask = mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) t[i].cs_irq = isa_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) } /* add_pcic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) #ifdef CONFIG_PNP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) static struct isapnp_device_id id_table[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) { 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) MODULE_DEVICE_TABLE(isapnp, id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) static struct pnp_dev *i82365_pnpdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) static void __init isa_probe(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) int i, j, sock, k, ns, id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) unsigned int port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) #ifdef CONFIG_PNP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) struct isapnp_device_id *devid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) struct pnp_dev *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) for (devid = id_table; devid->vendor; devid++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) if ((dev = pnp_find_dev(NULL, devid->vendor, devid->function, NULL))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (pnp_device_attach(dev) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) if (pnp_activate_dev(dev) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) printk("activate failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) pnp_device_detach(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) if (!pnp_port_valid(dev, 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) printk("invalid resources ?\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) pnp_device_detach(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) i365_base = pnp_port_start(dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) i82365_pnpdev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) if (!request_region(i365_base, 2, "i82365")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) if (sockets == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) printk("port conflict at %#lx\n", i365_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) id = identify(i365_base, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) for (i = 0; i < 4; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) if (i == ignore) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) sock = (i & 1) << 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (identify(port, sock) == IS_I82365DF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) add_socket(port, sock, IS_VLSI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) add_pcic(1, IS_VLSI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) for (i = 0; i < 8; i += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) if (sockets && !extra_sockets && (i == 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) port = i365_base + 2*(i>>2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) sock = (i & 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) id = identify(port, sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) if (id < 0) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) for (j = ns = 0; j < 2; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) /* Does the socket exist? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) if ((ignore == i+j) || (identify(port, sock+j) < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) /* Check for bad socket decode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) for (k = 0; k <= sockets; k++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) i365_set(k, I365_MEM(0)+I365_W_OFF, k);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) for (k = 0; k <= sockets; k++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) if (k <= sockets) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) add_socket(port, sock+j, id); ns++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) if (ns != 0) add_pcic(ns, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) static irqreturn_t pcic_interrupt(int irq, void *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) int i, j, csc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) u_int events, active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) u_long flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) int handled = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) pr_debug("pcic_interrupt(%d)\n", irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) for (j = 0; j < 20; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) active = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) for (i = 0; i < sockets; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) if (socket[i].cs_irq != irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) handled = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) ISA_LOCK(i, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) csc = i365_get(i, I365_CSC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if ((csc == 0) || (i365_get(i, I365_IDENT) & 0x70)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) ISA_UNLOCK(i, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) events |= (csc & I365_CSC_READY) ? SS_READY : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) ISA_UNLOCK(i, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) pr_debug("socket %d event 0x%02x\n", i, events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (events)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) pcmcia_parse_events(&socket[i].socket, events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) active |= events;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) if (!active) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) if (j == 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) pr_debug("pcic_interrupt done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) return IRQ_RETVAL(handled);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) } /* pcic_interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) static void pcic_interrupt_wrapper(struct timer_list *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) pcic_interrupt(0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) poll_timer.expires = jiffies + poll_interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) add_timer(&poll_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) static int i365_get_status(u_short sock, u_int *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) u_int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) status = i365_get(sock, I365_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) ? SS_DETECT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) *value |= (status & I365_CS_READY) ? SS_READY : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) if (socket[sock].type == IS_VG469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) status = i365_get(sock, VG469_VSENSE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) if (socket[sock].psock & 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) pr_debug("GetStatus(%d) = %#4.4x\n", sock, *value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) } /* i365_get_status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) static int i365_set_socket(u_short sock, socket_state_t *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) struct i82365_socket *t = &socket[sock];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) u_char reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) pr_debug("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) /* First set global controller options */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) set_bridge_state(sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) /* IO card, RESET flag, IO interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) reg = t->intr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) reg |= state->io_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) i365_set(sock, I365_INTCTL, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) reg = I365_PWR_NORESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) if (t->flags & IS_CIRRUS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) if (state->Vpp != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) if (state->Vpp == 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) reg |= I365_VPP1_12V;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) else if (state->Vpp == state->Vcc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) reg |= I365_VPP1_5V;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) else return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) if (state->Vcc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) reg |= I365_VCC_5V;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) if (state->Vcc == 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) else if (state->Vcc == 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) else return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) } else if (t->flags & IS_VG_PWR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) if (state->Vpp != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) if (state->Vpp == 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) reg |= I365_VPP1_12V;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) else if (state->Vpp == state->Vcc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) reg |= I365_VPP1_5V;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) else return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) if (state->Vcc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) reg |= I365_VCC_5V;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) if (state->Vcc == 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) else if (state->Vcc == 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) else return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) } else if (t->flags & IS_DF_PWR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) switch (state->Vcc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) case 0: break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) case 33: reg |= I365_VCC_3V; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) case 50: reg |= I365_VCC_5V; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) default: return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) switch (state->Vpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) case 0: break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) case 50: reg |= I365_VPP1_5V; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) case 120: reg |= I365_VPP1_12V; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) default: return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) switch (state->Vcc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) case 0: break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) case 50: reg |= I365_VCC_5V; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) default: return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) switch (state->Vpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) case 0: break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) default: return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) if (reg != i365_get(sock, I365_POWER))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) i365_set(sock, I365_POWER, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) /* Chipset-specific functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) if (t->flags & IS_CIRRUS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) /* Speaker control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) state->flags & SS_SPKR_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) /* Card status change interrupt mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) reg = t->cs_irq << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) if (state->flags & SS_IOCARD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) i365_set(sock, I365_CSCINT, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) i365_get(sock, I365_CSC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) } /* i365_set_socket */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) u_char map, ioctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) pr_debug("SetIOMap(%d, %d, %#2.2x, %d ns, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) (unsigned long long)io->start, (unsigned long long)io->stop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) map = io->map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) (io->stop < io->start)) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) /* Turn off the window before changing anything */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) i365_set(sock, I365_IOCTL, ioctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) /* Turn on the window if necessary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) if (io->flags & MAP_ACTIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) } /* i365_set_io_map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) u_short base, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) u_char map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) pr_debug("SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) "%#x)\n", sock, mem->map, mem->flags, mem->speed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) (unsigned long long)mem->res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) (unsigned long long)mem->res->end, mem->card_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) map = mem->map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) if ((map > 4) || (mem->card_start > 0x3ffffff) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) (mem->res->start > mem->res->end) || (mem->speed > 1000))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) /* Turn off the window before changing anything */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) base = I365_MEM(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) i = (mem->res->start >> 12) & 0x0fff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) i365_set_pair(sock, base+I365_W_START, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) i = (mem->res->end >> 12) & 0x0fff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) switch (to_cycles(mem->speed)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) case 0: break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) case 1: i |= I365_MEM_WS0; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) case 2: i |= I365_MEM_WS1; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) default: i |= I365_MEM_WS1 | I365_MEM_WS0; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) i365_set_pair(sock, base+I365_W_STOP, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) i365_set_pair(sock, base+I365_W_OFF, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) /* Turn on the window if necessary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) if (mem->flags & MAP_ACTIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) } /* i365_set_mem_map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) #if 0 /* driver model ordering issue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) Routines for accessing socket information and register dumps via
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) /sys/class/pcmcia_socket/...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) static ssize_t show_info(struct class_device *class_dev, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) return sprintf(buf, "type: %s\npsock: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) pcic[s->type].name, s->psock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) static ssize_t show_exca(struct class_device *class_dev, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) unsigned short sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) ssize_t ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) unsigned long flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) sock = s->number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) ISA_LOCK(sock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) for (i = 0; i < 0x40; i += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) ret += sprintf(buf, "%02x %02x %02x %02x%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) i365_get(sock,i), i365_get(sock,i+1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) i365_get(sock,i+2), i365_get(sock,i+3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) ((i % 16) == 12) ? "\n" : " ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) buf += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) ISA_UNLOCK(sock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) /* this is horribly ugly... proper locking needs to be done here at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) * some time... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) #define LOCKED(x) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) int retval; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) unsigned long flags; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) spin_lock_irqsave(&isa_lock, flags); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) retval = x; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) spin_unlock_irqrestore(&isa_lock, flags); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) return retval; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) static int pcic_get_status(struct pcmcia_socket *s, u_int *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) if (socket[sock].flags & IS_ALIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) *value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) LOCKED(i365_get_status(sock, value));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) static int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) if (socket[sock].flags & IS_ALIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) LOCKED(i365_set_socket(sock, state));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) static int pcic_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) if (socket[sock].flags & IS_ALIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) LOCKED(i365_set_io_map(sock, io));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) static int pcic_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) if (socket[sock].flags & IS_ALIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) LOCKED(i365_set_mem_map(sock, mem));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) static int pcic_init(struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) struct resource res = { .start = 0, .end = 0x1000 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) pccard_io_map io = { 0, 0, 0, 0, 1 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) pccard_mem_map mem = { .res = &res, };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) for (i = 0; i < 2; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) io.map = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) pcic_set_io_map(s, &io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) for (i = 0; i < 5; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) mem.map = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) pcic_set_mem_map(s, &mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) static struct pccard_operations pcic_operations = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) .init = pcic_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) .get_status = pcic_get_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) .set_socket = pcic_set_socket,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) .set_io_map = pcic_set_io_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) .set_mem_map = pcic_set_mem_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) static struct platform_driver i82365_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) .name = "i82365",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) static struct platform_device *i82365_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) static int __init init_i82365(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) ret = platform_driver_register(&i82365_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) i82365_device = platform_device_alloc("i82365", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) if (i82365_device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) ret = platform_device_add(i82365_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) platform_device_put(i82365_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) goto err_driver_unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) printk(KERN_INFO "Intel ISA PCIC probe: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) sockets = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) isa_probe();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) if (sockets == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) printk("not found.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) goto err_dev_unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) /* Set up interrupt handler(s) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) if (grab_irq != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) goto err_socket_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) /* register sockets with the pcmcia core */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) for (i = 0; i < sockets; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) socket[i].socket.dev.parent = &i82365_device->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) socket[i].socket.ops = &pcic_operations;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) socket[i].socket.resource_ops = &pccard_nonstatic_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) socket[i].socket.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) socket[i].number = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) ret = pcmcia_register_socket(&socket[i].socket);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) socket[i].flags |= IS_REGISTERED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) /* Finally, schedule a polling interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) if (poll_interval != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) timer_setup(&poll_timer, pcic_interrupt_wrapper, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) poll_timer.expires = jiffies + poll_interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) add_timer(&poll_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) err_socket_release:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) for (i = 0; i < sockets; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) /* Turn off all interrupt sources! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) i365_set(i, I365_CSCINT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) release_region(socket[i].ioaddr, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) err_dev_unregister:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) platform_device_unregister(i82365_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) release_region(i365_base, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) #ifdef CONFIG_PNP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) if (i82365_pnpdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) pnp_disable_dev(i82365_pnpdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) err_driver_unregister:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) platform_driver_unregister(&i82365_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) } /* init_i82365 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) static void __exit exit_i82365(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) for (i = 0; i < sockets; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) if (socket[i].flags & IS_REGISTERED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) pcmcia_unregister_socket(&socket[i].socket);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) platform_device_unregister(i82365_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) if (poll_interval != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) del_timer_sync(&poll_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) if (grab_irq != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) free_irq(cs_irq, pcic_interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) for (i = 0; i < sockets; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) /* Turn off all interrupt sources! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) i365_set(i, I365_CSCINT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) release_region(socket[i].ioaddr, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) release_region(i365_base, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) #ifdef CONFIG_PNP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) if (i82365_pnpdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) pnp_disable_dev(i82365_pnpdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) platform_driver_unregister(&i82365_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) } /* exit_i82365 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) module_init(init_i82365);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) module_exit(exit_i82365);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) MODULE_LICENSE("Dual MPL/GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) /*====================================================================*/