11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Device driver for Intel 82365 and compatible PC Card controllers.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i82365.c 1.265 1999/11/10 18:36:21
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The contents of this file are subject to the Mozilla Public
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    License Version 1.1 (the "License"); you may not use this file
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    except in compliance with the License. You may obtain a copy of
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the License at http://www.mozilla.org/MPL/
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Software distributed under the License is distributed on an "AS
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    implied. See the License for the specific language governing
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    rights and limitations under the License.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The initial developer of the original code is David A. Hinds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Alternatively, the contents of this file may be used under the
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    terms of the GNU General Public License version 2 (the "GPL"), in which
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    case the provisions of the GPL are applicable instead of the
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    above.  If you wish to allow the use of your version of this file
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    only under the terms of the GPL and not to allow others to use
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    your version of this file under the MPL, indicate your decision
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    by deleting the provisions above and replace them with the notice
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    and other provisions required by the GPL.  If you do not delete
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the provisions above, a recipient may use your version of this
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    file under either the MPL or the GPL.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/workqueue.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
47d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ss.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/isapnp.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ISA-bus controllers */
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "i82365.h"
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cirrus.h"
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "vg468.h"
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ricoh.h"
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
637d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t i365_count_irq(int, void *);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int _check_irq(int irq, int flags)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    free_irq(irq, i365_count_irq);
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return 0;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Parameters that can be set with 'insmod' */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Default base address for i82365sl and other ISA chips */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long i365_base = 0x3e0;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Should we probe at 0x3e2 for an extra ISA controller? */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int extra_sockets = 0;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Specify a socket number to ignore */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ignore = -1;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bit map or list of interrupts to choose from */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int irq_mask = 0xffff;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irq_list[16];
8564a6f9500d8e8a8e1b1adc2120e56cc88df5727fAl Virostatic unsigned int irq_list_count;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The card status change interrupt -- 0 means autoselect */
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cs_irq = 0;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Probe for safe interrupts? */
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_scan = 1;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Poll status interval -- 0 means default to interrupt */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int poll_interval = 0;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* External clock time, in nanoseconds.  120 ns = 8.33 MHz */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cycle_time = 120;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Cirrus options */
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int has_dma = -1;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int has_led = -1;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int has_ring = -1;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dynamic_mode = 0;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int freq_bypass = -1;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int setup_time = -1;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cmd_time = -1;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int recov_time = -1;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Vadem options */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int async_clock = -1;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cable_mode = -1;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wakeup = 0;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(i365_base, ulong, 0444);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ignore, int, 0444);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(extra_sockets, int, 0444);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(irq_mask, int, 0444);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(irq_list, int, &irq_list_count, 0444);
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(cs_irq, int, 0444);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(async_clock, int, 0444);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(cable_mode, int, 0444);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(wakeup, int, 0444);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(do_scan, int, 0444);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(poll_interval, int, 0444);
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(cycle_time, int, 0444);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(has_dma, int, 0444);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(has_led, int, 0444);
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(has_ring, int, 0444);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(dynamic_mode, int, 0444);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(freq_bypass, int, 0444);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(setup_time, int, 0444);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(cmd_time, int, 0444);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(recov_time, int, 0444);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct cirrus_state_t {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char		misc1, misc2;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char		timer[6];
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} cirrus_state_t;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct vg46x_state_t {
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char		ctl, ema;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} vg46x_state_t;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct i82365_socket {
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_short		type, flags;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct pcmcia_socket	socket;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    unsigned int	number;
148906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johansson    unsigned int	ioaddr;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_short		psock;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char		cs_irq, intr;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    union {
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cirrus_state_t		cirrus;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vg46x_state_t		vg46x;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    } state;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Where we keep track of our sockets... */
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sockets = 0;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i82365_socket socket[8] = {
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { 0, }, /* ... */
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Default ISA interrupt mask */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I365_MASK	0xdeb8	/* irq 15,14,12,11,10,9,7,5,4,3 */
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int grab_irq;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(isa_lock);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f)
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct timer_list poll_timer;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These definitions must match the pcic table! */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef enum pcic_id {
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    IS_I82365A, IS_I82365B, IS_I82365DF,
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    IS_PD6710, IS_PD672X, IS_VT83C469,
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} pcic_id;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Flags for classifying groups of controllers */
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_VADEM	0x0001
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_CIRRUS	0x0002
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_VIA		0x0010
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_UNKNOWN	0x0400
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_VG_PWR	0x0800
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_DF_PWR	0x1000
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_REGISTERED	0x2000
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_ALIVE	0x8000
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct pcic_t {
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    char		*name;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_short		flags;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} pcic_t;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic pcic_t pcic[] = {
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "Intel i82365sl A step", 0 },
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "Intel i82365sl B step", 0 },
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "Intel i82365sl DF", IS_DF_PWR },
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "IBM Clone", 0 },
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "Ricoh RF5C296/396", 0 },
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "VLSI 82C146", 0 },
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "Vadem VG-468", IS_VADEM },
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "Cirrus PD6710", IS_CIRRUS },
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "Cirrus PD672x", IS_CIRRUS },
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { "VIA VT83C469", IS_CIRRUS|IS_VIA },
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCIC_COUNT	(sizeof(pcic)/sizeof(pcic_t))
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(bus_lock);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_char i365_get(u_short sock, u_short reg)
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    unsigned long flags;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    spin_lock_irqsave(&bus_lock,flags);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    {
222906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johansson	unsigned int port = socket[sock].ioaddr;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char val;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg = I365_REG(socket[sock].psock, reg);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(reg, port); val = inb(port+1);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&bus_lock,flags);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void i365_set(u_short sock, u_short reg, u_char data)
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    unsigned long flags;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    spin_lock_irqsave(&bus_lock,flags);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    {
236906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johansson	unsigned int port = socket[sock].ioaddr;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char val = I365_REG(socket[sock].psock, reg);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(val, port); outb(data, port+1);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&bus_lock,flags);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void i365_bset(u_short sock, u_short reg, u_char mask)
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char d = i365_get(sock, reg);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    d |= mask;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, reg, d);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void i365_bclr(u_short sock, u_short reg, u_char mask)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char d = i365_get(sock, reg);
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    d &= ~mask;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, reg, d);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char d = i365_get(sock, reg);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (b)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d |= mask;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    else
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d &= ~mask;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, reg, d);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_short i365_get_pair(u_short sock, u_short reg)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_short a, b;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    a = i365_get(sock, reg);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    b = i365_get(sock, reg+1);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return (a + (b<<8));
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void i365_set_pair(u_short sock, u_short reg, u_short data)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, reg, data & 0xff);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, reg+1, data >> 8);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Code to save and restore global state information for Cirrus
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    PD67xx controllers, and to set and report global configuration
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    options.
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The VIA controllers also use these routines, as they are mostly
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Cirrus lookalikes, without the timing registers.
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cirrus_get_state(u_short s)
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int i;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    cirrus_state_t *p = &socket[s].state.cirrus;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    p->misc1 = i365_get(s, PD67_MISC_CTL_1);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    p->misc2 = i365_get(s, PD67_MISC_CTL_2);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (i = 0; i < 6; i++)
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cirrus_set_state(u_short s)
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int i;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char misc;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    cirrus_state_t *p = &socket[s].state.cirrus;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    misc = i365_get(s, PD67_MISC_CTL_2);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(s, PD67_MISC_CTL_2, p->misc2);
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (misc & PD67_MC2_SUSPEND) mdelay(50);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    misc = i365_get(s, PD67_MISC_CTL_1);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(s, PD67_MISC_CTL_1, misc | p->misc1);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (i = 0; i < 6; i++)
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int __init cirrus_set_opts(u_short s, char *buf)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct i82365_socket *t = &socket[s];
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    cirrus_state_t *p = &socket[s].state.cirrus;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_int mask = 0xffff;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (has_ring == -1) has_ring = 1;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring);
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (p->misc2 & PD67_MC2_IRQ15_RI)
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(buf, " [ring]");
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(buf, " [dyn mode]");
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (p->misc2 & PD67_MC2_FREQ_BYPASS)
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(buf, " [freq bypass]");
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (p->misc1 & PD67_MC1_INPACK_ENA)
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(buf, " [inpack]");
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (p->misc2 & PD67_MC2_IRQ15_RI)
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask &= ~0x8000;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (has_led > 0) {
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(buf, " [led]");
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask &= ~0x1000;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (has_dma > 0) {
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(buf, " [dma]");
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask &= ~0x0600;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (!(t->flags & IS_VIA)) {
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (setup_time >= 0)
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    p->timer[0] = p->timer[3] = setup_time;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmd_time > 0) {
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    p->timer[1] = cmd_time;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    p->timer[4] = cmd_time*2+4;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (p->timer[1] == 0) {
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    p->timer[1] = 6; p->timer[4] = 16;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (p->timer[0] == 0)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p->timer[0] = p->timer[3] = 1;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (recov_time >= 0)
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    p->timer[2] = p->timer[5] = recov_time;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf += strlen(buf);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1],
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p->timer[2], p->timer[3], p->timer[4], p->timer[5]);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return mask;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Code to save and restore global state information for Vadem VG468
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    and VG469 controllers, and to set and report global configuration
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    options.
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vg46x_get_state(u_short s)
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    vg46x_state_t *p = &socket[s].state.vg46x;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    p->ctl = i365_get(s, VG468_CTL);
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (socket[s].type == IS_VG469)
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->ema = i365_get(s, VG469_EXT_MODE);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vg46x_set_state(u_short s)
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    vg46x_state_t *p = &socket[s].state.vg46x;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(s, VG468_CTL, p->ctl);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (socket[s].type == IS_VG469)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_set(s, VG469_EXT_MODE, p->ema);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int __init vg46x_set_opts(u_short s, char *buf)
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    vg46x_state_t *p = &socket[s].state.vg46x;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    flip(p->ctl, VG468_CTL_ASYNC, async_clock);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    flip(p->ema, VG469_MODE_CABLE, cable_mode);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (p->ctl & VG468_CTL_ASYNC)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(buf, " [async]");
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (p->ctl & VG468_CTL_INPACK)
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcat(buf, " [inpack]");
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (socket[s].type == IS_VG469) {
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char vsel = i365_get(s, VG469_VSELECT);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vsel & VG469_VSEL_EXT_STAT) {
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    strcat(buf, " [ext mode]");
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (vsel & VG469_VSEL_EXT_BUS)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcat(buf, " [isa buf]");
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (p->ema & VG469_MODE_CABLE)
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    strcat(buf, " [cable]");
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (p->ema & VG469_MODE_COMPAT)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    strcat(buf, " [c step]");
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return 0xffff;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Generic routines to get and set controller options
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void get_bridge_state(u_short s)
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct i82365_socket *t = &socket[s];
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (t->flags & IS_CIRRUS)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cirrus_get_state(s);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    else if (t->flags & IS_VADEM)
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vg46x_get_state(s);
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_bridge_state(u_short s)
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct i82365_socket *t = &socket[s];
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (t->flags & IS_CIRRUS)
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cirrus_set_state(s);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    else {
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_set(s, I365_GBLCTL, 0x00);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_set(s, I365_GENCTL, 0x00);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (t->flags & IS_VADEM)
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vg46x_set_state(s);
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int __init set_bridge_opts(u_short s, u_short ns)
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_short i;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_int m = 0xffff;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    char buf[128];
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (i = s; i < s+ns; i++) {
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (socket[i].flags & IS_ALIVE) {
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    printk(KERN_INFO "    host opts [%d]: already alive!\n", i);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    continue;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = '\0';
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	get_bridge_state(i);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (socket[i].flags & IS_CIRRUS)
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    m = cirrus_set_opts(i, buf);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (socket[i].flags & IS_VADEM)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    m = vg46x_set_opts(i, buf);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bridge_state(i);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "    host opts [%d]:%s\n", i,
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       (*buf) ? buf : " none");
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return m;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Interrupt testing code, for ISA and PCI interrupts
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic volatile u_int irq_hits;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_short irq_sock;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4817d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t i365_count_irq(int irq, void *dev)
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_get(irq_sock, I365_CSC);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    irq_hits++;
485c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski    pr_debug("i82365: -> hit on irq %d\n", irq);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return IRQ_HANDLED;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int __init test_irq(u_short sock, int irq)
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
491c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski    pr_debug("i82365:  testing ISA irq %d\n", irq);
492dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner    if (request_irq(irq, i365_count_irq, IRQF_PROBE_SHARED, "scan",
49313e87ec68641fd54f3fa04eef3419d034ed2115aAndrew Morton			i365_count_irq) != 0)
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    irq_hits = 0; irq_sock = sock;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    msleep(10);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (irq_hits) {
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(irq, i365_count_irq);
499c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski	pr_debug("i82365:    spurious hit!\n");
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Generate one interrupt */
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4));
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    udelay(1000);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    free_irq(irq, i365_count_irq);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* mask all interrupts */
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, I365_CSCINT, 0);
512c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski    pr_debug("i82365:    hits = %d\n", irq_hits);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return (irq_hits != 1);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_int __init isa_scan(u_short sock, u_int mask0)
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_int mask1 = 0;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int i;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __alpha__
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIC 0x4d0
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Don't probe level-triggered interrupts -- reserved for PCI */
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (do_scan) {
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bridge_state(sock);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_set(sock, I365_CSCINT, 0);
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++)
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0))
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask1 |= (1 << i);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++)
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0))
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask1 ^= (1 << i);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    printk(KERN_INFO "    ISA irqs (");
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (mask1) {
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("scanned");
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    } else {
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fallback: just find interrupts that aren't in use */
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++)
545dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner	    if ((mask0 & (1 << i)) && (_check_irq(i, IRQF_PROBE_SHARED) == 0))
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask1 |= (1 << i);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("default");
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If scan failed, default to polled status */
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    printk(") = ");
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (i = 0; i < 16; i++)
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mask1 & (1<<i))
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (mask1 == 0) printk("none!");
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return mask1;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Time conversion functions */
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int to_cycles(int ns)
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return ns/cycle_time;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
572906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johanssonstatic int __init identify(unsigned int port, u_short sock)
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char val;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int type = -1;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Use the next free entry in the socket table */
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    socket[sockets].ioaddr = port;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    socket[sockets].psock = sock;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Wake up a sleepy Cirrus controller */
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (wakeup) {
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Pause at least 50 ms */
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay(50);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    switch (val) {
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    case 0x82:
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type = IS_I82365A; break;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    case 0x83:
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type = IS_I82365B; break;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    case 0x84:
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type = IS_I82365DF; break;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    case 0x88: case 0x89: case 0x8a:
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type = IS_IBM; break;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Check for Vadem VG-468 chips */
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    outb(0x0e, port);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    outb(0x37, port);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    val = i365_get(sockets, I365_IDENT);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (val & I365_IDENT_VADEM) {
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Check for Ricoh chips */
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    val = i365_get(sockets, RF5C_CHIP_ID);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type = IS_RF5Cx96;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Check for Cirrus CL-PD67xx chips */
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sockets, PD67_CHIP_INFO, 0);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    val = i365_get(sockets, PD67_CHIP_INFO);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = i365_get(sockets, PD67_CHIP_INFO);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((val & PD67_INFO_CHIP_ID) == 0) {
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    i365_set(sockets, PD67_EXT_INDEX, 0xe5);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5)
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = IS_VT83C469;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return type;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* identify */
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    See if a card is present, powered up, in IO mode, and already
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    bound to a (non PC Card) Linux driver.  We leave these alone.
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    We make an exception for cards that seem to be serial devices.
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init is_alive(u_short sock)
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char stat;
643906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johansson    unsigned int start, stop;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    stat = i365_get(sock, I365_STATUS);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
651f354942cb301fed273f423fb5c4f57bde3efc5b2Dominik Brodowski	((start & 0xfeef) != 0x02e8)) {
652f354942cb301fed273f423fb5c4f57bde3efc5b2Dominik Brodowski	if (!request_region(start, stop-start+1, "i82365"))
653f354942cb301fed273f423fb5c4f57bde3efc5b2Dominik Brodowski	    return 1;
654f354942cb301fed273f423fb5c4f57bde3efc5b2Dominik Brodowski	release_region(start, stop-start+1);
655f354942cb301fed273f423fb5c4f57bde3efc5b2Dominik Brodowski    }
656f354942cb301fed273f423fb5c4f57bde3efc5b2Dominik Brodowski
657f354942cb301fed273f423fb5c4f57bde3efc5b2Dominik Brodowski    return 0;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
662906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johanssonstatic void __init add_socket(unsigned int port, int psock, int type)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    socket[sockets].ioaddr = port;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    socket[sockets].psock = psock;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    socket[sockets].type = type;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    socket[sockets].flags = pcic[type].flags;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (is_alive(sockets))
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	socket[sockets].flags |= IS_ALIVE;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    sockets++;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init add_pcic(int ns, int type)
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_int mask = 0, i, base;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int isa_irq = 0;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct i82365_socket *t = &socket[sockets-ns];
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    base = sockets-ns;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (base == 0) printk("\n");
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    printk(KERN_INFO "  %s", pcic[type].name);
682906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johansson    printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       t->ioaddr, t->psock*0x40);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Set host options, build basic interrupt mask */
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (irq_list_count == 0)
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = irq_mask;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    else
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = mask = 0; i < irq_list_count; i++)
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    mask |= (1<<irq_list[i]);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    mask &= I365_MASK & set_bridge_opts(base, ns);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Scan for ISA interrupts */
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    mask = isa_scan(base, mask);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Poll if only two interrupts available */
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (!poll_interval) {
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int tmp = (mask & 0xff20);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tmp & (tmp-1);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((tmp & (tmp-1)) == 0)
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    poll_interval = HZ;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Only try an ISA cs_irq if this is the first controller */
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (!grab_irq && (cs_irq || !poll_interval)) {
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Avoid irq 12 unless it is explicitly requested */
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (cs_irq = 15; cs_irq > 0; cs_irq--)
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if ((cs_mask & (1 << cs_irq)) &&
709dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner		(_check_irq(cs_irq, IRQF_PROBE_SHARED) == 0))
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs_irq) {
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    grab_irq = 1;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    isa_irq = cs_irq;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    printk(" status change on irq %d\n", cs_irq);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (!isa_irq) {
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (poll_interval == 0)
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    poll_interval = HZ;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(" polling interval = %d ms\n",
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       poll_interval * 1000 / HZ);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Update socket interrupt information, capabilities */
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (i = 0; i < ns; i++) {
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t[i].socket.features |= SS_CAP_PCCARD;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t[i].socket.map_size = 0x1000;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t[i].socket.irq_mask = mask;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t[i].cs_irq = isa_irq;
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* add_pcic */
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PNP
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct isapnp_device_id id_table[] __initdata = {
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" },
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" },
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" },
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{	0 }
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(isapnp, id_table);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pnp_dev *i82365_pnpdev;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init isa_probe(void)
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int i, j, sock, k, ns, id;
756906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johansson    unsigned int port;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PNP
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct isapnp_device_id *devid;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct pnp_dev *dev;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (devid = id_table; devid->vendor; devid++) {
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev = pnp_find_dev(NULL, devid->vendor, devid->function, NULL))) {
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (pnp_device_attach(dev) < 0)
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    	continue;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (pnp_activate_dev(dev) < 0) {
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("activate failed\n");
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_device_detach(dev);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (!pnp_port_valid(dev, 0)) {
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("invalid resources ?\n");
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_device_detach(dev);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    i365_base = pnp_port_start(dev, 0);
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    i82365_pnpdev = dev;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    break;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
785f354942cb301fed273f423fb5c4f57bde3efc5b2Dominik Brodowski    if (!request_region(i365_base, 2, "i82365")) {
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sockets == 0)
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    printk("port conflict at %#lx\n", i365_base);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    id = identify(i365_base, 0);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) {
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 4; i++) {
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (i == ignore) continue;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    sock = (i & 1) << 1;
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (identify(port, sock) == IS_I82365DF) {
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_socket(port, sock, IS_VLSI);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_pcic(1, IS_VLSI);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    } else {
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 8; i += 2) {
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (sockets && !extra_sockets && (i == 4))
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    port = i365_base + 2*(i>>2);
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    sock = (i & 3);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    id = identify(port, sock);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (id < 0) continue;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    for (j = ns = 0; j < 2; j++) {
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Does the socket exist? */
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ignore == i+j) || (identify(port, sock+j) < 0))
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    continue;
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check for bad socket decode */
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (k = 0; k <= sockets; k++)
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    i365_set(k, I365_MEM(0)+I365_W_OFF, k);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (k = 0; k <= sockets; k++)
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (k <= sockets) break;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_socket(port, sock+j, id); ns++;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (ns != 0) add_pcic(ns, id);
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8317d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t pcic_interrupt(int irq, void *dev)
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int i, j, csc;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_int events, active;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_long flags = 0;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int handled = 0;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
838c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski    pr_debug("pcic_interrupt(%d)\n", irq);
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (j = 0; j < 20; j++) {
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	active = 0;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < sockets; i++) {
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (socket[i].cs_irq != irq)
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		continue;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    handled = 1;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    ISA_LOCK(i, flags);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    csc = i365_get(i, I365_CSC);
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if ((csc == 0) || (i365_get(i, I365_IDENT) & 0x70)) {
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ISA_UNLOCK(i, flags);
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		continue;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    else {
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    ISA_UNLOCK(i, flags);
862c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski	    pr_debug("socket %d event 0x%02x\n", i, events);
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (events)
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pcmcia_parse_events(&socket[i].socket, events);
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    active |= events;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!active) break;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (j == 20)
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
874c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski    pr_debug("pcic_interrupt done\n");
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return IRQ_RETVAL(handled);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* pcic_interrupt */
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pcic_interrupt_wrapper(u_long data)
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8807d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells    pcic_interrupt(0, NULL);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    poll_timer.expires = jiffies + poll_interval;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    add_timer(&poll_timer);
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i365_get_status(u_short sock, u_int *value)
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_int status;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    status = i365_get(sock, I365_STATUS);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	? SS_DETECT : 0;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    else {
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    *value |= (status & I365_CS_READY) ? SS_READY : 0;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (socket[sock].type == IS_VG469) {
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = i365_get(sock, VG469_VSENSE);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (socket[sock].psock & 1) {
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
916c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski    pr_debug("GetStatus(%d) = %#4.4x\n", sock, *value);
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return 0;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* i365_get_status */
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i365_set_socket(u_short sock, socket_state_t *state)
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct i82365_socket *t = &socket[sock];
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char reg;
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
927c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski    pr_debug("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* First set global controller options */
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    set_bridge_state(sock);
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* IO card, RESET flag, IO interrupt */
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    reg = t->intr;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    reg |= state->io_irq;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, I365_INTCTL, reg);
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    reg = I365_PWR_NORESET;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (t->flags & IS_CIRRUS) {
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->Vpp != 0) {
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (state->Vpp == 120)
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg |= I365_VPP1_12V;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    else if (state->Vpp == state->Vcc)
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg |= I365_VPP1_5V;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    else return -EINVAL;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->Vcc != 0) {
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    reg |= I365_VCC_5V;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (state->Vcc == 33)
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    else if (state->Vcc == 50)
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    else return -EINVAL;
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    } else if (t->flags & IS_VG_PWR) {
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->Vpp != 0) {
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (state->Vpp == 120)
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg |= I365_VPP1_12V;
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    else if (state->Vpp == state->Vcc)
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg |= I365_VPP1_5V;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    else return -EINVAL;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->Vcc != 0) {
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    reg |= I365_VCC_5V;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (state->Vcc == 33)
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    else if (state->Vcc == 50)
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    else return -EINVAL;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    } else if (t->flags & IS_DF_PWR) {
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (state->Vcc) {
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:		break;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 33:   	reg |= I365_VCC_3V; break;
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 50:	reg |= I365_VCC_5V; break;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:	return -EINVAL;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (state->Vpp) {
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:		break;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 50:   	reg |= I365_VPP1_5V; break;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 120:	reg |= I365_VPP1_12V; break;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:	return -EINVAL;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    } else {
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (state->Vcc) {
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:		break;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 50:	reg |= I365_VCC_5V; break;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:	return -EINVAL;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (state->Vpp) {
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:		break;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 50:	reg |= I365_VPP1_5V | I365_VPP2_5V; break;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 120:	reg |= I365_VPP1_12V | I365_VPP2_12V; break;
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:	return -EINVAL;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (reg != i365_get(sock, I365_POWER))
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_set(sock, I365_POWER, reg);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Chipset-specific functions */
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (t->flags & IS_CIRRUS) {
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Speaker control */
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   state->flags & SS_SPKR_ENA);
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Card status change interrupt mask */
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    reg = t->cs_irq << 4;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (state->flags & SS_IOCARD) {
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    } else {
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, I365_CSCINT, reg);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_get(sock, I365_CSC);
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return 0;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* i365_set_socket */
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i365_set_io_map(u_short sock, struct pccard_io_map *io)
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char map, ioctl;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1036c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski    pr_debug("SetIOMap(%d, %d, %#2.2x, %d ns, "
103701373046612d2bbd01064c3beaf18ff3338dafaeRandy Dunlap	  "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed,
103801373046612d2bbd01064c3beaf18ff3338dafaeRandy Dunlap	  (unsigned long long)io->start, (unsigned long long)io->stop);
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    map = io->map;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(io->stop < io->start)) return -EINVAL;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Turn off the window before changing anything */
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set(sock, I365_IOCTL, ioctl);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Turn on the window if necessary */
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (io->flags & MAP_ACTIVE)
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return 0;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* i365_set_io_map */
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_short base, i;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    u_char map;
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1066c9f50dddd184a020d64dab63fa795967f0f14aa4Dominik Brodowski    pr_debug("SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, "
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  "%#x)\n", sock, mem->map, mem->flags, mem->speed,
1068490ab72af6a7a74b1d77e8f1b67fdfad04371876Greg Kroah-Hartman	  (unsigned long long)mem->res->start,
1069490ab72af6a7a74b1d77e8f1b67fdfad04371876Greg Kroah-Hartman	  (unsigned long long)mem->res->end, mem->card_start);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    map = mem->map;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if ((map > 4) || (mem->card_start > 0x3ffffff) ||
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(mem->res->start > mem->res->end) || (mem->speed > 1000))
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff))
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Turn off the window before changing anything */
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    base = I365_MEM(map);
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i = (mem->res->start >> 12) & 0x0fff;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set_pair(sock, base+I365_W_START, i);
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i = (mem->res->end >> 12) & 0x0fff;
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    switch (to_cycles(mem->speed)) {
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    case 0:	break;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    case 1:	i |= I365_MEM_WS0; break;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    case 2:	i |= I365_MEM_WS1; break;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    default:	i |= I365_MEM_WS1 | I365_MEM_WS0; break;
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set_pair(sock, base+I365_W_STOP, i);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i365_set_pair(sock, base+I365_W_OFF, i);
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Turn on the window if necessary */
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (mem->flags & MAP_ACTIVE)
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return 0;
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* i365_set_mem_map */
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 /* driver model ordering issue */
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Routines for accessing socket information and register dumps via
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /sys/class/pcmcia_socket/...
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_info(struct class_device *class_dev, char *buf)
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "type:     %s\npsock:    %d\n",
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       pcic[s->type].name, s->psock);
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_exca(struct class_device *class_dev, char *buf)
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short sock;
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t ret = 0;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags = 0;
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock = s->number;
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ISA_LOCK(sock, flags);
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 0x40; i += 4) {
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret += sprintf(buf, "%02x %02x %02x %02x%s",
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       i365_get(sock,i), i365_get(sock,i+1),
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       i365_get(sock,i+2), i365_get(sock,i+3),
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ((i % 16) == 12) ? "\n" : " ");
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += ret;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ISA_UNLOCK(sock, flags);
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* this is horribly ugly... proper locking needs to be done here at
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * some time... */
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOCKED(x) do { \
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval; \
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags; \
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&isa_lock, flags); \
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = x; \
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&isa_lock, flags); \
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval; \
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pcic_get_status(struct pcmcia_socket *s, u_int *value)
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (socket[sock].flags & IS_ALIVE) {
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*value = 0;
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LOCKED(i365_get_status(sock, value));
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state)
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (socket[sock].flags & IS_ALIVE)
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LOCKED(i365_set_socket(sock, state));
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pcic_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (socket[sock].flags & IS_ALIVE)
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LOCKED(i365_set_io_map(sock, io));
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pcic_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (socket[sock].flags & IS_ALIVE)
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LOCKED(i365_set_mem_map(sock, mem));
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pcic_init(struct pcmcia_socket *s)
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct resource res = { .start = 0, .end = 0x1000 };
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pccard_io_map io = { 0, 0, 0, 0, 1 };
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pccard_mem_map mem = { .res = &res, };
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 2; i++) {
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		io.map = i;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pcic_set_io_map(s, &io);
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 5; i++) {
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mem.map = i;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pcic_set_mem_map(s, &mem);
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12227a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pccard_operations pcic_operations = {
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init			= pcic_init,
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_status		= pcic_get_status,
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_socket		= pcic_set_socket,
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_io_map		= pcic_set_io_map,
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_mem_map		= pcic_set_mem_map,
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12337a192ec334cab9fafe3a8665a65af398b0e24730Ming Leistatic struct platform_driver i82365_driver = {
12347a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei	.driver = {
12357a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei		.name = "i82365",
12367a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei		.owner		= THIS_MODULE,
12377a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei	},
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1240dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowskistatic struct platform_device *i82365_device;
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_i82365(void)
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int i, ret;
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12467a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei    ret = platform_driver_register(&i82365_driver);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (ret)
12482df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	goto err_out;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1250dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowski    i82365_device = platform_device_alloc("i82365", 0);
1251dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowski    if (i82365_device) {
1252dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowski	    ret = platform_device_add(i82365_device);
1253dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowski	    if (ret)
1254dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowski		    platform_device_put(i82365_device);
1255dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowski    } else
1256dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowski	    ret = -ENOMEM;
1257dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowski
12582df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza    if (ret)
12592df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	goto err_driver_unregister;
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    printk(KERN_INFO "Intel ISA PCIC probe: ");
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    sockets = 0;
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    isa_probe();
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (sockets == 0) {
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("not found.\n");
12682df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	ret = -ENODEV;
12692df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	goto err_dev_unregister;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Set up interrupt handler(s) */
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (grab_irq != 0)
12742df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
12752df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza
12762df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza    if (ret)
12772df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	goto err_socket_release;
12782df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* register sockets with the pcmcia core */
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (i = 0; i < sockets; i++) {
1281873733188a019acdb7fa253011cbdc0a8afd97f3Greg Kroah-Hartman	    socket[i].socket.dev.parent = &i82365_device->dev;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    socket[i].socket.ops = &pcic_operations;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    socket[i].socket.resource_ops = &pccard_nonstatic_ops;
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    socket[i].socket.owner = THIS_MODULE;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    socket[i].number = i;
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    ret = pcmcia_register_socket(&socket[i].socket);
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (!ret)
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    socket[i].flags |= IS_REGISTERED;
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 /* driver model ordering issue */
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   class_device_create_file(&socket[i].socket.dev,
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   	    &class_device_attr_info);
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   class_device_create_file(&socket[i].socket.dev,
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   	    &class_device_attr_exca);
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Finally, schedule a polling interrupt */
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (poll_interval != 0) {
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	poll_timer.function = pcic_interrupt_wrapper;
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	poll_timer.data = 0;
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&poll_timer);
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    	poll_timer.expires = jiffies + poll_interval;
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&poll_timer);
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    return 0;
13082df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenzaerr_socket_release:
13092df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza    for (i = 0; i < sockets; i++) {
13102df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	/* Turn off all interrupt sources! */
13112df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	i365_set(i, I365_CSCINT, 0);
13122df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	release_region(socket[i].ioaddr, 2);
13132df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza    }
13142df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenzaerr_dev_unregister:
13152df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza    platform_device_unregister(i82365_device);
13162df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza    release_region(i365_base, 2);
13172df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza#ifdef CONFIG_PNP
13182df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza    if (i82365_pnpdev)
13192df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza	pnp_disable_dev(i82365_pnpdev);
13202df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza#endif
13212df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenzaerr_driver_unregister:
13227a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei    platform_driver_unregister(&i82365_driver);
13232df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenzaerr_out:
13242df697036ba69ea99b73a2dbf82dcc8fec62d4abLeonardo Potenza    return ret;
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* init_i82365 */
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_i82365(void)
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int i;
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (i = 0; i < sockets; i++) {
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (socket[i].flags & IS_REGISTERED)
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    pcmcia_unregister_socket(&socket[i].socket);
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
1335dfb279c97510da659816f4f055146bb1f9f0a870Dominik Brodowski    platform_device_unregister(i82365_device);
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (poll_interval != 0)
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(&poll_timer);
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (grab_irq != 0)
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(cs_irq, pcic_interrupt);
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    for (i = 0; i < sockets; i++) {
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Turn off all interrupt sources! */
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i365_set(i, I365_CSCINT, 0);
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(socket[i].ioaddr, 2);
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
1345f354942cb301fed273f423fb5c4f57bde3efc5b2Dominik Brodowski    release_region(i365_base, 2);
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PNP
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (i82365_pnpdev)
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    		pnp_disable_dev(i82365_pnpdev);
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
13507a192ec334cab9fafe3a8665a65af398b0e24730Ming Lei    platform_driver_unregister(&i82365_driver);
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* exit_i82365 */
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_i82365);
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(exit_i82365);
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("Dual MPL/GPL");
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
1357