Pull in John Kohl's [jtk@netbsd.org] most recent (15Apr96) APM and PCMCIA work
authorhvozda <hvozda@openbsd.org>
Mon, 29 Apr 1996 14:12:01 +0000 (14:12 +0000)
committerhvozda <hvozda@openbsd.org>
Mon, 29 Apr 1996 14:12:01 +0000 (14:12 +0000)
(original PCMCIA framework  by Stefan Grefen [grefen@convex.com]).

43 files changed:
sys/arch/i386/apm_init/Makefile [new file with mode: 0644]
sys/arch/i386/apm_init/Makefile.inc [new file with mode: 0644]
sys/arch/i386/apm_init/apm_bios.h [new file with mode: 0644]
sys/arch/i386/apm_init/apm_init.S [new file with mode: 0644]
sys/arch/i386/apm_init/apm_segments.h [new file with mode: 0644]
sys/arch/i386/apm_init/apm_setup.h [new file with mode: 0644]
sys/arch/i386/apm_init/bin2asm.sh [new file with mode: 0644]
sys/arch/i386/apm_init/real_prot.S [new file with mode: 0644]
sys/arch/i386/apm_init/real_prot.h [new file with mode: 0644]
sys/arch/i386/apm_init/rmaouthdr [new file with mode: 0644]
sys/arch/i386/apm_init/table.c [new file with mode: 0644]
sys/arch/i386/conf/HELIOS_PCMCIA
sys/arch/i386/conf/Makefile.i386
sys/arch/i386/conf/PCMCIA [new file with mode: 0644]
sys/arch/i386/conf/files.i386
sys/arch/i386/i386/apm.c [new file with mode: 0644]
sys/arch/i386/i386/conf.c
sys/arch/i386/i386/gdt.c
sys/arch/i386/i386/genassym.c
sys/arch/i386/i386/locore.s
sys/arch/i386/i386/machdep.c
sys/arch/i386/i386/mainbus.c
sys/arch/i386/include/apmvar.h [new file with mode: 0644]
sys/arch/i386/include/gdt.h
sys/arch/i386/include/segments.h
sys/dev/ic/com.c
sys/dev/ic/i82365reg.h
sys/dev/isa/com.c
sys/dev/isa/files.isa
sys/dev/isa/if_ed.c
sys/dev/isa/if_ep.c
sys/dev/isa/pcmcia_isa.c
sys/dev/isa/pcmcia_pcic.c
sys/dev/isa/wd.c
sys/dev/pcmcia/files.pcmcia
sys/dev/pcmcia/pcmcia.c
sys/dev/pcmcia/pcmcia_conf.c
sys/dev/pcmcia/pcmcia_ioctl.h
sys/dev/pcmcia/pcmciabus.h [deleted file]
sys/dev/pcmcia/pcmciareg.h [new file with mode: 0644]
sys/dev/pcmcia/pcmciavar.h [new file with mode: 0644]
sys/kern/subr_autoconf.c
sys/sys/device.h

diff --git a/sys/arch/i386/apm_init/Makefile b/sys/arch/i386/apm_init/Makefile
new file mode 100644 (file)
index 0000000..44e521e
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# LP (Laptop Package)
+#
+# (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+#
+# This software may be used, modified, copied, and distributed in
+# both source and binary form provided that the above copyright and
+# these terms are retained. Under no circumstances is the author 
+# responsible for the proper functioning of this software, nor does 
+# the author assume any responsibility for damages incurred with its 
+# use.
+#
+# Sep., 1994   Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+# Oct., 1994   NetBSD port (1.0 BETA 10/2) by ukai
+# Dec., 1995   NetBSD 1.1 kernel build retrofit, jtk@netbsd.org
+#
+
+DIR=${APMREL}${APMDIR}
+
+.if exists (${DIR}/arch/${MACHINE_ARCH}/Makefile.inc)
+.PATH: ${DIR}/arch/${MACHINE_ARCH}
+.include "${DIR}/arch/${MACHINE_ARCH}/Makefile.inc"
+.endif
+
+.PATH: ${DIR}
+
+CC = ${APMCC}
+CFLAGS += -DINITIALIZER        -I${DIR} -DKERNEL \
+       ${APMCFLAGS:S@-I.@-I${KERNREL}.@g}
+
+OBJS = apm_init.o real_prot.o table.o
+
+#.SUFFIXES: .c .S .o
+#
+#.c.o:
+#      $(CC)  $(CFLAGS) $(OPTFLAGS) $(INC) -c $<
+#
+.S.o:
+       $(CC)  $(CFLAGS) $(INC) -c $<
+
+apm_init.inc: apm_init
+       sh ${DIR}/bin2asm.sh apm_init > apm_init.inc
+
+apm_init: $(OBJS)
+       $(LD) -Bstatic -N -T 0 -o apm_init $(OBJS)
+       cp apm_init apm_init.sym
+       @strip apm_init
+       @sh ${DIR}/rmaouthdr apm_init apm_init.tmp
+       @mv -f apm_init.tmp apm_init
+
+#allclean: clean
+#      @rm -f apm_init.inc
+clean:
+       rm -f *.o apm_init apm_init.sym apm_init.inc
+
+#.include <bsd.prog.mk>
diff --git a/sys/arch/i386/apm_init/Makefile.inc b/sys/arch/i386/apm_init/Makefile.inc
new file mode 100644 (file)
index 0000000..715da60
--- /dev/null
@@ -0,0 +1,39 @@
+#      $NetBSD: Makefile.inc,v 1.12 1995/10/07 09:56:55 mycroft Exp $
+#
+#      NOTE: $S must correspond to the top of the 'sys' tree
+
+APMDIR=        ${I386}/apm_init
+
+APMDST=        lib/apm_init
+APMREL?=       ../../
+APMINC?=       ${APMDST}/apm_init.inc
+
+APMDEPS= \
+       ${APMDIR}/Makefile \
+       ${APMDIR}/apm_bios.h \
+       ${APMDIR}/apm_init.S \
+       ${APMDIR}/apm_segments.h \
+       ${APMDIR}/bin2asm.sh \
+       ${APMDIR}/real_prot.S \
+       ${APMDIR}/real_prot.h \
+       ${APMDIR}/rmaouthdr \
+       ${APMDIR}/table.c
+
+${APMINC}:     ${APMDEPS} ${APMDST}
+       @echo making sure the apm grappling hook is up to date...
+       @(cd ${APMDST} && ${MAKE} -f ${APMREL}${APMDIR}/Makefile \
+         APMCC="${CC}" \
+         APMCFLAGS="${CFLAGS}" \
+         APMREL="${APMREL}" \
+         APMDIR="${APMDIR}" apm_init.inc)
+
+clean::                .NOTMAIN __always_make_apmlib
+       @echo cleaning the apm grappling hook objects
+       @(cd ${APMDST} && ${MAKE} -f ${APMREL}${APMDIR}/Makefile \
+         APMCC="${CC}" \
+         APMCFLAGS="${CFLAGS}" \
+         APMREL="${APMREL}" \
+         APMDIR="${APMDIR}" clean)
+
+${APMDST} __always_make_apmlib:        .NOTMAIN
+       @([ -d ${APMDST} ] || mkdir -p ${APMDST})
diff --git a/sys/arch/i386/apm_init/apm_bios.h b/sys/arch/i386/apm_init/apm_bios.h
new file mode 100644 (file)
index 0000000..5354b9c
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Advanced Power Management (APM) BIOS driver for laptop PCs.
+ * 
+ * Copyright (c) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, and distributed, in
+ * both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author 
+ * responsible for the proper functioning of this software, nor does 
+ * the author assume any responsibility for damages incurred with its 
+ * use.
+ *
+ * Aug, 1994   Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ * Oct, 1994   NetBSD port (1.0 BETA 10/2) by ukai
+ */
+
+#ifndef APM_BIOS_H 
+#define APM_BIOS_H     1
+
+#ifdef KERNEL
+
+/* BIOS id */
+#define APM_BIOS               0x53
+#define SYSTEM_BIOS            0x15
+
+/* APM flags */
+#define APM_16BIT_SUPPORT      0x01
+#define APM_32BIT_SUPPORT      0x02
+#define APM_CPUIDLE_SLOW       0x04
+#define APM_DISABLED           0x08
+#define APM_DISENGAGED         0x10
+
+/* APM initializer physical address */
+#define APM_OURADDR            0x00080000
+
+/* Error code of APM initializer */
+#define APMINI_CANTFIND                0xffffffff
+#define APMINI_NOT32BIT                0xfffffffe
+#define APMINI_CONNECTERR      0xfffffffd
+#define APMINI_BADVER          0xfffffffc
+
+/* APM functions */
+#define APM_INSTCHECK          0x00
+#define APM_REALCONNECT                0x01
+#define APM_PROT16CONNECT      0x02
+#define APM_PROT32CONNECT      0x03
+#define APM_DISCONNECT         0x04
+#define APM_CPUIDLE            0x05
+#define APM_CPUBUSY            0x06
+#define APM_SETPWSTATE         0x07
+#define APM_ENABLEDISABLEPM    0x08
+#define APM_RESTOREDEFAULT     0x09
+#define        APM_GETPWSTATUS         0x0a
+#define APM_GETPMEVENT         0x0b
+#define APM_GETPWSTATE         0x0c
+#define APM_ENABLEDISABLEDPM   0x0d
+#define APM_DRVVERSION         0x0e
+#define APM_ENGAGEDISENGAGEPM  0x0f
+#define APM_OEMFUNC            0x80
+
+/* error code */
+#define APME_OK                        0x00
+#define APME_PMDISABLED                0x01
+#define APME_REALESTABLISHED   0x02
+#define APME_NOTCONNECTED      0x03
+#define APME_PROT16ESTABLISHED 0x05
+#define APME_PROT16NOTSUPPORTED        0x06
+#define APME_PROT32ESTABLISHED 0x07
+#define APME_PROT32NOTDUPPORTED        0x08
+#define APME_UNKNOWNDEVICEID   0x09
+#define APME_OUTOFRANGE                0x0a
+#define APME_NOTENGAGED                0x0b
+#define APME_CANTENTERSTATE    0x60
+#define APME_NOPMEVENT         0x80
+#define APME_NOAPMPRESENT      0x86
+
+
+/* device code */
+#define PMDV_APMBIOS           0x0000
+#define PMDV_ALLDEV            0x0001
+#define PMDV_DISP0             0x0100
+#define PMDV_DISP1             0x0101
+#define PMDV_2NDSTORAGE0       0x0200
+#define PMDV_2NDSTORAGE1       0x0201
+#define PMDV_2NDSTORAGE2       0x0202
+#define PMDV_2NDSTORAGE3       0x0203
+#define PMDV_PARALLEL0         0x0300
+#define PMDV_PARALLEL1         0x0301
+#define PMDV_SERIAL0           0x0400
+#define PMDV_SERIAL1           0x0401
+#define PMDV_SERIAL2           0x0402
+#define PMDV_SERIAL3           0x0403
+#define PMDV_SERIAL4           0x0404
+#define PMDV_SERIAL5           0x0405
+#define PMDV_SERIAL6           0x0406
+#define PMDV_SERIAL7           0x0407
+#define PMDV_NET0              0x0500
+#define PMDV_NET1              0x0501
+#define PMDV_NET2              0x0502
+#define PMDV_NET3              0x0503
+#define PMDV_PCMCIA0           0x0600
+#define PMDV_PCMCIA1           0x0601
+#define PMDV_PCMCIA2           0x0602
+#define PMDV_PCMCIA3           0x0603
+/* 0x0700 - 0xdfff     Reserved                        */
+/* 0xe000 - 0xefff     OEM-defined power device IDs    */
+/* 0xf000 - 0xffff     Reserved                        */
+
+/* Power state */
+#define PMST_APMENABLED                0x0000
+#define PMST_STANDBY           0x0001
+#define PMST_SUSPEND           0x0002
+#define PMST_OFF               0x0003
+#define PMST_LASTREQNOTIFY     0x0004
+#define PMST_LASTREQREJECT     0x0005
+/* 0x0006 - 0x001f     Reserved system states          */
+/* 0x0020 - 0x003f     OEM-defined system states       */
+/* 0x0040 - 0x007f     OEM-defined device states       */
+/* 0x0080 - 0xffff     Reserved device states          */
+
+#if !defined(ASM) && !defined(INITIALIZER)
+
+/* C definitions */
+typedef struct apm_hook_func {
+       struct apm_hook_func    *next;          /* Linked list */
+       int                     (*func)(void);
+       const char              *name;
+       int                     order; 
+} *apm_hook_func_t;
+
+apm_hook_func_t apm_resume_hook_init(int (*func)(void), char *name, int order);
+void apm_resume_hook_delete(apm_hook_func_t delete_func);
+apm_hook_func_t apm_suspend_hook_init(int (*func)(void), char *name, int order);
+void apm_suspend_hook_delete(apm_hook_func_t delete_func);
+void apm_suspend_resume(void);
+void apm_cpu_idle(void);
+void apm_cpu_busy(void);
+
+#endif /* !ASM && !INITIALIZER */
+
+#define APM_MIN_ORDER          0x00
+#define APM_MID_ORDER          0x80
+#define APM_MAX_ORDER          0xff
+
+#endif /* KERNEL */
+
+/* power management event code */
+#define PMEV_NOEVENT           0x0000
+#define PMEV_STANDBYREQ                0x0001
+#define PMEV_SUSPENDREQ                0x0002
+#define PMEV_NORMRESUME                0x0003
+#define PMEV_CRITRESUME                0x0004
+#define PMEV_BATTERYLOW                0x0005
+#define PMEV_POWERSTATECHANGE  0x0006
+#define PMEV_UPDATETIME                0x0007
+#define PMEV_CRITSUSPEND       0x0008
+#define PMEV_USERSTANDBYREQ    0x0009
+#define PMEV_USERSUSPENDREQ    0x000a
+#define PMEV_STANDBYRESUME     0x000b
+/* 0x000c - 0x00ff     Reserved system events  */
+/* 0x0100 - 0x01ff     Reserved device events  */
+/* 0x0200 - 0x02ff     OEM-defined APM events  */
+/* 0x0300 - 0xffff     Reserved                */
+#define PMEV_DEFAULT           0xffffffff      /* used for customization */
+
+#if !defined(ASM) && !defined(INITIALIZER)
+
+typedef struct apm_info {
+       u_int   ai_major;       /* APM major version */
+       u_int   ai_minor;       /* APM minor version */
+       u_int   ai_acline;      /* AC line status */
+       u_int   ai_batt_stat;   /* Battery status */
+       u_int   ai_batt_life;   /* Remaining battery life */
+} *apm_info_t;
+
+#define APMIO_SUSPEND          _IO('P', 1)
+#define APMIO_GETINFO          _IOR('P', 2, struct apm_info)
+#define APMIO_ENABLE           _IO('P', 3)
+#define APMIO_DISABLE          _IO('P', 4)
+#define APMIO_HALTCPU          _IO('P', 5)
+#define APMIO_NOTHALTCPU       _IO('P', 6)
+
+#endif /* !ASM && !INITIALIZER */
+
+#endif /* APM_BIOS_H */
diff --git a/sys/arch/i386/apm_init/apm_init.S b/sys/arch/i386/apm_init/apm_init.S
new file mode 100644 (file)
index 0000000..945c251
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * LP (Laptop Package)
+ *
+ * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, and distributed, in
+ * both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author 
+ * responsible for the proper functioning of this software, nor does 
+ * the author assume any responsibility for damages incurred with its 
+ * use.
+ *
+ * Sep., 1994  Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ * Oct., 1994  NetBSD port (1.0 BETA 10/2) by ukai
+ */
+
+/*
+ * If you want to know the specification of APM BIOS, see the following
+ * documentations,
+ *
+ * [1] Intel Corporation and Microsoft Corporation, "Advanced Power 
+ *     Management, The Next Generation, Version 1.0", Feb.,1992.
+ *
+ * [2] Intel Corporation and Microsoft Corporation, "Advanced Power
+ *     Management (APM) BIOS Interface Specification Revision 1.1",
+ *     Sep.,1993, Intel Order Number: 241704-001, Microsoft Part
+ *     Number: 781-110-X01
+ *
+ * or contact
+ *
+ * APM Support Desk (Intel Corporation, US)
+ *   TEL: (800)628-8686 
+ *   FAX: (916)356-6100.
+ */
+
+       .file   "apm_init.S"
+
+#define ASM
+
+#include "real_prot.h"
+#include <apm_bios.h>
+#include <apm_segments.h>
+
+/*
+ * APM BIOS initializer
+ *
+ * Return value:
+ *     %eax    0xfffffff       Can't find APM BIOS
+ *             0xffffffe       Don't support 32bit connection
+ *             0xffffffd       Connection error
+ *             otherwise       APM version (16bit BCD format)
+ *     %ebx                    APM cs entry offset (32bit)
+ *     %ecx    lower 16bit     APM 16bit cs base (real mode segment)
+ *             upper 16bit     APM 32bit cs base (real mode segment)
+ *     %edx    lower 16bit     APM ds limit (real mode segment)
+ *             upper 16bit     [Reserved]
+ *     %esi    lower 16bit     APM cs limit (APM 1.1 or later)
+ *             upper 16bit     APM ds limit (APM 1.1 or later)
+ *     %edi    bit0 = 1        16bit protected mode interface supported
+ *             bit1 = 1        32bit protected mode interface supported
+ *             bit2 = 1        "CPU idle" call slows processor clock speed
+ *             bit3 = 1        APM BIOS Power Management disabled
+ *             bit4 = 1        APM BIOS Power Management disengaged
+ */
+
+       .text
+ENTRY(apm_init)
+       cli                             /* disable interrupt */
+       push    %ebp                    /* save original base pointer */
+                                       /* ebp is used as a register variable */
+       /* 
+        * save old data segments: We assume that %ds == %es && %ds == %ss
+        */
+       push    %fs
+       movw    %ds, %ax
+       movw    %ax, %fs
+       movw    $(APM_INIT_DS_SEL), %ax /* initializer data segment */
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %ss
+       movl    %esp, old_esp           /* save original stack pointer */
+       movl    $0xf000, %esp           /* setup temporary stack */
+                                       /* (note that it isn't 0x00000000) */
+
+       sidt    EXT(Idtr_prot)          /* save current IDT */
+       call    EXT(prot_to_real)       /* return to real mode */
+
+       /*
+        * APM installation check
+        */
+       movb    $(APM_BIOS), %ah
+       movb    $(APM_INSTCHECK), %al
+       data32
+       movl    $(PMDV_APMBIOS), %ebx
+       sti
+       int     $(SYSTEM_BIOS)          /* call system BIOS */
+       cli
+
+       jnc     1f                      /* if found, goto 1f */
+       
+       data32
+       call    EXT(real_to_prot)       /* come back again to protected mode */
+       movl    $(APMINI_CANTFIND), apm_version
+                                       /* can't find APM BIOS */
+       jmp     finish
+
+1:
+       movl    %eax, %edx              /* actually, movw %ax, %dx */
+                                       /* save the value of %ax */
+       data32
+       call    EXT(real_to_prot)       /* come back again to protected mode */
+       cmpb    $0x50, %bh              /* %bh == 'P'? */
+       jnz     1f
+       cmpb    $0x4d, %bl              /* %bl == 'M'? */
+       jz      2f
+
+1:
+       movl    $(APMINI_BADVER), apm_version
+                                       /* can't find APM BIOS */
+       jmp     finish
+
+2:
+       testl   $(APM_32BIT_SUPPORT), %ecx
+                                       /* supports 32bit connection? */
+       jnz     1f
+
+       movl    $(APMINI_NOT32BIT), apm_version
+                                       /* don't support 32bit connection */
+       jmp     finish
+1:
+       movl    %edx, apm_version
+       andl    $0x0000ffff, %ecx
+       movl    %ecx, apm_flags
+
+       /*
+        * APM Protected Mode 32-bit Interface Connect
+        */
+       call    EXT(prot_to_real)       /* return to real mode */
+
+       movb    $(APM_BIOS), %ah
+       movb    $(APM_DISCONNECT), %al  /* just in case bootloader connected*/
+       data32
+       movl    $(PMDV_APMBIOS), %ebx
+       sti
+       int     $(SYSTEM_BIOS)
+       cli
+       movb    $(APM_BIOS), %ah
+       movb    $(APM_PROT32CONNECT), %al
+       data32
+       movl    $(PMDV_APMBIOS), %ebx
+       sti
+       int     $(SYSTEM_BIOS)
+       cli
+       jnc     1f                      /* if successed, go to 1f */
+       data32
+       call    EXT(real_to_prot)
+       movl    $(APMINI_CONNECTERR), apm_version
+                                       /* connection error */
+       jmp     finish
+1:     
+       /* save PM 32bit code segment into %bp */
+       movl    %eax, %ebp              /* actually, movw %ax, %bp */
+       data32
+       call    EXT(real_to_prot)
+       movl    $0x0000ffff, %eax
+       andl    %eax, %ebp              /* 32bit cs base */
+       andl    %eax, %ecx              /* 16bit cs base */
+       andl    %eax, %edx              /* ds base */
+       andl    %eax, %esi              /* cs length (APM 1.1 or later) */
+       andl    %eax, %edi              /* ds length (APM 1.1 or later) */
+                                       /* %ebx is code offset */
+       /* pack 32bit cs and 16bit cs into %ecx */
+       shll    $16, %ebp
+       orl     %ebp, %ecx
+       /* pack cs length and ds length into %esi */
+       shll    $16, %edi
+       orl     %edi, %esi
+finish:
+       cli
+       lidt    EXT(Idtr_prot)          /* restore old IDTR */
+       movl    old_esp, %esp           /* restore old stack pointer */
+       movl    apm_version, %ebp       /* stored to %eax later */
+       movl    apm_flags, %edi
+#if 0
+       movw    $(BOOTSTRAP_DS_SEL), %ax
+                                       /* restore old data segments */
+#else
+       movw    %fs, %ax
+#endif
+       movw    %ax, %ss
+       movw    %ax, %es
+       movw    %ax, %ds
+       movl    %ebp, %eax
+       pop     %fs
+       popl    %ebp                    /* restore old base pointer */
+       lret                            /* restore old code segment */
+
+       .data
+
+       .globl  EXT(ouraddr)
+LEXT(ouraddr)
+       .long   APM_OURADDR
+
+old_esp:
+       .long   0
+apm_version:
+       .long   0
+apm_flags:
+       .long   0
+old_ds:
+       .word   0
+old_es:
+       .word   0
+old_ss:
+       .word   0
diff --git a/sys/arch/i386/apm_init/apm_segments.h b/sys/arch/i386/apm_init/apm_segments.h
new file mode 100644 (file)
index 0000000..5e5fcdb
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * LP (Laptop Package)
+ *
+ * Copyright (C) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, and distributed, in
+ * both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author 
+ * responsible for the proper functioning of this software, nor does 
+ * the author assume any responsibility for damages incurred with its 
+ * use.
+ *
+ * Sep., 1994  Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ */
+
+#define SIZEOF_GDT             8
+#define BOOTSTRAP_GDT_NUM      9
+
+#define APM_INIT_CS_INDEX      (BOOTSTRAP_GDT_NUM - 3)
+#define APM_INIT_DS_INDEX      (BOOTSTRAP_GDT_NUM - 2)
+#define APM_INIT_CS16_INDEX    (BOOTSTRAP_GDT_NUM - 1)
+#define APM_INIT_CS_SEL                (APM_INIT_CS_INDEX << 3)
+#define APM_INIT_DS_SEL                (APM_INIT_DS_INDEX << 3)
+#define APM_INIT_CS16_SEL      (APM_INIT_CS16_INDEX << 3)
+
+#define CS32_ATTRIB            0x4F9e
+#define CS16_ATTRIB            0x009e
+#define DS32_ATTRIB            0x4F92
+
+#define BOOTSTRAP_DS_SEL       0x10
diff --git a/sys/arch/i386/apm_init/apm_setup.h b/sys/arch/i386/apm_init/apm_setup.h
new file mode 100644 (file)
index 0000000..fdc380e
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * LP (Laptop Package)
+ *
+ * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, distributed, and sold,
+ * in both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author 
+ * responsible for the proper functioning of this software, nor does 
+ * the author assume any responsibility for damages incurred with its 
+ * use.
+ *
+ * Sep., 1994  Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ * Oct., 1994  NetBSD port (1.0 BETA 10/2) by ukai
+ */
+
+extern u_long  apm_version;
+extern u_long  apm_cs_entry;
+extern u_short apm_cs32_base;
+extern u_short apm_cs16_base;
+extern u_short apm_ds_base;
+extern u_short apm_cs_limit;
+extern u_short apm_ds_limit;
+extern u_short apm_flags;
diff --git a/sys/arch/i386/apm_init/bin2asm.sh b/sys/arch/i386/apm_init/bin2asm.sh
new file mode 100644 (file)
index 0000000..6694b49
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh -
+# bin2asm (binary to asm) shell script version by ukai
+#
+#
+if [ $# -lt 1 ]; then
+       echo 'usage: $0 [in]'
+       exit 1
+fi
+in=$1
+size=`ls -l ${in} | awk '{print $5}'`
+# Oops, must 8 byte align
+len=`expr \( $size + 8 \) / 8 \* 8` 
+
+echo "/* This file is automatically generated by bin2asm.sh */" 
+echo "/* Original file is '${in}' */"
+echo
+dd if=${in} bs=${len} conv=sync |\
+       hexdump -v -e '"        .byte   " 7/1 "0x%02x, " 1/1 " 0x%02x" "\n"'
+echo
+echo "/* Total size = $size -> $len */"
+echo "/* End of File */"
diff --git a/sys/arch/i386/apm_init/real_prot.S b/sys/arch/i386/apm_init/real_prot.S
new file mode 100644 (file)
index 0000000..5f9e97e
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ * 
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ * 
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ *     from: Mach, Revision 2.2  92/04/04  11:34:13  rpd
+ *     $Id: real_prot.S,v 1.1 1996/04/29 14:15:43 hvozda Exp $
+ */
+
+
+/*
+  Copyright 1988, 1989, 1990, 1991, 1992 
+   by Intel Corporation, Santa Clara, California.
+
+                All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * LP (Laptop Package)
+ *
+ * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, and distributed, in
+ * both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author 
+ * responsible for the proper functioning of this software, nor does 
+ * the author assume any responsibility for damages incurred with its 
+ * use.
+ *
+ * Sep., 1994  Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ * Oct., 1994  NetBSD port (1.0 BETA 10/2) by ukai
+ */
+
+/*
+ * Modified for APM BIOS initializer by HOSOKAWA Tatsumi
+ *
+ * See also locore.s. It supports these functions works correctly.
+ */
+
+       .file "real_prot.S"
+
+#include "real_prot.h"
+#include "apm_segments.h"
+
+CR0_PE_ON      =       0x1
+CR0_PE_OFF     =       0xfffffffe
+
+.globl _ouraddr
+       .text
+
+/*
+ *
+ * real_to_prot()
+ *     transfer from real mode to protected mode.
+ */
+
+ENTRY(real_to_prot)
+       /* guarantee that interrupt is disabled when in prot mode */
+       cli
+
+       /* 
+        * deleted for APM initializer by HOSOKAWA Tatsumi 
+        *                                <hosoakwa@mt.cs.keio.ac.jp>
+        */
+#if 0
+       /* load the gdtr */
+       addr32
+       data32
+       lgdt    EXT(Gdtr)
+#endif
+
+       /* set the PE bit of CR0 */
+       mov     %cr0, %eax
+
+       data32
+       or      $CR0_PE_ON, %eax
+       mov     %eax, %cr0 
+
+       /*
+        * make intrasegment jump to flush the processor pipeline and
+        * reload CS register
+        */
+       data32
+       ljmp    $(APM_INIT_CS_SEL), $xprot
+
+xprot:
+       /*
+        * we are in USE32 mode now
+        * set up the protected mode segment registers : DS, SS, ES
+        */
+       mov     $(APM_INIT_DS_SEL), %eax
+       movw    %ax, %ds
+       movw    %ax, %ss
+       movw    %ax, %es
+
+       /* load idtr so we can debug */
+       lidt    EXT(Idtr_prot)
+
+       ret
+
+/*
+ *
+ * prot_to_real()
+ *     transfer from protected mode to real mode
+ * 
+ */
+
+ENTRY(prot_to_real)
+
+       /* set up a dummy stack frame for the second seg change. */
+       movl    _ouraddr, %eax
+       sarl    $4, %eax
+       pushw   %ax
+       movw    $xreal, %ax     /* gas botches pushw $xreal - extra bytes 0, 0*/
+       pushw   %ax             /* decode to add %al, (%eax) (%al usually 0) */
+
+       /* Change to use16 mode. */
+       ljmp    $(APM_INIT_CS16_SEL), $x16
+
+x16:
+       /* clear the PE bit of CR0 */
+       mov     %cr0, %eax
+       data32
+       and     $CR0_PE_OFF, %eax
+       mov     %eax, %cr0
+
+       /*
+        * make intersegment jmp to flush the processor pipeline
+        * using the fake stack frame set up earlier
+        * and reload CS register
+        */
+       lret
+
+xreal:
+       /*
+        * we are in real mode now
+        * set up the real mode segment registers : DS, SS, ES
+        */
+       movw    %cs, %ax
+       movw    %ax, %ds
+       movw    %ax, %ss
+       movw    %ax, %es
+
+       /* load idtr so we can debug */
+       addr32
+       data32
+       lidt    EXT(Idtr_real)
+
+       data32
+       ret
diff --git a/sys/arch/i386/apm_init/real_prot.h b/sys/arch/i386/apm_init/real_prot.h
new file mode 100644 (file)
index 0000000..51e91cf
--- /dev/null
@@ -0,0 +1,57 @@
+/* 
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ * 
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ * 
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ *     from: Mach, Revision 2.7  92/02/29  15:33:41  rpd
+ *     $Id: real_prot.h,v 1.1 1996/04/29 14:15:14 hvozda Exp $
+ */
+
+/*
+ * LP (Laptop Package)
+ *
+ * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, and distributed, in
+ * both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author 
+ * responsible for the proper functioning of this software, nor does 
+ * the author assume any responsibility for damages incurred with its 
+ * use.
+ *
+ * Sep., 1994  Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ * Oct., 1994  NetBSD port (1.0 BETA 10/2) by ukai
+ */
+
+/*
+ * Modified to APM BIOS initializer by HOSOKAWA, Tatsumi
+ */
+
+#define ALIGN  4
+#define EXT(x) _ ## x
+#define LEXT(x) _ ## x ## :
+
+#define addr32 .byte 0x67
+#define data32 .byte 0x66
+
+#define        ENTRY(x)        .globl EXT(x); .align ALIGN; LEXT(x)
diff --git a/sys/arch/i386/apm_init/rmaouthdr b/sys/arch/i386/apm_init/rmaouthdr
new file mode 100644 (file)
index 0000000..6087150
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/csh -f
+#
+#      from: Mach, Revision 2.2  92/04/04  11:36:01  rpd
+#      $Id: rmaouthdr,v 1.1 1996/04/29 14:15:35 hvozda Exp $ 
+#
+dd if=$1 of=$2 ibs=32 skip=1 obs=1024b
diff --git a/sys/arch/i386/apm_init/table.c b/sys/arch/i386/apm_init/table.c
new file mode 100644 (file)
index 0000000..d3cc1d9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * LP (Laptop Package)
+ *
+ * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, and distributed, in
+ * both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author 
+ * responsible for the proper functioning of this software, nor does 
+ * the author assume any responsibility for damages incurred with its 
+ * use.
+ *
+ * Sep., 1994  Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ * Oct., 1994  NetBSD port (1.0 BETA 10/2) by ukai
+ */
+
+#include <apm_bios.h>
+
+struct pseudo_desc {
+       unsigned short  limit;
+       unsigned long   base __attribute__ ((packed));
+};
+
+struct pseudo_desc Idtr_prot = { 0, 0 }; /* filled on run time */
+struct pseudo_desc Idtr_real = { 0x400 - 1, 0x0 };
index b412cdf..2b91d0e 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: HELIOS_PCMCIA,v 1.3 1996/04/18 18:55:35 niklas Exp $
+#      $OpenBSD: HELIOS_PCMCIA,v 1.4 1996/04/29 14:12:01 hvozda Exp $
 #
 #      HELIOS_PCMCIA -- Eric Hvozda's notebook
 #
@@ -25,6 +25,7 @@ options               KTRACE          # system call tracing, a la ktrace(1)
 options                COMPAT_NOMID    # compatibility with 386BSD, BSDI, NetBSD 0.8,
 options                COMPAT_09       # NetBSD 0.9,
 options                COMPAT_10       # NetBSD 1.0,
+options                COMPAT_11       # NetBSD 1.1,
 options                COMPAT_43       # and 4.3BSD
 
 options                LKM             # loadable kernel modules
@@ -48,26 +49,46 @@ options             FDSCRIPTS       # secure setuid scripts
 
 options                INET            # IP + ICMP + TCP + UDP
 
-config         bsd     root on wd0a swap on wd0b and vnd0b dumps on wd0b
+config         bsd     root on wd0a swap on wd0b dumps on wd0b
 
 mainbus0       at root
 
 isa0   at mainbus0
 pci0   at mainbus0
+#apm0  at mainbus0
 
 npx0   at isa? port 0xf0 irq 13        # math coprocessor
 
 pc0    at isa? port 0x60 irq 1         # generic PC console device
-
-pcic0  at isa? port 0x3E0 flags 0
-pcmcia0 at pcic? iomem 0xd4000 iosiz 4096
-com2   at pcmcia? port 0x3e8 irq 12
-ed2    at pcmcia? port 0x300 iomem 0xcc000 irq 10
+#spkr0 at pckbd? port 0x61             # PC speaker
+
+# Multiple controllers need some testing.  Some laptops have multiple PCIC
+# controllers instead of two-slot controllers.
+# The i82365 (pcic) controller uses the same ports for the first two
+# controllers and for the second two controllers.
+
+# IRQ 2/9 doesn't seem to work for status change interrupts, so use one
+# of the higher ones.
+pcicmaster0    at isa? port 0x3E0 size 2
+pcic0  at pcicmaster0 irq 11 iomem 0xd4000 iosiz 4096
+pcic1  at pcicmaster0 irq 12 iomem 0xd5000 iosiz 4096
+pcicmaster1 at isa? port 0x3E2 size 2
+pcic2  at pcicmaster1 irq 11 iomem 0xd6000 iosiz 4096
+pcic3  at pcicmaster1 irq 12 iomem 0xd7000 iosiz 4096
+
+pcmcia* at pcic?
+
+#ed0     at pcmcia? port 0x300 iomem 0xd8000 iosiz 8192        irq 10
+ed0     at pcmcia? port 0x300 size 0x20 irq 10 slot ?
+#ep0     at pcmcia? port 0x300 size 0x10 irq 10 slot ?
+#com1    at pcmcia? port 0x2f8 size 8 irq 5 slot ?
+com2    at pcmcia? port 0x3e8 size 8 irq 5 slot ?
+#com3    at pcmcia? port 0x2e8 size 8  irq 3 slot ?
 
 com0   at isa? port 0x3f8 irq 4        # standard PC serial ports
 com1   at isa? port 0x2f8 irq 3
 
-lpt0   at isa? port 0x378 irq 7        # standard PC parallel ports
+lpt0   at isa? port 0x378              # standard PC parallel ports
 
 fdc0   at isa? port 0x3f0 irq 6 drq 2  # standard PC floppy controllers
 fd0    at fdc? drive 0
@@ -75,7 +96,7 @@ fd0   at fdc? drive 0
 wdc0   at isa? port 0x1f0 irq 14       # ST506, ESDI, and IDE controllers
 wd0    at wdc? drive 0
 
-sb0    at isa? port 0x240 irq 5 drq 1  # SoundBlaster
+sb0    at isa? port 0x240 irq 7 drq 1  # SoundBlaster
 
 pseudo-device  loop    1               # network loopback
 pseudo-device  bpfilter 8              # packet filter
index aee0809..0edf404 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile.i386,v 1.8 1996/04/24 12:05:17 mickey Exp $
+#      $OpenBSD: Makefile.i386,v 1.9 1996/04/29 14:12:10 hvozda Exp $
 #      $NetBSD: Makefile.i386,v 1.66 1996/02/29 20:56:16 cgd Exp $
 
 # Makefile for OpenBSD
@@ -145,10 +145,14 @@ links:
          sed 's,../.*/\(.*.o\),rm -f \1; ln -s ../GENERIC/\1 \1,' > makelinks
        sh makelinks && rm -f dontlink
 
+# depend on APM
+.include "${I386}/apm_init/Makefile.inc"
+locore.o: ${APMINC}
+
 SRCS=  ${I386}/i386/locore.s \
        param.c ioconf.c ${CFILES} ${SFILES}
 depend: .depend
-.depend: ${SRCS} assym.h param.c
+.depend: ${SRCS} assym.h param.c ${APMINC}
        mkdep ${AFLAGS} ${CPPFLAGS} ${I386}/i386/locore.s
        mkdep -a ${CFLAGS} ${CPPFLAGS} param.c ioconf.c ${CFILES}
        mkdep -a ${AFLAGS} ${CPPFLAGS} ${SFILES}
diff --git a/sys/arch/i386/conf/PCMCIA b/sys/arch/i386/conf/PCMCIA
new file mode 100644 (file)
index 0000000..d057ea3
--- /dev/null
@@ -0,0 +1,138 @@
+#      $Id: PCMCIA,v 1.1 1996/04/29 14:12:24 hvozda Exp $
+#      $Source: /home/cvs/src/sys/arch/i386/conf/Attic/PCMCIA,v $
+#
+#      ATHENA-AHA      -- ATHENA kernel for Adaptec & others...
+#
+# from:        GENERIC -- everything that's currently supported
+#       NetBSD: GENERIC,v 1.12 1995/02/21 01:43:02 brezak Exp
+#
+
+machine                i386            # architecture, used by config; REQUIRED
+
+options                I586_CPU
+options                I486_CPU
+options                I386_CPU
+options                INSECURE
+options                MATH_EMULATE
+
+options                DUMMY_NOPS      # speed hack; recommanded
+options                XSERVER,UCONSOLE
+options                MACHINE_NONCONTIG
+
+maxusers       32              # estimated number of users
+options                TIMEZONE=300    # time zone to adjust RTC time by
+options                DST=1           # daylight savings time used by RTC
+
+options                SWAPPAGER       # paging; REQUIRED
+options                VNODEPAGER      # mmap() of files
+options                DEVPAGER        # mmap() of devices
+
+options                DDB             # in-kernel debugger
+#makeoptions   DEBUG="-g"      # compile full symbol table
+#options       DIAGNOSTIC      # internally consistency checks
+options                KTRACE          # system call tracing, a la ktrace(1)
+
+options                SYSVMSG         # System V-like message queues
+options                SYSVSEM         # System V-like semaphores
+options                SYSVSHM         # System V-like memory sharing
+#options       SHMMAXPGS=1024  # 1024 pages is the default
+
+options                COMPAT_NOMID    # compatibility with 386BSD, BSDI, NetBSD 0.8,
+options                COMPAT_09       # NetBSD 0.9,
+options                COMPAT_10       # NetBSD 1.0,
+options                COMPAT_43       # and 4.3BSD
+options                TCP_COMPAT_42   # TCP bug compatibility with 4.2BSD
+
+options                COMPAT_SVR4     # binary compatibility with SVR4
+options                COMPAT_IBCS2    # binary compatibility with SCO and ISC
+options                COMPAT_LINUX    # binary compatibility with Linux
+
+options                USER_LDT        # user-settable LDT; used by WINE
+options                LKM             # loadable kernel modules
+
+options                FFS #,QUOTA     # UFS and quotas
+#options       LFS             # log-structured file system
+options                MFS             # memory file system
+
+options                NFSCLIENT       # Network File System client
+options                NFSSERVER       # Network File System server
+options                HAS_VOPLEASE    # XXX
+
+options                APM_NOIDLE
+#options               PCIVERBOSE
+#options               PCMCIA_DEBUG
+#options               PCMCIA_ISA_DEBUG
+
+### SCSI:
+#options               CD9660          # ISO 9660 + Rock Ridge file system
+###
+options                MSDOSFS         # MS-DOS file system
+options                FIFO            # FIFOs; RECOMMENDED
+options                PROCFS          # /proc
+
+#options       GATEWAY         # packet forwarding
+options                INET            # IP + ICMP + TCP + UDP
+#options       NS              # XNS
+#options       ISO,TPIP        # OSI
+#options       EON             # OSI tunneling over IP
+#options       CCITT,LLC,HDLC  # X.25
+
+config         netbsd  swap generic
+options                GENERIC
+
+# Local Athena options
+
+options                PCVT_CTRL_ALT_DEL       # For screwed-over Linux weenies
+
+mainbus0 at root
+isa0   at mainbus0
+pci0   at mainbus0 bus 0
+
+npx0   at isa? port 0xf0 irq 13        # math coprocessor
+
+vt0    at isa? port 0x60 irq 1
+
+com0   at isa? port 0x3f8 irq 4        # standard PC serial ports
+com1   at isa? port 0x2f8 irq 3
+com2   at isa? port 0x3e8 irq 5
+
+lpt0   at isa? port 0x378 irq 7        # standard PC parallel ports
+
+pms0   at pckbd? irq 12                # PS/2 auxiliary port mouse
+
+fdc0   at isa? port 0x3f0 irq 6 drq 2  # standard PC floppy controllers
+fd0    at fdc0 drive 0
+
+wdc0   at isa? port 0x1f0 irq 14       # ST506, ESDI, and IDE controllers
+wd0    at wdc0 drive 0
+
+spkr0  at pckbd? port 0x61
+#apm0  at mainbus?
+
+# Multiple controllers need some testing.  Some laptops have multiple PCIC
+# controllers instead of two-slot controllers.
+# The i82365 (pcic) controller uses the same ports for the first two
+# controllers and for the second two controllers.
+
+# IRQ 2/9 doesn't seem to work for status change interrupts, so use one
+# of the higher ones.
+pcicmaster0    at isa? port 0x3E0 size 2
+pcic0  at pcicmaster0 irq 11 iomem 0xd4000 iosiz 4096
+pcic1  at pcicmaster0 irq 12 iomem 0xd5000 iosiz 4096
+pcicmaster1 at isa? port 0x3E2 size 2
+pcic2  at pcicmaster1 irq 11 iomem 0xd6000 iosiz 4096
+pcic3  at pcicmaster1 irq 12 iomem 0xd7000 iosiz 4096
+
+pcmcia* at pcic?
+
+#ed0     at pcmcia? port 0x300 iomem 0xd8000 iosiz 8192        irq 10
+ed0     at pcmcia? port 0x300 size 0x20 irq 10 slot ?
+ep0     at pcmcia? port 0x300 size 0x10 irq 10 slot ?
+#com1    at pcmcia? port 0x2f8 size 8 irq 5 slot ?
+#com2    at pcmcia? port 0x3e8 size 8 irq 5 slot ?
+com3    at pcmcia? port 0x2e8 size 8   irq 3 slot ?
+
+pseudo-device  loop    1               # network loopback
+pseudo-device  bpfilter 4              # packet filter
+pseudo-device  ppp     2               # PPP
+pseudo-device  pty     64              # pseudo-terminals
index c434f13..2bd8ee7 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.i386,v 1.13 1996/04/28 17:02:01 mickey Exp $
+#      $OpenBSD: files.i386,v 1.14 1996/04/29 14:12:16 hvozda Exp $
 #      $NetBSD: files.i386,v 1.72 1996/04/09 22:59:03 cgd Exp $
 #
 # new style config file for i386 architecture
@@ -52,7 +52,8 @@ major {rd = 17}
 # System bus types
 #
 
-device mainbus: isabus, eisabus, pcibus
+define mainbus { }
+device mainbus: isabus, eisabus, pcibus, mainbus
 attach mainbus at root
 file   arch/i386/i386/mainbus.c        mainbus
 
@@ -68,6 +69,12 @@ include "../../../dev/pci/files.pci"
 file   arch/i386/pci/pci_machdep.c     pci
 file   arch/i386/pci/pci_compat.c      pci     # XXX compatibility
 
+#
+# Pcmcia, before ISA (to define device stuff)
+#
+
+include "../../../dev/pcmcia/files.pcmcia"
+
 #
 # ISA and mixed ISA+EISA or ISA+PCI or ISA+PCMCIA drivers
 #
@@ -77,10 +84,6 @@ major        {mcd = 7}
 major  {wd = 0}
 major  {wt = 3}
 
-#define pcic here until config issues are resolved
-#device pcic at isa: pcmciabus
-#file  dev/isa/pcmcia_pcic.c           pcic
-
 include "../../../dev/isa/files.isa"
 file   arch/i386/isa/isa_machdep.c     isabus
 
@@ -138,9 +141,9 @@ file        arch/i386/isa/spkr.c            spkr needs-flag
 # National Semiconductor DS8390/WD83C690-based boards
 # (WD/SMC 80x3 family, SMC Ultra [8216], 3Com 3C503, NE[12]000, and clones)
 # XXX conflicts with other ports; can't be in files.isa
-device ed: ether, ifnet
-attach ed at isa
-file   dev/isa/if_ed.c                 ed
+#device        ed: ether, ifnet
+#attach        ed at isa
+#file  dev/isa/if_ed.c                 ed
 
 # AMD am7990 (Lance) -based boards
 # (BICC Isolan, NE2100, DEPCA)
@@ -183,3 +186,7 @@ file        arch/i386/i386/linux_machdep.c          compat_linux
 # FreeBSD binary compatibility (COMPAT_FREEBSD)
 include "../../../compat/freebsd/files.freebsd"
 file   arch/i386/i386/freebsd_machdep.c        compat_freebsd
+
+device apm
+attach apm at mainbus
+file   arch/i386/i386/apm.c            apm needs-count
diff --git a/sys/arch/i386/i386/apm.c b/sys/arch/i386/i386/apm.c
new file mode 100644 (file)
index 0000000..03483c7
--- /dev/null
@@ -0,0 +1,844 @@
+/*     $NetBSD $       */
+
+/*-
+ * Copyright (c) 1995 John T. Kohl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "apm.h"
+#if NAPM > 0
+
+#if NAPM > 1
+#error only one APM device may be configured
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/signalvar.h>
+#include <sys/kernel.h>
+#include <sys/map.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/gdt.h>
+#include <machine/psl.h>
+
+#include <dev/isa/isareg.h>
+#include <i386/isa/isa_machdep.h>
+#include <i386/isa/nvram.h>
+#include <dev/isa/isavar.h>
+
+#include <machine/apmvar.h>
+
+#if defined(DEBUG) || defined(APMDEBUG)
+#define DPRINTF(x)     printf x
+#define STATIC /**/
+#else
+#define        DPRINTF(x)      /**/
+#define STATIC static
+#endif
+
+int apmprobe __P((struct device *, void *, void *));
+void apmattach __P((struct device *, struct device *, void *));
+
+#define APM_NEVENTS 16
+
+struct apm_softc {
+       struct device sc_dev;
+       struct selinfo sc_rsel;
+       struct selinfo sc_xsel;
+       int     sc_flags;
+       int     event_count;
+       int     event_ptr;
+       struct  apm_event_info event_list[APM_NEVENTS];
+};
+#define        SCFLAG_OREAD    0x0000001
+#define        SCFLAG_OWRITE   0x0000002
+#define        SCFLAG_OPEN     (SCFLAG_OREAD|SCFLAG_OWRITE)
+
+#define        APMUNIT(dev)    (minor(dev)&0xf0)
+#define        APMDEV(dev)     (minor(dev)&0x0f)
+#define APMDEV_NORMAL  0
+#define APMDEV_CTL     8
+
+struct cfattach apm_ca = {
+    sizeof(struct apm_softc), apmprobe, apmattach
+};
+
+struct cfdriver apm_cd = {
+       NULL, "apm", DV_DULL
+};
+
+struct apm_connect_info apminfo = { 0 };
+u_char apm_majver;
+u_char apm_minver;
+u_short        apminited;
+int apm_dobusy;
+
+STATIC int apm_get_powstat __P((struct apmregs *));
+STATIC void apm_power_print __P((struct apm_softc *, struct apmregs *));
+STATIC void apm_event_handle __P((struct apm_softc *, struct apmregs *));
+STATIC int apm_get_event __P((struct apmregs *));
+STATIC void apm_set_ver __P((struct apm_softc *));
+STATIC void apm_periodic_check __P((void *));
+STATIC void apm_disconnect __P((void *));
+STATIC void apm_perror __P((const char *, struct apmregs *));
+STATIC void apm_powmgt_enable __P((int onoff));
+STATIC void apm_powmgt_engage __P((int onoff, u_int devid));
+STATIC void apm_devpowmgt_enable __P((int onoff, u_int devid));
+STATIC void apm_suspend __P((void));
+STATIC void apm_standby __P((void));
+STATIC int apm_record_event __P((struct apm_softc *sc, u_int event_type));
+
+STATIC const char *
+apm_err_translate(code)
+int code;
+{
+       switch(code) {
+       case APM_ERR_PM_DISABLED:
+               return "power management disabled";
+       case APM_ERR_REALALREADY:
+               return "real mode interface already connected";
+       case APM_ERR_NOTCONN:
+               return "interface not connected";
+       case APM_ERR_16ALREADY:
+               return "16-bit interface already connected";
+       case APM_ERR_16NOTSUPP:
+               return "16-bit interface not supported";
+       case APM_ERR_32ALREADY:
+               return "32-bit interface already connected";
+       case APM_ERR_32NOTSUPP:
+               return "32-bit interface not supported";
+       case APM_ERR_UNRECOG_DEV:
+               return "unrecognized device ID";
+       case APM_ERR_ERANGE:
+               return "parameter out of range";
+       case APM_ERR_NOTENGAGED:
+               return "interface not engaged";
+       case APM_ERR_UNABLE:
+               return "unable to enter requested state";
+       case APM_ERR_NOEVENTS:
+               return "No pending events";
+       case APM_ERR_NOT_PRESENT:
+               return "No APM present";
+       default:
+               return "unknown error code?";
+       }
+}
+
+STATIC void
+apm_perror(str, regs)
+const char *str;
+struct apmregs *regs;
+{
+       printf("APM %s: %s (%d)\n", str,
+              apm_err_translate(APM_ERR_CODE(regs)),
+              APM_ERR_CODE(regs));
+}
+
+STATIC void
+apm_power_print (sc, regs)
+struct apm_softc *sc;
+struct apmregs *regs;
+{
+       if (BATT_LIFE(regs) != APM_BATT_LIFE_UNKNOWN) {
+               printf("%s: battery life expectancy %d%%\n",
+                      sc->sc_dev.dv_xname,
+                      BATT_LIFE(regs));
+       }
+       printf("%s: A/C state: ", sc->sc_dev.dv_xname);
+       switch (AC_STATE(regs)) {
+       case APM_AC_OFF:
+               printf("off\n");
+               break;
+       case APM_AC_ON:
+               printf("on\n");
+               break;
+       case APM_AC_BACKUP:
+               printf("backup power\n");
+               break;
+       default:
+       case APM_AC_UNKNOWN:
+               printf("unknown\n");
+               break;
+       }
+       printf("%s: battery charge state:", sc->sc_dev.dv_xname);
+       if (apm_minver == 0)
+               switch (BATT_STATE(regs)) {
+               case APM_BATT_HIGH:
+                       printf("high\n");
+                       break;
+               case APM_BATT_LOW:
+                       printf("low\n");
+                       break;
+               case APM_BATT_CRITICAL:
+                       printf("critical\n");
+                       break;
+               case APM_BATT_CHARGING:
+                       printf("charging\n");
+                       break;
+               case APM_BATT_UNKNOWN:
+                       printf("unknown\n");
+                       break;
+               default:
+                       printf("undecoded state %x\n", BATT_STATE(regs));
+                       break;
+               }
+       else if (apm_minver >= 1) {
+               if (BATT_FLAGS(regs) & APM_BATT_FLAG_NOBATTERY)
+                       printf(" no battery");
+               else {
+                       if (BATT_FLAGS(regs) & APM_BATT_FLAG_HIGH)
+                               printf(" high");
+                       if (BATT_FLAGS(regs) & APM_BATT_FLAG_LOW)
+                               printf(" low");
+                       if (BATT_FLAGS(regs) & APM_BATT_FLAG_CRITICAL)
+                               printf(" critical");
+                       if (BATT_FLAGS(regs) & APM_BATT_FLAG_CHARGING)
+                               printf(" charging");
+               }
+               printf("\n");
+               if (BATT_REM_VALID(regs))
+                       printf("%s: estimated %d:%02d minutes\n",
+                              sc->sc_dev.dv_xname,
+                              BATT_REMAINING(regs) / 60,
+                              BATT_REMAINING(regs)%60);
+       }
+       return;
+}
+
+int apm_standbys = 0;
+int apm_userstandbys = 0;
+int apm_suspends = 0;
+int apm_battlow = 0;
+
+STATIC void
+apm_get_powstate(dev)
+u_int dev;
+{
+    struct apmregs regs;
+    int rval;
+    regs.bx = dev;
+    rval = apmcall(APM_GET_POWER_STATE, &regs);
+    if (rval == 0) {
+       printf("apm dev %04x state %04x\n", dev, regs.cx);
+    }
+}
+
+STATIC void
+apm_suspend()
+{
+       (void) apm_set_powstate(APM_DEV_ALLDEVS, APM_SYS_SUSPEND);
+}
+
+STATIC void
+apm_standby()
+{
+       (void) apm_set_powstate(APM_DEV_ALLDEVS, APM_SYS_STANDBY);
+}
+
+static int apm_evindex = 0;
+
+STATIC int
+apm_record_event(sc, event_type)
+struct apm_softc *sc;
+u_int event_type;
+{
+       struct apm_event_info *evp;
+
+       if ((sc->sc_flags & SCFLAG_OPEN) == 0)
+               return 1;               /* no user waiting */
+       if (sc->event_count == APM_NEVENTS)
+               return 1;                       /* overflow */
+       evp = &sc->event_list[sc->event_ptr];
+       sc->event_count++;
+       sc->event_ptr++;
+       sc->event_ptr %= APM_NEVENTS;
+       evp->type = event_type;
+       evp->index = ++apm_evindex;
+       selwakeup(&sc->sc_rsel);
+       return (sc->sc_flags & SCFLAG_OWRITE) ? 0 : 1; /* user may handle */
+}
+
+STATIC void
+apm_event_handle(sc, regs)
+struct apm_softc *sc;
+struct apmregs *regs;
+{
+       int error;
+       struct apmregs nregs;
+
+       switch(regs->bx) {
+       case APM_USER_STANDBY_REQ:
+               DPRINTF(("user wants STANDBY--fat chance\n"));
+               (void) apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_REJECTED);
+               (void) apm_record_event(sc, regs->bx);
+               apm_userstandbys++;
+               break;
+       case APM_STANDBY_REQ:
+               DPRINTF(("standby requested\n"));
+               if (apm_standbys || apm_suspends)
+                   DPRINTF(("damn fool BIOS did not wait for answer\n"));
+               if (apm_record_event(sc, regs->bx)) {
+                       (void) apm_set_powstate(APM_DEV_ALLDEVS,
+                                               APM_LASTREQ_INPROG);
+                       apm_standbys++;
+               } else
+                       (void) apm_set_powstate(APM_DEV_ALLDEVS,
+                                               APM_LASTREQ_REJECTED);
+               break;
+       case APM_USER_SUSPEND_REQ:
+               DPRINTF(("user wants suspend--fat chance!\n"));
+               (void) apm_set_powstate(APM_DEV_ALLDEVS,
+                                       APM_LASTREQ_REJECTED);
+               apm_suspends++;
+               apm_record_event(sc, regs->bx);
+               break;
+       case APM_SUSPEND_REQ:
+               DPRINTF(("suspend requested\n"));
+               if (apm_standbys || apm_suspends)
+                   DPRINTF(("damn fool BIOS did not wait for answer\n"));
+               if (apm_record_event(sc, regs->bx)) {
+                       (void) apm_set_powstate(APM_DEV_ALLDEVS,
+                                               APM_LASTREQ_INPROG);
+                       apm_suspends++;
+               } else
+                       (void) apm_set_powstate(APM_DEV_ALLDEVS,
+                                               APM_LASTREQ_REJECTED);
+               break;
+       case APM_POWER_CHANGE:
+               DPRINTF(("power status change\n"));
+               error = apm_get_powstat(&nregs);
+               if (error == 0)
+                       apm_power_print(sc, &nregs);
+               apm_record_event(sc, regs->bx);
+               break;
+       case APM_NORMAL_RESUME:
+               DPRINTF(("system resumed\n"));
+               inittodr(time.tv_sec);
+               apm_record_event(sc, regs->bx);
+               break;
+       case APM_CRIT_RESUME:
+               DPRINTF(("system resumed without us!\n"));
+               inittodr(time.tv_sec);
+               apm_record_event(sc, regs->bx);
+               break;
+       case APM_SYS_STANDBY_RESUME:
+               DPRINTF(("system standby resume\n"));
+               inittodr(time.tv_sec);
+               apm_record_event(sc, regs->bx);
+               break;
+       case APM_UPDATE_TIME:
+               DPRINTF(("update time, please\n"));
+               inittodr(time.tv_sec);
+               apm_record_event(sc, regs->bx);
+               break;
+       case APM_CRIT_SUSPEND_REQ:
+               DPRINTF(("suspend required immediately\n"));
+               apm_record_event(sc, regs->bx);
+               apm_suspend();
+               break;
+       case APM_BATTERY_LOW:
+               DPRINTF(("Battery low!\n"));
+               apm_battlow++;
+               apm_record_event(sc, regs->bx);
+               break;
+       default:
+               printf("APM nonstandard event code %x\n", regs->bx);
+       }
+}
+
+STATIC int
+apm_get_event(regs)
+struct apmregs *regs;
+{
+    return apmcall(APM_GET_PM_EVENT, regs);
+}
+
+STATIC void
+apm_periodic_check(arg)
+void *arg;
+{
+       struct apmregs regs;
+       struct apm_softc *sc = arg;
+       while (apm_get_event(&regs) == 0) {
+               apm_event_handle(sc, &regs);
+       };
+       if (APM_ERR_CODE(&regs) != APM_ERR_NOEVENTS)
+               apm_perror("get event", &regs);
+       if (apm_suspends /*|| (apm_battlow && apm_userstandbys)*/) {
+               /* stupid TI TM5000! */
+               apm_suspend();
+       } else if (apm_standbys || apm_userstandbys) {
+               apm_standby();
+       }
+       apm_suspends = apm_standbys = apm_battlow = apm_userstandbys =0;
+       timeout(apm_periodic_check, sc, hz);
+}
+
+STATIC void
+apm_powmgt_enable(onoff)
+int onoff;
+{
+       struct apmregs regs;
+       regs.bx = apm_minver == 0 ? APM_MGT_ALL : APM_DEV_APM_BIOS;
+       regs.cx = onoff ? APM_MGT_ENABLE : APM_MGT_DISABLE;
+       if (apmcall(APM_PWR_MGT_ENABLE, &regs) != 0)
+               apm_perror("power management enable", &regs);
+}
+
+STATIC void
+apm_powmgt_engage(onoff, dev)
+int onoff;
+u_int dev;
+{
+       struct apmregs regs;
+       if (apm_minver == 0)
+               return;
+       regs.bx = dev;
+       regs.cx = onoff ? APM_MGT_ENGAGE : APM_MGT_DISENGAGE;
+       if (apmcall(APM_PWR_MGT_ENGAGE, &regs) != 0)
+               printf("APM power mgmt engage (device %x): %s (%d)\n",
+                      dev, apm_err_translate(APM_ERR_CODE(&regs)),
+                      APM_ERR_CODE(&regs));
+}
+
+STATIC void
+apm_devpowmgt_enable(onoff, dev)
+int onoff;
+u_int dev;
+{
+       struct apmregs regs;
+       if (apm_minver == 0)
+           return;
+       regs.bx = dev;
+       /* enable is auto BIOS managment.
+        * disable is program control.
+        */
+       regs.cx = onoff ? APM_MGT_ENABLE : APM_MGT_DISABLE;
+       if (apmcall(APM_DEVICE_MGMT_ENABLE, &regs) != 0)
+               printf("APM device engage (device %x): %s (%d)\n",
+                      dev, apm_err_translate(APM_ERR_CODE(&regs)),
+                      APM_ERR_CODE(&regs));
+}
+
+int
+apm_set_powstate(dev, state)
+u_int dev, state;
+{
+       struct apmregs regs;
+       if (!apminited || (apm_minver == 0 && state > APM_SYS_OFF))
+           return EINVAL;
+       regs.bx = dev;
+       regs.cx = state;
+       if (apmcall(APM_SET_PWR_STATE, &regs) != 0) {
+               apm_perror("set power state", &regs);
+               return EIO;
+       }
+       return 0;
+}
+
+#ifdef APM_NOIDLE
+int apmidleon = 0;
+#else
+int apmidleon = 1;
+#endif
+
+void
+apm_cpu_busy()
+{
+       struct apmregs regs;
+       if (!apminited)
+           return;
+       if ((apminfo.apm_detail & APM_IDLE_SLOWS) &&
+           apmcall(APM_CPU_BUSY, &regs) != 0)
+               apm_perror("set CPU busy", &regs);
+}
+
+void
+apm_cpu_idle()
+{
+       struct apmregs regs;
+       if (!apminited || !apmidleon)
+           return;
+       if (apmcall(APM_CPU_IDLE, &regs) != 0)
+               apm_perror("set CPU idle", &regs);
+}
+
+void *apm_sh;
+
+#ifdef APM_V10_ONLY
+int apm_v11_enabled = 0;
+#else
+int apm_v11_enabled = 1;
+#endif
+
+STATIC void
+apm_set_ver(self)
+struct apm_softc *self;
+{
+       struct apmregs regs;
+       int error;
+
+       regs.cx = 0x0101;       /* APM Version 1.1 */
+       regs.bx = APM_DEV_APM_BIOS;
+       
+       if (apm_v11_enabled &&
+           (error = apmcall(APM_DRIVER_VERSION, &regs)) == 0) {
+               apm_majver = APM_CONN_MAJOR(&regs);
+               apm_minver = APM_CONN_MINOR(&regs);
+       } else {
+               apm_majver = 1;
+               apm_minver = 0;
+       }
+       printf(": Power Management spec V%d.%d",
+              apm_majver, apm_minver);
+       apminited = 1;
+       if (apminfo.apm_detail & APM_IDLE_SLOWS) {
+#ifdef DEBUG
+       /* not relevant much */
+               printf(" (slowidle)");
+#endif
+               apm_dobusy = 1;
+       } else
+           apm_dobusy = 0;
+#ifdef DIAGNOSTIC
+       if (apminfo.apm_detail & APM_BIOS_PM_DISABLED)
+               printf(" (BIOS mgmt disabled)");
+       if (apminfo.apm_detail & APM_BIOS_PM_DISENGAGED)
+               printf(" (BIOS managing devices)");
+#endif
+       printf("\n");
+}
+
+STATIC int
+apm_get_powstat(regs)
+struct apmregs *regs;
+{
+       regs->bx = APM_DEV_ALLDEVS;
+       return apmcall(APM_POWER_STATUS, regs);
+}
+
+STATIC void
+apm_disconnect(xxx)
+void *xxx;
+{
+       struct apmregs regs;
+       regs.bx = apm_minver == 1 ? APM_DEV_ALLDEVS : APM_DEFAULTS_ALL;
+       if (apmcall(APM_SYSTEM_DEFAULTS, &regs))
+               apm_perror("system defaults failed", &regs);
+
+       regs.bx = APM_DEV_APM_BIOS;
+       if (apmcall(APM_DISCONNECT, &regs))
+               apm_perror("disconnect failed", &regs);
+       else
+               printf("APM disconnected\n");
+}
+
+int
+apmprobe(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       struct apm_attach_args *aaa = aux;
+
+       if (apminited)
+               return 0;
+       if ((apminfo.apm_detail & APM_32BIT_SUPPORTED) &&
+           strcmp(aaa->aaa_busname, "apm") == 0) {
+               return 1;
+       }
+       return 0;
+}
+
+void
+apmattach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct apm_softc *apmsc = (void *)self;
+       struct apmregs regs;
+       int error;
+       /*
+        * set up GDT descriptors for APM
+        */
+       if (apminfo.apm_detail & APM_32BIT_SUPPORTED) {
+               apminfo.apm_segsel = GSEL(GAPM32CODE_SEL,SEL_KPL);
+               apminfo.apm_code32_seg_base <<= 4;
+               apminfo.apm_code16_seg_base <<= 4;
+               apminfo.apm_data_seg_base <<= 4;
+               /* something is still amiss in the limit-fetch in the boot
+                  loader; it returns incorrect (too small) limits.
+                  for now, force them to max size. */
+               apminfo.apm_code32_seg_len = 65536;
+               apminfo.apm_data_seg_len = 65536;
+#if 0
+               switch ((APM_MAJOR_VERS(apminfo.apm_detail) << 8) +
+                       APM_MINOR_VERS(apminfo.apm_detail)) {
+               case 0x0100:
+                       apminfo.apm_code32_seg_len = 65536;
+                       apminfo.apm_data_seg_len = 65536;
+                       break;
+               default:
+                       if (apminfo.apm_data_seg_len == 0)
+                               apminfo.apm_data_seg_len = 65536;
+                       break;
+               }
+#endif
+               setsegment(&dynamic_gdt[GAPM32CODE_SEL].sd,
+                          (void *)ISA_HOLE_VADDR(apminfo.apm_code32_seg_base),
+                          apminfo.apm_code32_seg_len-1,
+                          SDT_MEMERA, SEL_KPL, 1, 0);
+               setsegment(&dynamic_gdt[GAPM16CODE_SEL].sd,
+                          (void *)ISA_HOLE_VADDR(apminfo.apm_code16_seg_base),
+                          65536-1,     /* just in case */
+                          SDT_MEMERA, SEL_KPL, 0, 0);
+               setsegment(&dynamic_gdt[GAPMDATA_SEL].sd,
+                          (void *)ISA_HOLE_VADDR(apminfo.apm_data_seg_base),
+                          apminfo.apm_data_seg_len-1,
+                          SDT_MEMRWA, SEL_KPL, 1, 0);
+#if defined(DEBUG) || defined(APMDEBUG)
+               printf(": detail %x 32b:%x/%x/%x 16b:%x/%x data %x/%x/%x ep %x (%x:%x)\n%s",
+                      apminfo.apm_detail,
+                      apminfo.apm_code32_seg_base,
+                      ISA_HOLE_VADDR(apminfo.apm_code32_seg_base),
+                      apminfo.apm_code32_seg_len,
+                      apminfo.apm_code16_seg_base,
+                      ISA_HOLE_VADDR(apminfo.apm_code16_seg_base),
+                      apminfo.apm_data_seg_base,
+                      ISA_HOLE_VADDR(apminfo.apm_data_seg_base),
+                      apminfo.apm_data_seg_len,
+                      apminfo.apm_entrypt,
+                      apminfo.apm_segsel,
+                      apminfo.apm_entrypt+ISA_HOLE_VADDR(apminfo.apm_code32_seg_base),
+                      apmsc->sc_dev.dv_xname);
+#endif
+               apm_set_ver(apmsc);
+               /*
+                * Engage cooperative power mgt (we get to do it)
+                * on all devices (v1.1).
+                */
+               apm_powmgt_engage(1, APM_DEV_ALLDEVS);
+#if 0
+               /* doesn't seem to work, sigh. */
+               apm_powmgt_engage(1, APM_DEV_DISPLAY(APM_DEV_ALLUNITS));
+               apm_powmgt_engage(1, APM_DEV_DISK(APM_DEV_ALLUNITS));
+               apm_powmgt_engage(1, APM_DEV_PARALLEL(APM_DEV_ALLUNITS));
+               apm_powmgt_engage(1, APM_DEV_NETWORK(APM_DEV_ALLUNITS));
+               apm_powmgt_engage(1, APM_DEV_PCMCIA(APM_DEV_ALLUNITS));
+#endif
+               error = apm_get_powstat(&regs);
+               if (error == 0) {
+                       apm_power_print(apmsc, &regs);
+               } else
+                       apm_perror("get power status", &regs);
+               apm_cpu_busy();
+               apm_periodic_check(apmsc);
+       } else {
+               dynamic_gdt[GAPM32CODE_SEL] = dynamic_gdt[GNULL_SEL];
+               dynamic_gdt[GAPM16CODE_SEL] = dynamic_gdt[GNULL_SEL];
+               dynamic_gdt[GAPMDATA_SEL] = dynamic_gdt[GNULL_SEL];
+       }
+}
+
+int
+apmopen(dev, flag, mode, p)
+       dev_t dev;
+       int flag, mode;
+       struct proc *p;
+{
+       int unit = APMUNIT(dev);
+       int ctl = APMDEV(dev);
+       struct apm_softc *sc;
+
+       if (unit >= apm_cd.cd_ndevs)
+               return ENXIO;
+       sc = apm_cd.cd_devs[unit];
+       if (!sc)
+               return ENXIO;
+       
+       switch (ctl) {
+       case APMDEV_CTL:
+               if (!(flag & FWRITE))
+                       return EINVAL;
+               if (sc->sc_flags & SCFLAG_OWRITE)
+                       return EBUSY;
+               sc->sc_flags |= SCFLAG_OWRITE;
+               break;
+       case APMDEV_NORMAL:
+               if (!(flag & FREAD) || (flag & FWRITE))
+                       return EINVAL;
+               sc->sc_flags |= SCFLAG_OREAD;
+               break;
+       default:
+               return ENXIO;
+               break;
+       }
+       return 0;
+}
+
+int
+apmclose(dev, flag, mode, p)
+       dev_t dev;
+       int flag, mode;
+       struct proc *p;
+{
+       struct apm_softc *sc = apm_cd.cd_devs[APMUNIT(dev)];
+       int ctl = APMDEV(dev);
+
+       DPRINTF(("apmclose: pid %d flag %x mode %x\n", p->p_pid, flag, mode));
+       switch (ctl) {
+       case APMDEV_CTL:
+               sc->sc_flags &= ~SCFLAG_OWRITE;
+               break;
+       case APMDEV_NORMAL:
+               sc->sc_flags &= ~SCFLAG_OREAD;
+               break;
+       }
+       if ((sc->sc_flags & SCFLAG_OPEN) == 0) {
+               sc->event_count = 0;
+               sc->event_ptr = 0;
+       }
+       return 0;
+}
+
+int
+apmioctl(dev, cmd, data, flag, p)
+       dev_t dev;
+       u_long cmd;
+       caddr_t data;
+       int flag;
+       struct proc *p;
+{
+       int error;
+       struct apm_softc *sc = apm_cd.cd_devs[APMUNIT(dev)];
+       struct apm_power_info *powerp;
+       struct apm_event_info *evp;
+       struct apmregs regs;
+       register int i;
+       struct apm_ctl *actl;
+
+       switch (cmd) {
+               /* some ioctl names from linux */
+       case APM_IOC_STANDBY:
+               if ((flag & FWRITE) == 0)
+                       return EBADF;
+               apm_userstandbys++;
+               return 0;
+       case APM_IOC_SUSPEND:
+               if ((flag & FWRITE) == 0)
+                       return EBADF;
+               apm_suspends++;
+               return 0;
+       case APM_IOC_DEV_CTL:
+               actl = (struct apm_ctl *)data;
+               if ((flag & FWRITE) == 0)
+                       return EBADF;
+               apm_get_powstate(actl->dev); /* XXX */
+               return apm_set_powstate(actl->dev, actl->mode);
+       case APM_IOC_NEXTEVENT:
+               if (sc->event_count) {
+                       evp = (struct apm_event_info *)data;
+                       i = sc->event_ptr + APM_NEVENTS - sc->event_count;
+                       i %= APM_NEVENTS;
+                       *evp = sc->event_list[i];
+                       sc->event_count--;
+                       return 0;
+               } else
+                       return EAGAIN;
+       case APM_IOC_GETPOWER:
+               powerp = (struct apm_power_info *)data;
+               error = apm_get_powstat(&regs);
+               if (error == 0) {
+                       bzero(powerp, sizeof(*powerp));
+                       if (BATT_LIFE(&regs) != APM_BATT_LIFE_UNKNOWN)
+                               powerp->battery_life = BATT_LIFE(&regs);
+                       powerp->ac_state = AC_STATE(&regs);
+                       switch (apm_minver) {
+                       case 0:
+                               powerp->battery_state = BATT_STATE(&regs);
+                               break;
+                       case 1:
+                       default:
+                               powerp->battery_state = APM_BATT_UNKNOWN;
+                               if (BATT_FLAGS(&regs) & APM_BATT_FLAG_HIGH)
+                                       powerp->battery_state = APM_BATT_HIGH;
+                               else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_LOW)
+                                       powerp->battery_state = APM_BATT_LOW;
+                               else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_CRITICAL)
+                                       powerp->battery_state = APM_BATT_CRITICAL;
+                               else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_CHARGING)
+                                       powerp->battery_state = APM_BATT_CHARGING;
+                               else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_NOBATTERY)
+                                               powerp->battery_state = APM_BATTERY_ABSENT;
+                               if (BATT_REM_VALID(&regs))
+                                   powerp->minutes_left = BATT_REMAINING(&regs);
+                       }
+               } else {
+                       apm_perror("ioctl get power status", &regs);
+                       error = EIO;
+               }
+               break;
+               
+       default:
+               return ENOTTY;
+       }
+       return 0;
+}
+
+int
+apmselect(dev, rw, p)
+       dev_t dev;
+       int rw;
+       struct proc *p;
+{
+       struct apm_softc *sc = apm_cd.cd_devs[APMUNIT(dev)];
+
+       switch (rw) {
+       case FREAD:
+               if (sc->event_count)
+                       return 1;
+               selrecord(p, &sc->sc_rsel);
+               break;
+       case FWRITE:
+       case 0:
+               return 0;
+       }
+       return 0;
+}
+
+#endif /* NAPM > 0 */
index c56ad77..9b68b21 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.12 1996/04/21 22:16:23 deraadt Exp $       */
+/*     $OpenBSD: conf.c,v 1.13 1996/04/29 14:12:41 hvozda Exp $        */
 /*     $NetBSD: conf.c,v 1.74 1996/03/30 07:30:33 mycroft Exp $        */
 
 /*
@@ -124,6 +124,13 @@ int        nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]);
        (dev_type_mmap((*))) enodev }
 #define cdev_joy_init cdev_ss_init
 
+/* open, close, ioctl, select -- XXX should be a generic device */
+#define cdev_ocis_init(c,n) { \
+        dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+        (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+        (dev_type_stop((*))) enodev, 0,  dev_init(c,n,select), \
+        (dev_type_mmap((*))) enodev, 0 }
+
 cdev_decl(cn);
 cdev_decl(ctty);
 #define        mmread  mmrw
@@ -161,6 +168,8 @@ cdev_decl(ch);
 dev_decl(filedesc,open);
 #include "bpfilter.h"
 cdev_decl(bpf);
+#include "pcmcia.h"
+cdev_decl(pcmcia);
 #include "spkr.h"
 cdev_decl(spkr);
 #ifdef LKM
@@ -187,6 +196,8 @@ cdev_decl(svr4_net);
 cdev_decl(ccd);
 #include "joy.h"
 cdev_decl(joy);
+#include "apm.h"
+cdev_decl(apm);
 #include "rnd.h"
 cdev_decl(rnd);
 
@@ -222,11 +233,11 @@ struct cdevsw     cdevsw[] =
        cdev_disk_init(NCCD,ccd),       /* 18: concatenated disk driver */
        cdev_ss_init(NSS,ss),           /* 19: SCSI scanner */
        cdev_notdef(),                  /* 20 */
-       cdev_notdef(),                  /* 21 */
+       cdev_ocis_init(NAPM,apm),       /* 21: Advancded Power Management */
        cdev_fd_init(1,filedesc),       /* 22: file descriptor pseudo-device */
        cdev_bpftun_init(NBPFILTER,bpf),/* 23: Berkeley packet filter */
        cdev_notdef(),                  /* 24 */
-       cdev_notdef(),                  /* 25 */
+       cdev_ocis_init(NPCMCIA,pcmcia), /* 25: PCMCIA Bus */
        cdev_joy_init(NJOY,joy),        /* 26: joystick */
        cdev_spkr_init(NSPKR,spkr),     /* 27: PC speaker */
        cdev_lkm_init(NLKM,lkm),        /* 28: loadable module driver */
index a511ab5..37361fb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: gdt.c,v 1.7 1996/04/18 19:18:08 niklas Exp $  */
+/*     $OpenBSD: gdt.c,v 1.8 1996/04/29 14:12:48 hvozda Exp $  */
 /*     $NetBSD: gdt.c,v 1.7 1996/02/27 22:45:01 jtc Exp $      */
 
 /*-
@@ -214,6 +214,16 @@ gdt_get_slot()
                if (gdt_next != gdt_count)
                        panic("gdt_get_slot botch 1");
                if (gdt_next >= gdt_size) {
+                       /*
+                        * gdt_size is clamped by maxproc, set in
+                        * /sys/conf/param.c and clamped in init386().
+                        * It's held there to (MAXGDTSIZ - NGDT) if no
+                        * user LDTs, or half that if user LDTs are
+                        * allowed. It's important to count that
+                        * correctly, because by the time we get here,
+                        * it's too late to abort the fork operation
+                        * -- we must have a GDT slot available.
+                        */
                        if (gdt_size >= MAXGDTSIZ)
                                panic("gdt_get_slot botch 2");
                        if (dynamic_gdt == gdt)
index d3e01c4..8bba187 100644 (file)
 #include <machine/pmap.h>
 #include <machine/vmparam.h>
 
+#include "apm.h"
+#if NAPM > 0
+#include <machine/apmvar.h>
+#endif
+
 #ifdef COMPAT_SVR4
 #include <compat/svr4/svr4_ucontext.h>
 #endif
@@ -150,6 +155,21 @@ main()
        off("IH_COUNT", struct intrhand, ih_count);
        off("IH_NEXT", struct intrhand, ih_next);
 #endif
+#if NAPM > 0
+       off("APM_CODE32", struct apm_connect_info, apm_code32_seg_base);
+       off("APM_CODE16", struct apm_connect_info, apm_code16_seg_base);
+       off("APM_DATA", struct apm_connect_info, apm_data_seg_base);
+       off("APM_CODE32_LEN", struct apm_connect_info, apm_code32_seg_len);
+       off("APM_DATA_LEN", struct apm_connect_info, apm_data_seg_len);
+       off("APM_ENTRY", struct apm_connect_info, apm_entrypt);
+       off("APM_DETAIL", struct apm_connect_info, apm_detail);
+       off("APM_CALL", struct apm_connect_info, apm_entrypt);
+       def("APM_SIZE", sizeof(struct apm_connect_info));
+       off("APMREG_AX", struct apmregs, ax);
+       off("APMREG_BX", struct apmregs, bx);
+       off("APMREG_CX", struct apmregs, cx);
+       off("APMREG_DX", struct apmregs, dx);
+#endif
 
        exit(0);
 }
index e7af288..65f33ef 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "npx.h"
 #include "assym.h"
+#include "apm.h"
 
 #include <sys/errno.h>
 #include <sys/syscall.h>
 
        .globl  _cpu,_cpu_vendor,_cold,_esym,_boothowto,_bootdev,_atdevbase
        .globl  _cyloffset,_proc0paddr,_curpcb,_PTDpaddr,_dynamic_gdt
+#if NAPM > 0
+#include <machine/apmvar.h>
+       .globl  _apminfo
+       .globl  _apm_current_gdt_pdesc  /* current GDT pseudo desc. */
+       .globl  _bootstrap_gdt
+_apm_current_gdt_pdesc:        
+       .word   0, 0, 0
+_bootstrap_gdt:        
+       .space SIZEOF_GDTE * BOOTSTRAP_GDT_NUM
+#endif
 _cpu:          .long   0       # are we 386, 386sx, or 486
 _cpu_vendor:   .space  16      # vendor string returned by `cpuid' instruction
 _cold:         .long   1       # cold till we are not
@@ -178,6 +189,102 @@ start:    movw    $0x1234,0x472                   # warm boot
        addl    $KERNBASE,%eax
 1:     movl    %eax,RELOC(_esym)
 
+#if NAPM > 0
+
+       /*
+        * Setup APM BIOS:
+        *
+        * APM BIOS initialization should be done from real mode or V86 mode.
+        *
+        * (by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>)
+        */
+
+       /*
+        * Cleanup %fs and %gs:
+        *
+        * Some BIOS bootstrap routine store junk value into %fs
+        * and %gs.
+        */
+
+       xorl    %eax, %eax
+       movw    %ax, %fs
+       movw    %ax, %gs
+
+       /* get GDT base */
+       sgdt    RELOC(_apm_current_gdt_pdesc)
+
+       /* copy GDT to _bootstrap_gdt */
+       xorl    %ecx, %ecx
+       movw    RELOC(_apm_current_gdt_pdesc), %cx
+       movl    RELOC(_apm_current_gdt_pdesc)+2, %esi
+       lea     RELOC(_bootstrap_gdt), %edi
+       cld
+       rep
+       movsb
+
+       /* setup GDT pseudo descriptor */
+       movw    $(SIZEOF_GDTE*BOOTSTRAP_GDT_NUM), %ax
+       movw    %ax, RELOC(_apm_current_gdt_pdesc)
+       leal    RELOC(_bootstrap_gdt), %eax
+       movl    %eax, RELOC(_apm_current_gdt_pdesc)+2
+
+       /* load new GDTR */
+       lgdt    RELOC(_apm_current_gdt_pdesc)
+
+       /* 
+        * Copy APM initializer under 1MB boundary:
+        *
+        * APM initializer program must switch the CPU to real mode.
+        * But NetBSD kernel runs above 1MB boundary. So we must 
+        * copy the initializer code to conventional memory.
+        */
+       movl    RELOC(_apm_init_image_size), %ecx       /* size */
+       lea     RELOC(_apm_init_image), %esi            /* source */
+       movl    $ APM_OURADDR, %edi                     /* destination */
+       cld
+       rep
+       movsb
+
+       /* setup GDT for APM initializer */
+       lea     RELOC(_bootstrap_gdt), %ecx
+       movl    $(APM_OURADDR), %eax    /* use %ax for 15..0 */
+       movl    %eax, %ebx
+       shrl    $16, %ebx               /* use %bl for 23..16 */
+                                       /* use %bh for 31..24 */
+#define APM_SETUP_GDT(index, attrib) \
+       movl    $(index), %si ; \
+       lea     0(%ecx,%esi,8), %edx ; \
+       movw    $0xffff, (%edx) ; \
+       movw    %ax, 2(%edx) ; \
+       movb    %bl, 4(%edx) ; \
+       movw    $(attrib), 5(%edx) ; \
+       movb    %bh, 7(%edx)
+
+       APM_SETUP_GDT(APM_INIT_CS_INDEX  , CS32_ATTRIB)
+       APM_SETUP_GDT(APM_INIT_DS_INDEX  , DS32_ATTRIB)
+       APM_SETUP_GDT(APM_INIT_CS16_INDEX, CS16_ATTRIB)
+
+       /*
+        * Call the initializer:
+        *
+        * direct intersegment call to conventional memory code
+        */
+       .byte   0x9a            /* actually, lcall $APM_INIT_CS_SEL, $0 */
+       .long   0
+       .word   APM_INIT_CS_SEL
+
+       movw    %ax,RELOC(_apminfo+APM_DETAIL)
+       movw    %di,RELOC(_apminfo+APM_DETAIL)+2
+       movl    %ebx,RELOC(_apminfo+APM_ENTRY)
+       movw    %cx,RELOC(_apminfo+APM_CODE32)
+       shrl    $16, %ecx
+       movw    %cx,RELOC(_apminfo+APM_CODE16)
+       movw    %dx,RELOC(_apminfo+APM_DATA)
+       movw    %si,RELOC(_apminfo+APM_CODE32_LEN)
+       shrl    $16, %esi
+       movw    %si,RELOC(_apminfo+APM_DATA_LEN)
+#endif /* APM */
+
        /* First, reset the PSL. */
        pushl   $PSL_MBO
        popfl
@@ -363,7 +470,7 @@ try586:     /* Use the `cpuid' instruction. */
 #endif
 
        /* Calculate where to start the bootstrap tables. */
-       movl    %edi,%esi                       # edi = esym ?: end
+       movl    %edi,%esi                       # edi = esym ? esym : end
        addl    $PGOFSET,%esi                   # page align up
        andl    $~PGOFSET,%esi
 
@@ -1481,6 +1588,9 @@ ENTRY(remrq)
 3:     .asciz  "remrq"
 #endif /* DIAGNOSTIC */
 
+#if NAPM > 0
+       .globl _apm_cpu_idle,_apm_cpu_busy,_apm_dobusy
+#endif
 /*
  * When no processes are on the runq, cpu_switch() branches to here to wait for
  * something to come ready.
@@ -1491,7 +1601,16 @@ ENTRY(idle)
        testl   %ecx,%ecx
        jnz     sw1
        sti
+#if NAPM > 0
+       call    _apm_cpu_idle
+#endif
        hlt
+#if NAPM > 0
+       cmpl    $0,_apm_dobusy
+       je      1f
+       call    _apm_cpu_busy
+1:     
+#endif
        jmp     _idle
 
 #ifdef DIAGNOSTIC
@@ -2075,3 +2194,78 @@ ENTRY(bzero)
 
        popl    %edi
        ret
+       
+#if NAPM > 0
+/*
+ * int apmcall(int function, struct apmregs *regs):
+ *     call the APM protected mode bios function FUNCTION for BIOS selection
+ *     WHICHBIOS.
+ *     Fills in *regs with registers as returned by APM.
+ *     returns nonzero if error returned by APM.
+ */
+apmstatus:     .long 0
+ENTRY(apmcall)
+       pushl   %ebp
+       movl    %esp,%ebp
+       pushl   %esi
+       pushl   %edi
+       pushl   %ebx
+       
+#if defined(DEBUG) || defined(DIAGNOSTIC)
+       pushl   %ds             
+       pushl   %es
+       pushl   %fs
+       pushl   %gs
+       xorl    %ax,%ax
+/*     movl    %ax,%ds         # can't toss %ds, we need it for apmstatus*/
+       movl    %ax,%es
+       movl    %ax,%fs
+       movl    %ax,%gs
+#endif
+       movb    %cs:8(%ebp),%al
+       movb    $0x53,%ah
+       movl    %cs:12(%ebp),%ebx
+       movw    %cs:APMREG_CX(%ebx),%cx
+       movw    %cs:APMREG_DX(%ebx),%dx
+       movw    %cs:APMREG_BX(%ebx),%bx
+       pushfl
+       cli
+       pushl   %ds
+       lcall   %cs:(_apminfo+APM_CALL)
+       popl    %ds
+       setc    apmstatus
+       popfl
+#if defined(DEBUG) || defined(DIAGNOSTIC)
+       popl    %gs
+       popl    %fs
+       popl    %es
+       popl    %ds             # see above
+#endif
+       movl    12(%ebp),%esi
+       movw    %ax,APMREG_AX(%esi)
+       movw    %bx,APMREG_BX(%esi)
+       movw    %cx,APMREG_CX(%esi)
+       movw    %dx,APMREG_DX(%esi)
+/* todo: do something with %edi? */
+       cmpl    $0,apmstatus
+       jne     1f
+       xorl    %eax,%eax
+1:     
+       popl    %ebx
+       popl    %edi
+       popl    %esi
+       popl    %ebp
+       ret
+               
+_apm_init_image:
+       .globl  _apm_init_image
+
+8:
+#include "lib/apm_init/apm_init.inc"
+9:
+
+_apm_init_image_size:
+       .globl  _apm_init_image_size
+       .long   9b - 8b
+
+#endif /* APM */
index e3bdb4a..27438f0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: machdep.c,v 1.13 1996/04/21 22:16:31 deraadt Exp $    */
+/*     $OpenBSD: machdep.c,v 1.14 1996/04/29 14:13:15 hvozda Exp $     */
 /*     $NetBSD: machdep.c,v 1.197 1996/04/12 08:44:40 mycroft Exp $    */
 
 /*-
 #include <i386/isa/isa_machdep.h>
 #include <i386/isa/nvram.h>
 
+#include "apm.h"
+
+#if NAPM > 0
+#include <machine/apmvar.h>
+#endif
+
 #ifdef VM86
 #include <machine/vm86.h>
 #endif
@@ -736,6 +742,16 @@ haltsys:
        doshutdownhooks();
 
        if (howto & RB_HALT) {
+#if NAPM > 0 && !defined(APM_NO_POWEROFF)
+               /* turn off, if we can.  But try to turn disk off and
+                * wait a bit first--some disk drives are slow to clean up
+                * and users have reported disk corruption.
+                */
+               delay(500000);
+               apm_set_powstate(APM_DEV_DISK(0xff), APM_SYS_OFF);
+               delay(500000);
+               apm_set_powstate(APM_DEV_ALLDEVS, APM_SYS_OFF);
+#endif
                printf("\n");
                printf("The operating system has halted.\n");
                printf("Please press any key to reboot.\n\n");
@@ -1169,6 +1185,16 @@ init386(first_avail)
        /* call pmap initialization to make new kernel address space */
        pmap_bootstrap((vm_offset_t)atdevbase + IOM_SIZE);
 
+#ifdef USER_LDT
+#define MAXPROC ((MAXGDTSIZ-NGDT)/2)
+#else
+#define MAXPROC (MAXGDTSIZ-NGDT)
+#endif
+       if (maxproc > MAXPROC) {
+               printf("reducing maxproc to %d to fit into gdt\n", MAXPROC);
+               maxproc = MAXPROC;
+       }
+
 #ifdef DDB
        ddb_init();
        if (boothowto & RB_KDB)
index 5de4b47..c20a774 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mainbus.c,v 1.2 1996/04/21 22:16:32 deraadt Exp $     */
+/*     $OpenBSD: mainbus.c,v 1.3 1996/04/29 14:13:25 hvozda Exp $      */
 /*     $NetBSD: mainbus.c,v 1.8 1996/04/11 22:13:37 cgd Exp $  */
 
 /*
 #include <i386/isa/isa_machdep.h>
 
 #include "pci.h"
+#include "apm.h"
+
+#if NAPM > 0
+#include <machine/apmvar.h>
+#endif
 
 int    mainbus_match __P((struct device *, void *, void *));
 void   mainbus_attach __P((struct device *, struct device *, void *));
@@ -64,6 +69,9 @@ union mainbus_attach_args {
        struct pcibus_attach_args mba_pba;
        struct eisabus_attach_args mba_eba;
        struct isabus_attach_args mba_iba;
+#if NAPM > 0
+       struct apm_attach_args mba_aaa;
+#endif
 };
 
 /*
@@ -118,7 +126,12 @@ mainbus_attach(parent, self, aux)
                config_found(self, &mba.mba_pba, mainbus_print);
        }
 #endif
-
+#if NAPM > 0
+       {
+           mba.mba_aaa.aaa_busname = "apm";
+           config_found(self, &mba.mba_aaa, mainbus_print);
+       }
+#endif
 }
 
 int
diff --git a/sys/arch/i386/include/apmvar.h b/sys/arch/i386/include/apmvar.h
new file mode 100644 (file)
index 0000000..75dfd2c
--- /dev/null
@@ -0,0 +1,263 @@
+/*     $NetBSD$        */
+/*
+ *  Copyright (c) 1995 John T. Kohl
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+#ifndef __I386_APM_H__
+#define __I386_APM_H__
+
+/* Advanced Power Management (v1.0 and v1.1 specification)
+ * functions/defines/etc.
+ */
+#define APM_BIOS_FNCODE        (0x53)
+#define APM_SYSTEM_BIOS        (0x15)
+#define APM_BIOS_FN(x) ((APM_BIOS_FNCODE<<8)|(x))
+/*
+ * APM info word from boot loader
+ */
+#define        APM_MAJOR_VERS(info) (((info)&0xff00)>>8)
+#define        APM_MINOR_VERS(info) ((info)&0xff)
+#define APM_16BIT_SUPPORTED    0x00010000
+#define APM_32BIT_SUPPORTED    0x00020000
+#define APM_IDLE_SLOWS         0x00040000
+#define APM_BIOS_PM_DISABLED   0x00080000
+#define APM_BIOS_PM_DISENGAGED 0x00100000
+
+#define        APM_ERR_CODE(regs)      (((regs)->ax & 0xff00) >> 8)
+#define        APM_ERR_PM_DISABLED     0x01
+#define        APM_ERR_REALALREADY     0x02
+#define        APM_ERR_NOTCONN         0x03
+#define        APM_ERR_16ALREADY       0x05
+#define        APM_ERR_16NOTSUPP       0x06
+#define        APM_ERR_32ALREADY       0x07
+#define        APM_ERR_32NOTSUPP       0x08
+#define        APM_ERR_UNRECOG_DEV     0x09
+#define        APM_ERR_ERANGE          0x0A
+#define        APM_ERR_NOTENGAGED      0x0B
+#define APM_ERR_UNABLE         0x60
+#define APM_ERR_NOEVENTS       0x80
+#define        APM_ERR_NOT_PRESENT     0x86
+
+#define APM_DEV_APM_BIOS       0x0000
+#define APM_DEV_ALLDEVS                0x0001
+/* device classes are high byte; device IDs go in low byte */
+#define                APM_DEV_DISPLAY(x)      (0x0100|((x)&0xff))
+#define                APM_DEV_DISK(x)         (0x0200|((x)&0xff))
+#define                APM_DEV_PARALLEL(x)     (0x0300|((x)&0xff))
+#define                APM_DEV_SERIAL(x)       (0x0400|((x)&0xff))
+#define                APM_DEV_NETWORK(x)      (0x0500|((x)&0xff))
+#define                APM_DEV_PCMCIA(x)       (0x0600|((x)&0xff))
+#define                APM_DEV_ALLUNITS        0xff
+
+#define        APM_INSTALLATION_CHECK  0x00    /* int15 only */
+#define        APM_REALMODE_CONNECT    0x01    /* int15 only */
+#define        APM_16BIT_CONNECT       0x02    /* int15 only */
+#define        APM_32BIT_CONNECT       0x03    /* int15 only */
+#define APM_DISCONNECT         0x04    /* %bx = APM_DEV_APM_BIOS */
+#define APM_CPU_IDLE           0x05
+#define APM_CPU_BUSY           0x06
+#define APM_SET_PWR_STATE      0x07
+#define                APM_SYS_READY   0x0000  /* %cx */
+#define                APM_SYS_STANDBY 0x0001
+#define                APM_SYS_SUSPEND 0x0002
+#define                APM_SYS_OFF     0x0003
+#define                APM_LASTREQ_INPROG      0x0004
+#define                APM_LASTREQ_REJECTED    0x0005
+
+/* system standby is device ID (%bx) 0x0001, APM_SYS_STANDBY */
+/* system suspend is device ID (%bx) 0x0001, APM_SYS_SUSPEND */
+
+#define APM_PWR_MGT_ENABLE     0x08
+#define                APM_MGT_ALL     0xffff  /* %bx */
+#define                APM_MGT_DISABLE 0x0     /* %cx */
+#define                APM_MGT_ENABLE  0x1
+
+#define APM_SYSTEM_DEFAULTS    0x09
+#define                APM_DEFAULTS_ALL        0xffff  /* %bx */
+
+#define APM_POWER_STATUS       0x0a
+#define                APM_AC_OFF              0x00
+#define                APM_AC_ON               0x01
+#define                APM_AC_BACKUP           0x02
+#define                APM_AC_UNKNOWN          0xff
+#define                APM_BATT_HIGH           0x00
+#define                APM_BATT_LOW            0x01
+#define                APM_BATT_CRITICAL       0x02
+#define                APM_BATT_CHARGING       0x03
+#define                APM_BATT_UNKNOWN        0xff
+#define                APM_BATT_FLAG_HIGH      0x01
+#define                APM_BATT_FLAG_LOW       0x02
+#define                APM_BATT_FLAG_CRITICAL  0x04
+#define                APM_BATT_FLAG_CHARGING  0x08
+#define                APM_BATT_FLAG_NOBATTERY 0x80
+#define                APM_BATT_LIFE_UNKNOWN   0xff
+#define                BATT_STATE(regp) ((regp)->bx & 0xff)
+#define                BATT_FLAGS(regp) (((regp)->cx & 0xff00) >> 8)
+#define                AC_STATE(regp) (((regp)->bx & 0xff00) >> 8)
+#define                BATT_LIFE(regp) ((regp)->cx & 0xff) /* in % */
+#define                BATT_REMAINING(regp) (((regp)->dx & 0x8000) ? \
+                                     ((regp)->dx & 0x7fff)*60 : \
+                                     ((regp)->dx & 0x7fff))
+#define                BATT_REM_VALID(regp) (((regp)->dx & 0xffff) != 0xffff)
+#define        APM_GET_PM_EVENT        0x0b
+#define                APM_STANDBY_REQ         0x0001 /* %bx on return */
+#define                APM_SUSPEND_REQ         0x0002
+#define                APM_NORMAL_RESUME       0x0003
+#define                APM_CRIT_RESUME         0x0004 /* suspend/resume happened
+                                                 without us */
+#define                APM_BATTERY_LOW         0x0005
+#define                APM_POWER_CHANGE        0x0006
+#define                APM_UPDATE_TIME         0x0007
+#define                APM_CRIT_SUSPEND_REQ    0x0008
+#define                APM_USER_STANDBY_REQ    0x0009
+#define                APM_USER_SUSPEND_REQ    0x000A
+#define                APM_SYS_STANDBY_RESUME  0x000B
+
+#define        APM_GET_POWER_STATE     0x0c
+#define        APM_DEVICE_MGMT_ENABLE  0x0d
+
+#define        APM_DRIVER_VERSION      0x0e
+/* %bx should be DEV value (APM_DEV_APM_BIOS)
+   %ch = driver major vno
+   %cl = driver minor vno
+   return: %ah = conn major; %al = conn minor
+   */
+#define                APM_CONN_MINOR(regp) ((regp)->ax & 0xff)
+#define                APM_CONN_MAJOR(regp) (((regp)->ax & 0xff00) >> 8)
+
+#define APM_PWR_MGT_ENGAGE     0x0F
+#define                APM_MGT_DISENGAGE       0x0     /* %cx */
+#define                APM_MGT_ENGAGE          0x1
+
+#define APM_OEM                        0x80
+
+#ifdef _LOCORE
+/*
+ * LP (Laptop Package)
+ *
+ * Copyright (C) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, and distributed, in
+ * both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author 
+ * responsible for the proper functioning of this software, nor does 
+ * the author assume any responsibility for damages incurred with its 
+ * use.
+ *
+ * Sep., 1994  Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ */
+
+/* Error code of APM initializer */
+#define APMINI_CANTFIND                0xffffffff
+#define APMINI_NOT32BIT                0xfffffffe
+#define APMINI_CONNECTERR      0xfffffffd
+
+#define        SIZEOF_GDTE             8
+#define BOOTSTRAP_GDT_NUM      9       /* see i386/boot/table.c */
+
+#define APM_INIT_CS_INDEX      (BOOTSTRAP_GDT_NUM - 3)
+#define APM_INIT_DS_INDEX      (BOOTSTRAP_GDT_NUM - 2)
+#define APM_INIT_CS16_INDEX    (BOOTSTRAP_GDT_NUM - 1)
+#define APM_INIT_CS_SEL                (APM_INIT_CS_INDEX << 3)
+#define APM_INIT_DS_SEL                (APM_INIT_DS_INDEX << 3)
+#define APM_INIT_CS16_SEL      (APM_INIT_CS16_INDEX << 3)
+
+#define CS32_ATTRIB            0xCF9e
+#define CS16_ATTRIB            0x0F9e
+#define DS32_ATTRIB            0xCF92
+
+#define BOOTSTRAP_DS_SEL       0x10
+/* APM initializer physical address */
+#define APM_OURADDR            0x00080000
+#define APM_RELOC(x)   ((x) - _apm_init_image)
+
+#else /* !_LOCORE */
+
+/* filled in by apmcall */ 
+struct apmregs {
+    u_short ax;
+    u_short bx;
+    u_short cx;
+    u_short dx;
+};
+
+struct apm_connect_info {
+       u_int apm_code32_seg_base;      /* real-mode style segment selector */
+       u_int apm_code16_seg_base;
+       u_int apm_data_seg_base;
+       u_int apm_entrypt;
+       u_short apm_segsel;             /* segment selector for APM */
+       u_short _pad1;
+       u_int apm_code32_seg_len;
+       u_int apm_data_seg_len;
+       u_int apm_detail;
+};
+
+struct apm_event_info {
+       u_int type;
+       u_int index;
+       u_int spare[8];
+};
+
+#define APM_BATTERY_ABSENT 4
+
+struct apm_power_info {
+       u_char battery_state;
+       u_char ac_state;
+       u_char battery_life;
+       u_char spare1;
+       u_int minutes_left;             /* estimate */
+       u_int spare2[6];
+};
+
+struct apm_ctl {
+       u_int dev;
+       u_int mode;
+};
+
+#define        APM_IOC_REJECT  _IOW('A', 0, struct apm_event_info) /* reject request # */
+#define        APM_IOC_STANDBY _IO('A', 1)     /* put system into standby */
+#define        APM_IOC_SUSPEND _IO('A', 2)     /* put system into suspend */
+#define        APM_IOC_GETPOWER _IOR('A', 3, struct apm_power_info) /* fetch battery state */
+#define        APM_IOC_NEXTEVENT _IOR('A', 4, struct apm_event_info) /* fetch event */
+#define        APM_IOC_DEV_CTL _IOW('A', 5, struct apm_ctl) /* put device into mode */
+
+struct apm_attach_args {
+       char *aaa_busname;
+};
+
+#ifdef _KERNEL
+extern struct apm_connect_info apminfo;        /* in locore */
+extern int apmpresent;
+extern int apmcall __P((int function, struct apmregs *regs));
+extern void apm_cpu_busy __P((void));
+extern void apm_cpu_idle __P((void));
+extern void apminit __P((void));
+int apm_set_powstate __P((u_int devid, u_int powstate));
+#endif /* _KERNEL */
+#endif /* _LOCORE */
+#endif /* __i386_apm_h__ */
index ebb8d5b..7b7a6ea 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: gdt.h,v 1.2 1996/04/18 19:21:37 niklas Exp $  */
+/*     $OpenBSD: gdt.h,v 1.3 1996/04/29 14:13:48 hvozda Exp $  */
 /*     $NetBSD: gdt.h,v 1.3 1996/02/27 22:32:11 jtc Exp $      */
 
 /*-
@@ -37,6 +37,9 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#define        MAXGDTSIZ       8192            /* max # entries in an i386 GDT */
+extern union descriptor *dynamic_gdt;
+
 void tss_alloc __P((struct pcb *));
 void tss_free __P((struct pcb *));
 void ldt_alloc __P((struct pcb *, union descriptor *, size_t));
index a1a332e..4558ccc 100644 (file)
@@ -217,7 +217,10 @@ void setsegment __P((struct segment_descriptor *, void *, size_t, int, int,
 #define        GLDT_SEL        3       /* Default LDT descriptor */
 #define        GUCODE_SEL      4       /* User code descriptor */
 #define        GUDATA_SEL      5       /* User data descriptor */
-#define        NGDT            6
+#define        GAPM32CODE_SEL  6
+#define        GAPM16CODE_SEL  7
+#define        GAPMDATA_SEL    8
+#define        NGDT            9
 
 /*
  * Entries in the Local Descriptor Table (LDT)
index 77dd247..5570f7e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: com.c,v 1.11 1996/04/21 22:23:15 deraadt Exp $        */
+/*     $OpenBSD: com.c,v 1.12 1996/04/29 14:16:15 hvozda Exp $ */
 /*     $NetBSD: com.c,v 1.79 1996/04/15 18:54:31 cgd Exp $     */
 
 /*-
@@ -81,6 +81,7 @@
 struct com_softc {
        struct device sc_dev;
        void *sc_ih;
+       bus_chipset_tag_t sc_bc;
        struct tty *sc_tty;
 
        int sc_overflows;
@@ -94,7 +95,6 @@ struct com_softc {
        int sc_hayespbase;
 #endif
 
-       bus_chipset_tag_t sc_bc;
        bus_io_handle_t sc_ioh;
        bus_io_handle_t sc_hayespioh;
 
@@ -102,6 +102,9 @@ struct com_softc {
 #define        COM_HW_NOIEN    0x01
 #define        COM_HW_FIFO     0x02
 #define        COM_HW_HAYESP   0x04
+#define        COM_HW_ABSENT_PENDING   0x08    /* reattached, awaiting close/reopen */
+#define        COM_HW_ABSENT   0x10            /* configure actually failed, or removed */
+#define        COM_HW_REATTACH 0x20            /* reattaching */
 #define        COM_HW_CONSOLE  0x40
        u_char sc_swflags;
 #define        COM_SW_SOFTCAR  0x01
@@ -125,6 +128,8 @@ int comintr __P((void *));
 void compoll __P((void *));
 int comparam __P((struct tty *, struct termios *));
 void comstart __P((struct tty *));
+void com_absent_notify __P((struct com_softc *sc));
+void comstart_pending __P((void *arg));
 
 /*
  * XXX the following two cfattach structs should be different, and possibly
@@ -145,12 +150,17 @@ struct cfattach com_commulti_ca = {
 };
 #endif
 
+
 struct cfdriver com_cd = {
        NULL, "com", DV_TTY
 };
 
 int cominit __P((bus_chipset_tag_t, bus_io_handle_t, int));
 
+#ifndef CONSPEED
+#define        CONSPEED B9600
+#endif
+
 #ifdef COMCONSOLE
 int    comdefaultrate = CONSPEED;              /* XXX why set default? */
 #else
@@ -181,49 +191,201 @@ extern int kgdb_debug_init;
 #define        CLR(t, f)       (t) &= ~(f)
 #define        ISSET(t, f)     ((t) & (f))
 
-/*#include "pcmciabus.h"*/
-#if NPCMCIABUS >0                       
+#if NCOM_PCMCIA
+#include <dev/pcmcia/pcmciavar.h>
+
+int com_pcmcia_match __P((struct device *, void *, void *));
+void com_pcmcia_attach __P((struct device *, struct device *, void *));
+int com_pcmcia_detach __P((struct device *));
+
+struct cfattach com_pcmcia_ca = {
+       sizeof(struct com_softc), com_pcmcia_match, comattach,
+       com_pcmcia_detach
+};
+
+int 
+com_pcmcia_mod __P((struct pcmcia_link *pc_link,
+                   struct device *self,
+                   struct pcmcia_conf *pc_cf,
+                   struct cfdata *cf));
+
 /* additional setup needed for pcmcia devices */
-#include <dev/pcmcia/pcmciabus.h>
 /* modify config entry */
-static int 
-commod(pc_link,self,pc_cf,cf)
+int 
+com_pcmcia_mod(pc_link, self, pc_cf, cf)
     struct pcmcia_link *pc_link;
     struct device *self;
     struct pcmcia_conf *pc_cf; 
     struct cfdata *cf;
 {               
     int err; 
-    struct pcmciadevs *dev=pc_link->device;
+    struct pcmciadevs *dev = pc_link->device;
     struct ed_softc *sc = (void *)self; 
-    if(!(err=pc_link->adapter->bus_link->bus_config(pc_link,self,pc_cf,cf))) {
-        pc_cf->memwin=0;
-       if(pc_cf->cfgtype==0) 
-           pc_cf->cfgtype=CFGENTRYID; /* determine from ioaddr */
+    if (!(err = PCMCIA_BUS_CONFIG(pc_link->adapter, pc_link, self,
+                                 pc_cf, cf))) {
+        pc_cf->memwin = 0;
+       if (pc_cf->cfgtype == 0) 
+           pc_cf->cfgtype = CFGENTRYID; /* determine from ioaddr */
     }
     return err;
 }
+
+int com_pcmcia_isa_attach __P((struct device *, void *, void *,
+                              struct pcmcia_link *));
+int com_pcmcia_remove __P((struct pcmcia_link *, struct device *));
+
 static struct pcmcia_com {
     struct pcmcia_device pcd;
-} pcmcia_com= {
-    "PCMCIA Modem card",commod,NULL,NULL,NULL
+} pcmcia_com =  {
+    {"PCMCIA Modem card", com_pcmcia_mod, com_pcmcia_isa_attach,
+     NULL, com_pcmcia_remove}
 };          
-struct pcmciadevs pcmcia_com_devs[]={
-  { "com", 0, 
+
+
+struct pcmciadevs pcmcia_com_devs[] = {
+  { "com", 0,
   NULL, "*MODEM*", NULL, NULL,
   NULL, (void *)&pcmcia_com 
   },
-  { "com", 0, 
+  { "com", 0,
   NULL, NULL, "*MODEM*", NULL,
   NULL, (void *)&pcmcia_com 
   },
-  { "com", 0, 
+  { "com", 0,
   NULL, NULL, NULL, "*MODEM*",
   NULL, (void *)&pcmcia_com 
   },
   {NULL}
 };
+#define ncom_pcmcia_devs sizeof(pcmcia_com_devs)/sizeof(pcmcia_com_devs[0])
+
+int
+com_pcmcia_match(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       return pcmcia_slave_match(parent, match, aux, pcmcia_com_devs,
+                                 ncom_pcmcia_devs);
+}
+
+int
+com_pcmcia_isa_attach(parent, match, aux, pc_link)
+       struct device *parent;
+       void *match;
+       void *aux;
+       struct pcmcia_link *pc_link;
+{
+       struct isa_attach_args *ia = aux;
+       struct com_softc *sc = match;
+
+       int rval;
+       if (rval = comprobe(parent, sc->sc_dev.dv_cfdata, ia)) {
+               if (ISSET(pc_link->flags, PCMCIA_REATTACH)) {
+#ifdef COM_DEBUG
+                       printf("comreattach, hwflags=%x\n", sc->sc_hwflags);
+#endif
+                       sc->sc_hwflags = COM_HW_REATTACH |
+                               (sc->sc_hwflags & (COM_HW_ABSENT_PENDING|COM_HW_CONSOLE));
+               } else
+                       sc->sc_hwflags = 0;
+       }
+       return rval;
+}
+
+
+/*
+ * Called by config_detach attempts, shortly after com_pcmcia_remove
+ * was called.
+ */
+int
+com_pcmcia_detach(self)
+       struct device *self;
+{
+       struct com_softc *sc = (void *)self;
+
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT_PENDING)) {
+               /* don't let it really be detached, it is still open */
+               return EBUSY;
+       }
+       return 0;               /* OK! */
+}
+
+/*
+ * called by pcmcia framework to accept/reject remove attempts.
+ * If we return 0, then the detach will proceed.
+ */
+int
+com_pcmcia_remove(pc_link, self)
+       struct pcmcia_link *pc_link;
+       struct device *self;
+{
+       struct com_softc *sc = (void *)self;
+       struct tty *tp;
+       int s;
+
+       if (!sc->sc_tty)
+               goto ok;
+       tp = sc->sc_tty;
+
+       /* not in use ?  if so, return "OK" */
+       if (!ISSET(tp->t_state, TS_ISOPEN) &&
+           !ISSET(tp->t_state, TS_WOPEN)) {
+               ttyfree(sc->sc_tty);
+               sc->sc_tty = NULL;
+    ok:
+               isa_intr_disestablish(sc->sc_bc, sc->sc_ih);
+               sc->sc_ih = NULL;
+               SET(sc->sc_hwflags, COM_HW_ABSENT);
+               return 0;               /* OK! */
+       }
+       /*
+        * Not easily removed.  Put device into a dead state, clean state
+        * as best we can.  notify all waiters.
+        */
+       SET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING);
+#ifdef COM_DEBUG
+       printf("pending detach flags %x\n", sc->sc_hwflags);
+#endif
+
+       s = spltty();
+       com_absent_notify(sc);
+       splx(s);
+
+       return 0;
+}
+
+#if 0
+void
+com_pcmcia_attach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct pcmcia_attach_args *paa = aux;
+       
+       printf("com_pcmcia_attach %p %p %p\n", parent, self, aux);
+       delay(2000000);
+       if (!pcmcia_configure(parent, self, paa->paa_link)) {
+               struct com_softc *sc = (void *)self;
+               sc->sc_hwflags |= COM_HW_ABSENT;
+               printf(": not attached\n");
+       }
+}
 #endif
+#endif
+
+/*
+ * must be called at spltty() or higher.
+ */
+void
+com_absent_notify(sc)
+       struct com_softc *sc;
+{
+       struct tty *tp;
+       if (tp = sc->sc_tty) {
+               CLR(tp->t_state, TS_CARR_ON|TS_BUSY);
+               ttyflush(tp, FREAD|FWRITE);
+       }
+}
 
 int
 comspeed(speed)
@@ -351,13 +513,21 @@ comprobe(parent, match, aux)
        int iobase, needioh;
        int rv = 1;
 
+#if NCOM_ISA || NCOM_PCMCIA
+#define IS_ISA(parent) \
+       (!strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa") || \
+        !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "pcmcia"))
+#elif NCOM_ISA
+#define IS_ISA(parent) \
+       !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa")
+#endif
        /*
         * XXX should be broken out into functions for isa probe and
         * XXX for commulti probe, with a helper function that contains
         * XXX most of the interesting stuff.
         */
-#if NCOM_ISA
-       if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
+#if NCOM_ISA || NCOM_PCMCIA
+       if (IS_ISA(parent)) {
                struct isa_attach_args *ia = aux;
 
                bc = ia->ia_bc;
@@ -393,8 +563,8 @@ comprobe(parent, match, aux)
                bus_io_unmap(bc, ioh, COM_NPORTS);
 
 out:
-#if NCOM_ISA
-       if (rv && !strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
+#if NCOM_ISA || NCOM_PCMCIA
+       if (rv && IS_ISA(parent)) {
                struct isa_attach_args *ia = aux;
 
                ia->ia_iosize = COM_NPORTS;
@@ -425,10 +595,16 @@ comattach(parent, self, aux)
         * XXX for commulti attach, with a helper function that contains
         * XXX most of the interesting stuff.
         */
-       sc->sc_hwflags = 0;
+       if (ISSET(sc->sc_hwflags, COM_HW_REATTACH)) {
+               int s;
+               s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+       } else
+           sc->sc_hwflags = 0;
        sc->sc_swflags = 0;
-#if NCOM_ISA
-       if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
+#if NCOM_ISA || NCOM_PCMCIA
+       if (IS_ISA(parent)) {
                struct isa_attach_args *ia = aux;
 
                /*
@@ -457,7 +633,7 @@ comattach(parent, self, aux)
                irq = IRQUNK;
 
                if (ca->ca_noien)
-                       sc->sc_hwflags |= COM_HW_NOIEN;
+                       SET(sc->sc_hwflags, COM_HW_NOIEN);
        } else
 #endif
                panic("comattach: impossible");
@@ -522,8 +698,8 @@ comattach(parent, self, aux)
        bus_io_write_1(bc, ioh, com_mcr, 0);
 
        if (irq != IRQUNK) {
-#if NCOM_ISA
-               if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
+#if NCOM_ISA || NCOM_PCMCIA
+               if (IS_ISA(parent)) {
                        struct isa_attach_args *ia = aux;
 
                        sc->sc_ih = isa_intr_establish(ia->ia_ic, irq,
@@ -576,7 +752,7 @@ comopen(dev, flag, mode, p)
        if (unit >= com_cd.cd_ndevs)
                return ENXIO;
        sc = com_cd.cd_devs[unit];
-       if (!sc)
+       if (!sc || ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING))
                return ENXIO;
 
        if (!sc->sc_tty)
@@ -716,19 +892,30 @@ comclose(dev, flag, mode, p)
 
        (*linesw[tp->t_line].l_close)(tp, flag);
        s = spltty();
-       CLR(sc->sc_lcr, LCR_SBREAK);
-       bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr);
-       bus_io_write_1(bc, ioh, com_ier, 0);
-       if (ISSET(tp->t_cflag, HUPCL) &&
-           !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) {
-               /* XXX perhaps only clear DTR */
-               bus_io_write_1(bc, ioh, com_mcr, 0);
+       if (!ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               /* can't do any of this stuff .... */
+               CLR(sc->sc_lcr, LCR_SBREAK);
+               bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr);
+               bus_io_write_1(bc, ioh, com_ier, 0);
+               if (ISSET(tp->t_cflag, HUPCL) &&
+                   !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) {
+                       /* XXX perhaps only clear DTR */
+                       bus_io_write_1(bc, ioh, com_mcr, 0);
+               }
        }
        CLR(tp->t_state, TS_BUSY | TS_FLUSH);
        if (--comsopen == 0)
                untimeout(compoll, NULL);
        splx(s);
        ttyclose(tp);
+#ifdef COM_DEBUG
+       /* mark it ready for more use if reattached earlier */
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT_PENDING)) {
+           printf("comclose pending cleared\n");
+       }
+#endif
+       CLR(sc->sc_hwflags, COM_HW_ABSENT_PENDING);
+
 #ifdef notyet /* XXXX */
        if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
                ttyfree(tp);
@@ -747,6 +934,13 @@ comread(dev, uio, flag)
        struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
        struct tty *tp = sc->sc_tty;
  
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               int s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+               return EIO;
+       }
+
        return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
 }
  
@@ -759,6 +953,13 @@ comwrite(dev, uio, flag)
        struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
        struct tty *tp = sc->sc_tty;
  
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               int s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+               return EIO;
+       }
+
        return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
 }
 
@@ -800,6 +1001,13 @@ comioctl(dev, cmd, data, flag, p)
        bus_io_handle_t ioh = sc->sc_ioh;
        int error;
 
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               int s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+               return EIO;
+       }
+
        error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
        if (error >= 0)
                return error;
@@ -914,6 +1122,13 @@ comparam(tp, t)
        tcflag_t oldcflag;
        int s;
 
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               int s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+               return EIO;
+       }
+
        /* check requested parameters */
        if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
                return EINVAL;
@@ -1041,6 +1256,18 @@ comparam(tp, t)
        return 0;
 }
 
+void
+comstart_pending(arg)
+       void *arg;
+{
+       struct com_softc *sc = arg;
+       int s;
+
+       s = spltty();
+       com_absent_notify(sc);
+       splx(s);
+}
+
 void
 comstart(tp)
        struct tty *tp;
@@ -1051,6 +1278,16 @@ comstart(tp)
        int s;
 
        s = spltty();
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               /*
+                * not quite good enough: if caller is ttywait() it will
+                * go to sleep immediately, so hang out a bit and then
+                * prod caller again.
+                */
+               com_absent_notify(sc);
+               timeout(comstart_pending, sc, 1);
+               goto out;
+       }
        if (ISSET(tp->t_state, TS_BUSY))
                goto out;
        if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) ||
@@ -1236,6 +1473,9 @@ comintr(arg)
        } iter[32];
 #endif
 
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT) || !sc->sc_tty)
+               return 0;               /* can't do squat. */
+
 #ifdef COM_DEBUG
        n = 0;
        if (ISSET(iter[n].iir = bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND))
index fb05f10..1f0a8f7 100644 (file)
@@ -8,7 +8,7 @@
  * Support is included for Intel 82365SL PCIC controllers and clones
  * thereof.
  *
- * $Id: i82365reg.h,v 1.1 1996/01/15 00:08:50 hvozda Exp $
+ * $Id: i82365reg.h,v 1.2 1996/04/29 14:15:58 hvozda Exp $
  ***********************************************************************/
 
 /*
@@ -30,6 +30,7 @@
  */
 
 #define PCIC_BASE 0x03e0       /* base adddress of pcic register set */
+#define PCIC_NPORTS 2          /* pcic takes 2 ports */
 
 /* First, all the registers */
 #define PCIC_ID_REV    0x00    /* Identification and Revision */
 #define PCIC_INTEL1    0x83    /* Intel 82365SL Rev. 1; Both Memory and I/O */
 #define PCIC_IBM1      0x88    /* IBM PCIC clone; Both Memory and I/O */
 #define PCIC_IBM2      0x89    /* IBM PCIC clone; Both Memory and I/O */
+#define PCIC_146FC6    0x84    /* VL82C146FC6; Both Memory and I/O */
+#define PCIC_146FC7    0x85    /* VL82C146FC7; Both Memory and I/O */
 
 /* For Interface Status register (PCIC_STATUS) */
 #define PCIC_VPPV      0x80    /* Vpp_valid */
 /* For the Interrupt and General Control register (PCIC_INT_GEN) */
 #define PCIC_INT_MASK          0x0f
 #define PCIC_INT_FLAGMASK      0x0f
-#define PCIC_INTR_ENA  0x10    
+#define PCIC_INTR_ENA  0x10    /* clr bit means CSC interrupt goes via IRQ */
 #define PCIC_CARDTYPE  0x20    /* Card Type 0 = memory, 1 = I/O */
 #define                PCIC_IOCARD     0x20
 #define                PCIC_MEMCARD    0x00
 #define PCIC_RINGIND   0x80    
 
 /* For the Card Status Change register (PCIC_STAT_CHG) */
+#define PCIC_GPICH     0x10    /* General Purpose Input (GPI) Change */
 #define PCIC_CDTCH     0x08    /* Card Detect Change */
 #define PCIC_RDYCH     0x04    /* Ready Change */
 #define PCIC_BATWRN    0x02    /* Battery Warning */
 #define PCIC_BATDED    0x01    /* Battery Dead */
 #define PCIC_STCH      0x01    /* Status Change */
 
+/* For the Card Status Change interrupt config register (PCIC_STAT_INT) */
+#define PCIC_CDT_ENA   0x08    /* Card Detect Enable */
+#define PCIC_RDY_ENA   0x04    /* Ready Enable */
+#define PCIC_BATWRN_ENA        0x02    /* Battery Warning */
+#define PCIC_BATDED_ENA        0x01    /* Battery Dead */
+#define PCIC_ST_ENA    0x01    /* Status Change */
+
 /* For the Address Window Enable Register (PCIC_ADDRWINE) */
 #define PCIC_SM0_EN    0x01    /* Memory Window 0 Enable */
 #define PCIC_SM1_EN    0x02    /* Memory Window 1 Enable */
 /* For Card Detect and General Control register (PCIC_CDGC) */
 #define PCIC_16_DL_INH 0x01    /* 16-bit memory delay inhibit */
 #define PCIC_CNFG_RST_EN 0x02  /* configuration reset enable */
-#define PCIC_GPI_EN    0x04    /* GPI Enable */
+#define PCIC_GPI_EN    0x04    /* General Purpose Input (GPI) Enable */
 #define PCIC_GPI_TRANS 0x08    /* GPI Transition Control */
 #define PCIC_CDRES_EN  0x10    /* card detect resume enable */
 #define PCIC_SW_CD_INT 0x20    /* s/w card detect interrupt */
@@ -206,12 +217,16 @@ struct pcic_register {
 };
 struct pcic_regs {
     u_short chip_vers;
-#define PCMICA_CHIP_82365_0   1
-#define PCMICA_CHIP_82365_1   2
-#define PCMICA_CHIP_IBM_1     3
-#define PCMICA_CHIP_IBM_2     4
+#define PCMICA_CHIP_82365_0    1
+#define PCMICA_CHIP_82365_1    2
+#define PCMICA_CHIP_IBM_1      3
+#define PCMICA_CHIP_IBM_2      4
+#define PCMICA_CHIP_146FC6     5
+#define PCMICA_CHIP_146FC7     6
     u_short cnt;
     struct pcic_register reg[128];
 };
 /* DON'T ADD ANYTHING AFTER THIS #endif */
 #endif /* __82365_H__ */
+#ifndef __82365_H__
+#define __82365_H__
index 77dd247..5570f7e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: com.c,v 1.11 1996/04/21 22:23:15 deraadt Exp $        */
+/*     $OpenBSD: com.c,v 1.12 1996/04/29 14:16:15 hvozda Exp $ */
 /*     $NetBSD: com.c,v 1.79 1996/04/15 18:54:31 cgd Exp $     */
 
 /*-
@@ -81,6 +81,7 @@
 struct com_softc {
        struct device sc_dev;
        void *sc_ih;
+       bus_chipset_tag_t sc_bc;
        struct tty *sc_tty;
 
        int sc_overflows;
@@ -94,7 +95,6 @@ struct com_softc {
        int sc_hayespbase;
 #endif
 
-       bus_chipset_tag_t sc_bc;
        bus_io_handle_t sc_ioh;
        bus_io_handle_t sc_hayespioh;
 
@@ -102,6 +102,9 @@ struct com_softc {
 #define        COM_HW_NOIEN    0x01
 #define        COM_HW_FIFO     0x02
 #define        COM_HW_HAYESP   0x04
+#define        COM_HW_ABSENT_PENDING   0x08    /* reattached, awaiting close/reopen */
+#define        COM_HW_ABSENT   0x10            /* configure actually failed, or removed */
+#define        COM_HW_REATTACH 0x20            /* reattaching */
 #define        COM_HW_CONSOLE  0x40
        u_char sc_swflags;
 #define        COM_SW_SOFTCAR  0x01
@@ -125,6 +128,8 @@ int comintr __P((void *));
 void compoll __P((void *));
 int comparam __P((struct tty *, struct termios *));
 void comstart __P((struct tty *));
+void com_absent_notify __P((struct com_softc *sc));
+void comstart_pending __P((void *arg));
 
 /*
  * XXX the following two cfattach structs should be different, and possibly
@@ -145,12 +150,17 @@ struct cfattach com_commulti_ca = {
 };
 #endif
 
+
 struct cfdriver com_cd = {
        NULL, "com", DV_TTY
 };
 
 int cominit __P((bus_chipset_tag_t, bus_io_handle_t, int));
 
+#ifndef CONSPEED
+#define        CONSPEED B9600
+#endif
+
 #ifdef COMCONSOLE
 int    comdefaultrate = CONSPEED;              /* XXX why set default? */
 #else
@@ -181,49 +191,201 @@ extern int kgdb_debug_init;
 #define        CLR(t, f)       (t) &= ~(f)
 #define        ISSET(t, f)     ((t) & (f))
 
-/*#include "pcmciabus.h"*/
-#if NPCMCIABUS >0                       
+#if NCOM_PCMCIA
+#include <dev/pcmcia/pcmciavar.h>
+
+int com_pcmcia_match __P((struct device *, void *, void *));
+void com_pcmcia_attach __P((struct device *, struct device *, void *));
+int com_pcmcia_detach __P((struct device *));
+
+struct cfattach com_pcmcia_ca = {
+       sizeof(struct com_softc), com_pcmcia_match, comattach,
+       com_pcmcia_detach
+};
+
+int 
+com_pcmcia_mod __P((struct pcmcia_link *pc_link,
+                   struct device *self,
+                   struct pcmcia_conf *pc_cf,
+                   struct cfdata *cf));
+
 /* additional setup needed for pcmcia devices */
-#include <dev/pcmcia/pcmciabus.h>
 /* modify config entry */
-static int 
-commod(pc_link,self,pc_cf,cf)
+int 
+com_pcmcia_mod(pc_link, self, pc_cf, cf)
     struct pcmcia_link *pc_link;
     struct device *self;
     struct pcmcia_conf *pc_cf; 
     struct cfdata *cf;
 {               
     int err; 
-    struct pcmciadevs *dev=pc_link->device;
+    struct pcmciadevs *dev = pc_link->device;
     struct ed_softc *sc = (void *)self; 
-    if(!(err=pc_link->adapter->bus_link->bus_config(pc_link,self,pc_cf,cf))) {
-        pc_cf->memwin=0;
-       if(pc_cf->cfgtype==0) 
-           pc_cf->cfgtype=CFGENTRYID; /* determine from ioaddr */
+    if (!(err = PCMCIA_BUS_CONFIG(pc_link->adapter, pc_link, self,
+                                 pc_cf, cf))) {
+        pc_cf->memwin = 0;
+       if (pc_cf->cfgtype == 0) 
+           pc_cf->cfgtype = CFGENTRYID; /* determine from ioaddr */
     }
     return err;
 }
+
+int com_pcmcia_isa_attach __P((struct device *, void *, void *,
+                              struct pcmcia_link *));
+int com_pcmcia_remove __P((struct pcmcia_link *, struct device *));
+
 static struct pcmcia_com {
     struct pcmcia_device pcd;
-} pcmcia_com= {
-    "PCMCIA Modem card",commod,NULL,NULL,NULL
+} pcmcia_com =  {
+    {"PCMCIA Modem card", com_pcmcia_mod, com_pcmcia_isa_attach,
+     NULL, com_pcmcia_remove}
 };          
-struct pcmciadevs pcmcia_com_devs[]={
-  { "com", 0, 
+
+
+struct pcmciadevs pcmcia_com_devs[] = {
+  { "com", 0,
   NULL, "*MODEM*", NULL, NULL,
   NULL, (void *)&pcmcia_com 
   },
-  { "com", 0, 
+  { "com", 0,
   NULL, NULL, "*MODEM*", NULL,
   NULL, (void *)&pcmcia_com 
   },
-  { "com", 0, 
+  { "com", 0,
   NULL, NULL, NULL, "*MODEM*",
   NULL, (void *)&pcmcia_com 
   },
   {NULL}
 };
+#define ncom_pcmcia_devs sizeof(pcmcia_com_devs)/sizeof(pcmcia_com_devs[0])
+
+int
+com_pcmcia_match(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       return pcmcia_slave_match(parent, match, aux, pcmcia_com_devs,
+                                 ncom_pcmcia_devs);
+}
+
+int
+com_pcmcia_isa_attach(parent, match, aux, pc_link)
+       struct device *parent;
+       void *match;
+       void *aux;
+       struct pcmcia_link *pc_link;
+{
+       struct isa_attach_args *ia = aux;
+       struct com_softc *sc = match;
+
+       int rval;
+       if (rval = comprobe(parent, sc->sc_dev.dv_cfdata, ia)) {
+               if (ISSET(pc_link->flags, PCMCIA_REATTACH)) {
+#ifdef COM_DEBUG
+                       printf("comreattach, hwflags=%x\n", sc->sc_hwflags);
+#endif
+                       sc->sc_hwflags = COM_HW_REATTACH |
+                               (sc->sc_hwflags & (COM_HW_ABSENT_PENDING|COM_HW_CONSOLE));
+               } else
+                       sc->sc_hwflags = 0;
+       }
+       return rval;
+}
+
+
+/*
+ * Called by config_detach attempts, shortly after com_pcmcia_remove
+ * was called.
+ */
+int
+com_pcmcia_detach(self)
+       struct device *self;
+{
+       struct com_softc *sc = (void *)self;
+
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT_PENDING)) {
+               /* don't let it really be detached, it is still open */
+               return EBUSY;
+       }
+       return 0;               /* OK! */
+}
+
+/*
+ * called by pcmcia framework to accept/reject remove attempts.
+ * If we return 0, then the detach will proceed.
+ */
+int
+com_pcmcia_remove(pc_link, self)
+       struct pcmcia_link *pc_link;
+       struct device *self;
+{
+       struct com_softc *sc = (void *)self;
+       struct tty *tp;
+       int s;
+
+       if (!sc->sc_tty)
+               goto ok;
+       tp = sc->sc_tty;
+
+       /* not in use ?  if so, return "OK" */
+       if (!ISSET(tp->t_state, TS_ISOPEN) &&
+           !ISSET(tp->t_state, TS_WOPEN)) {
+               ttyfree(sc->sc_tty);
+               sc->sc_tty = NULL;
+    ok:
+               isa_intr_disestablish(sc->sc_bc, sc->sc_ih);
+               sc->sc_ih = NULL;
+               SET(sc->sc_hwflags, COM_HW_ABSENT);
+               return 0;               /* OK! */
+       }
+       /*
+        * Not easily removed.  Put device into a dead state, clean state
+        * as best we can.  notify all waiters.
+        */
+       SET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING);
+#ifdef COM_DEBUG
+       printf("pending detach flags %x\n", sc->sc_hwflags);
+#endif
+
+       s = spltty();
+       com_absent_notify(sc);
+       splx(s);
+
+       return 0;
+}
+
+#if 0
+void
+com_pcmcia_attach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct pcmcia_attach_args *paa = aux;
+       
+       printf("com_pcmcia_attach %p %p %p\n", parent, self, aux);
+       delay(2000000);
+       if (!pcmcia_configure(parent, self, paa->paa_link)) {
+               struct com_softc *sc = (void *)self;
+               sc->sc_hwflags |= COM_HW_ABSENT;
+               printf(": not attached\n");
+       }
+}
 #endif
+#endif
+
+/*
+ * must be called at spltty() or higher.
+ */
+void
+com_absent_notify(sc)
+       struct com_softc *sc;
+{
+       struct tty *tp;
+       if (tp = sc->sc_tty) {
+               CLR(tp->t_state, TS_CARR_ON|TS_BUSY);
+               ttyflush(tp, FREAD|FWRITE);
+       }
+}
 
 int
 comspeed(speed)
@@ -351,13 +513,21 @@ comprobe(parent, match, aux)
        int iobase, needioh;
        int rv = 1;
 
+#if NCOM_ISA || NCOM_PCMCIA
+#define IS_ISA(parent) \
+       (!strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa") || \
+        !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "pcmcia"))
+#elif NCOM_ISA
+#define IS_ISA(parent) \
+       !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa")
+#endif
        /*
         * XXX should be broken out into functions for isa probe and
         * XXX for commulti probe, with a helper function that contains
         * XXX most of the interesting stuff.
         */
-#if NCOM_ISA
-       if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
+#if NCOM_ISA || NCOM_PCMCIA
+       if (IS_ISA(parent)) {
                struct isa_attach_args *ia = aux;
 
                bc = ia->ia_bc;
@@ -393,8 +563,8 @@ comprobe(parent, match, aux)
                bus_io_unmap(bc, ioh, COM_NPORTS);
 
 out:
-#if NCOM_ISA
-       if (rv && !strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
+#if NCOM_ISA || NCOM_PCMCIA
+       if (rv && IS_ISA(parent)) {
                struct isa_attach_args *ia = aux;
 
                ia->ia_iosize = COM_NPORTS;
@@ -425,10 +595,16 @@ comattach(parent, self, aux)
         * XXX for commulti attach, with a helper function that contains
         * XXX most of the interesting stuff.
         */
-       sc->sc_hwflags = 0;
+       if (ISSET(sc->sc_hwflags, COM_HW_REATTACH)) {
+               int s;
+               s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+       } else
+           sc->sc_hwflags = 0;
        sc->sc_swflags = 0;
-#if NCOM_ISA
-       if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
+#if NCOM_ISA || NCOM_PCMCIA
+       if (IS_ISA(parent)) {
                struct isa_attach_args *ia = aux;
 
                /*
@@ -457,7 +633,7 @@ comattach(parent, self, aux)
                irq = IRQUNK;
 
                if (ca->ca_noien)
-                       sc->sc_hwflags |= COM_HW_NOIEN;
+                       SET(sc->sc_hwflags, COM_HW_NOIEN);
        } else
 #endif
                panic("comattach: impossible");
@@ -522,8 +698,8 @@ comattach(parent, self, aux)
        bus_io_write_1(bc, ioh, com_mcr, 0);
 
        if (irq != IRQUNK) {
-#if NCOM_ISA
-               if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
+#if NCOM_ISA || NCOM_PCMCIA
+               if (IS_ISA(parent)) {
                        struct isa_attach_args *ia = aux;
 
                        sc->sc_ih = isa_intr_establish(ia->ia_ic, irq,
@@ -576,7 +752,7 @@ comopen(dev, flag, mode, p)
        if (unit >= com_cd.cd_ndevs)
                return ENXIO;
        sc = com_cd.cd_devs[unit];
-       if (!sc)
+       if (!sc || ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING))
                return ENXIO;
 
        if (!sc->sc_tty)
@@ -716,19 +892,30 @@ comclose(dev, flag, mode, p)
 
        (*linesw[tp->t_line].l_close)(tp, flag);
        s = spltty();
-       CLR(sc->sc_lcr, LCR_SBREAK);
-       bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr);
-       bus_io_write_1(bc, ioh, com_ier, 0);
-       if (ISSET(tp->t_cflag, HUPCL) &&
-           !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) {
-               /* XXX perhaps only clear DTR */
-               bus_io_write_1(bc, ioh, com_mcr, 0);
+       if (!ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               /* can't do any of this stuff .... */
+               CLR(sc->sc_lcr, LCR_SBREAK);
+               bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr);
+               bus_io_write_1(bc, ioh, com_ier, 0);
+               if (ISSET(tp->t_cflag, HUPCL) &&
+                   !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) {
+                       /* XXX perhaps only clear DTR */
+                       bus_io_write_1(bc, ioh, com_mcr, 0);
+               }
        }
        CLR(tp->t_state, TS_BUSY | TS_FLUSH);
        if (--comsopen == 0)
                untimeout(compoll, NULL);
        splx(s);
        ttyclose(tp);
+#ifdef COM_DEBUG
+       /* mark it ready for more use if reattached earlier */
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT_PENDING)) {
+           printf("comclose pending cleared\n");
+       }
+#endif
+       CLR(sc->sc_hwflags, COM_HW_ABSENT_PENDING);
+
 #ifdef notyet /* XXXX */
        if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
                ttyfree(tp);
@@ -747,6 +934,13 @@ comread(dev, uio, flag)
        struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
        struct tty *tp = sc->sc_tty;
  
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               int s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+               return EIO;
+       }
+
        return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
 }
  
@@ -759,6 +953,13 @@ comwrite(dev, uio, flag)
        struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
        struct tty *tp = sc->sc_tty;
  
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               int s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+               return EIO;
+       }
+
        return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
 }
 
@@ -800,6 +1001,13 @@ comioctl(dev, cmd, data, flag, p)
        bus_io_handle_t ioh = sc->sc_ioh;
        int error;
 
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               int s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+               return EIO;
+       }
+
        error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
        if (error >= 0)
                return error;
@@ -914,6 +1122,13 @@ comparam(tp, t)
        tcflag_t oldcflag;
        int s;
 
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               int s = spltty();
+               com_absent_notify(sc);
+               splx(s);
+               return EIO;
+       }
+
        /* check requested parameters */
        if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
                return EINVAL;
@@ -1041,6 +1256,18 @@ comparam(tp, t)
        return 0;
 }
 
+void
+comstart_pending(arg)
+       void *arg;
+{
+       struct com_softc *sc = arg;
+       int s;
+
+       s = spltty();
+       com_absent_notify(sc);
+       splx(s);
+}
+
 void
 comstart(tp)
        struct tty *tp;
@@ -1051,6 +1278,16 @@ comstart(tp)
        int s;
 
        s = spltty();
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+               /*
+                * not quite good enough: if caller is ttywait() it will
+                * go to sleep immediately, so hang out a bit and then
+                * prod caller again.
+                */
+               com_absent_notify(sc);
+               timeout(comstart_pending, sc, 1);
+               goto out;
+       }
        if (ISSET(tp->t_state, TS_BUSY))
                goto out;
        if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) ||
@@ -1236,6 +1473,9 @@ comintr(arg)
        } iter[32];
 #endif
 
+       if (ISSET(sc->sc_hwflags, COM_HW_ABSENT) || !sc->sc_tty)
+               return 0;               /* can't do squat. */
+
 #ifdef COM_DEBUG
        n = 0;
        if (ISSET(iter[n].iir = bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND))
index f145e7b..6303824 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.isa,v 1.10 1996/04/27 18:39:07 niklas Exp $
+#      $OpenBSD: files.isa,v 1.11 1996/04/29 14:16:22 hvozda Exp $
 #      $NetBSD: files.isa,v 1.17 1996/03/29 20:53:30 mycroft Exp $
 #
 # Config.new file and device description for machine-independent ISA code.
@@ -19,27 +19,6 @@ file dev/isa/isa.c                   isa needs-flag
 define isadma
 file   dev/isa/isadma.c                isadma needs-flag
 
-# PCMCIA
-# XXX What is this?
-#config problems
-#device pcic at isa
-#file dev/isa/pcmcia_pcic.c  pcic pcmciabus
-
-define pcicbus {[iomem = -1], [iosiz = 0]}
-
-device pcic: pcicbus
-attach pcic at isa
-file   dev/isa/pcmcia_pcic.c           pcic
-
-file   dev/isa/pcmcia_isa.c            pcmcia
-
-#
-# PCMCIA-only drivers
-#
-
-include "../../../dev/pcmcia/files.pcmcia"
-
-
 #
 # 8250/16[45]50-based multi-port serial boards
 #
@@ -69,7 +48,8 @@ file  dev/isa/rtfps.c                 rtfps
 device com: tty
 attach com at isa with com_isa
 attach com at commulti with com_commulti
-file   dev/isa/com.c                   com & (com_isa | com_commulti) needs-flag
+attach com at pcmcia with com_pcmcia
+file   dev/isa/com.c                   com & (com_isa | com_commulti | com_pcmcia) needs-flag
 
 # Cyclades Cyclom multiport serial cards
 # XXX currently broken
@@ -167,9 +147,10 @@ file       dev/isa/elink.c                 elink
 # National Semiconductor DS8390/WD83C690-based boards
 # (WD/SMC 80x3 family, SMC Ultra [8216], 3Com 3C503, NE[12]000, and clones)
 # XXX conflicts with amiga if_ed.c
-#device        ed: ether, ifnet
-#attach        ed at isa
-#file  dev/isa/if_ed.c                 ed needs-flag
+device ed: ether, ifnet
+attach ed at isa with ed_isa
+attach ed at pcmcia with ed_pcmcia
+file   dev/isa/if_ed.c                 ed & (ed_isa | ed_pcmcia) needs-flag
 
 # 3Com 3C505
 device eg: ether, ifnet
@@ -185,7 +166,8 @@ file        dev/isa/if_el.c                 el
 device ep: ether, ifnet, elink
 attach ep at isa with ep_isa
 attach ep at pci with ep_pci
-file   dev/isa/if_ep.c                 ep needs-flag
+attach ep at pcmcia with ep_pcmcia
+file   dev/isa/if_ep.c                 ep & (ep_isa | ep_pci | ep_pcmcia) needs-flag
 
 # Fujitsu MB8696[05]-based boards
 # (Allied Telesis AT1700)
@@ -265,3 +247,14 @@ file       dev/isa/wss.c                   wss needs-flag
 device gus: audio, isadma, ics2101, ad1848, mulaw
 attach gus at isa
 file   dev/isa/gus.c                   gus needs-flag
+
+#
+# PCMCIA PCIC (i82365SL and compatibles):
+#
+device pcicmaster { [irq = -1], [iomem = -1], [iosiz = 0] }
+attach pcicmaster at isa
+device pcic: pcmciabus
+attach pcic at pcicmaster
+file dev/isa/pcmcia_pcic.c  pcic | pcicmaster
+
+file dev/isa/pcmcia_isa.c  pcmcia
index d770c80..8f2499c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_ed.c,v 1.11 1996/04/27 22:19:59 niklas Exp $       */
+/*     $OpenBSD: if_ed.c,v 1.12 1996/04/29 14:16:31 hvozda Exp $       */
 /*     $NetBSD: if_ed.c,v 1.93 1996/04/11 22:28:55 cgd Exp $   */
 
 /*
@@ -19,6 +19,7 @@
  */
 
 #include "bpfilter.h"
+#include "ed.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -154,9 +155,11 @@ void ed_pio_readmem __P((struct ed_softc *, u_short, caddr_t, u_short));
 void ed_pio_writemem __P((struct ed_softc *, caddr_t, u_short, u_short));
 u_short ed_pio_write_mbufs __P((struct ed_softc *, struct mbuf *, u_short));
 
-struct cfattach ed_ca = {
+#if NED_ISA > 0
+struct cfattach ed_isa_ca = {
        sizeof(struct ed_softc), edprobe, edattach
 };
+#endif
 
 struct cfdriver ed_cd = {
        NULL, "ed", DV_IFNET
@@ -166,17 +169,19 @@ struct cfdriver ed_cd = {
 #define ETHER_MAX_LEN  1518
 #define        ETHER_ADDR_LEN  6
 
-#define        NIC_PUT(bc, ioh, nic, reg, val) \
-       bus_io_write_1((bc), (ioh), ((nic) + (reg)), (val))
-#define        NIC_GET(bc, ioh, nic, reg)      \
-       bus_io_read_1((bc), (ioh), ((nic) + (reg)))
+#if NED_PCMCIA > 0 
+#include <dev/pcmcia/pcmciavar.h>
 
-/*#include "pcmciabus.h"*/
-#if NPCMCIABUS > 0 
+int ed_pcmcia_match __P((struct device *, void *, void *));
+void ed_pcmcia_attach __P((struct device *, struct device *, void *));
+int ed_pcmcia_detach __P((struct device *));
 
-#include <dev/pcmcia/pcmciabus.h>
-static int ed_probe_pcmcia_ne __P((struct device *, void *,
-                                  void *, struct pcmcia_link *));
+struct cfattach ed_pcmcia_ca = {
+       sizeof(struct ed_softc), ed_pcmcia_match, edattach, ed_pcmcia_detach
+};
+
+static int ed_pcmcia_isa_attach __P((struct device *, void *,
+                                    void *, struct pcmcia_link *));
 
 static int edmod __P((struct pcmcia_link *, struct device *,
                      struct pcmcia_conf *, struct cfdata *cf));
@@ -185,7 +190,7 @@ static int ed_remove __P((struct pcmcia_link *, struct device *));
 
 /* additional setup needed for pcmcia devices */
 static int
-ed_probe_pcmcia_ne(parent, match, aux, pc_link)
+ed_pcmcia_isa_attach(parent, match, aux, pc_link)
        struct device *parent;
        void *match;
        void *aux;
@@ -199,17 +204,18 @@ ed_probe_pcmcia_ne(parent, match, aux, pc_link)
        extern int ifqmaxlen;
        u_char enaddr[ETHER_ADDR_LEN];
 
-       if ((int)dev->param >= 0)
+       if ((int)dev->param != -1)
                err = pcmcia_read_cis(pc_link, enaddr, 
                                      (int) dev->param, ETHER_ADDR_LEN);
        else
                err = 0;
        if (err)
-               printf("Cannot read cis info %d\n", err);
+               printf("%s: attaching ed: cannot read cis info %d\n",
+                      parent->dv_xname, err);
 
-       if (ed_probe_Novell(sc, cf, ia)) {
+       if (ed_find_Novell(sc, cf, ia)) {
                delay(100);
-               if ((int)dev->param >= 0) {
+               if ((int)dev->param != -1) {
                    err = pcmcia_read_cis(pc_link, sc->sc_arpcom.ac_enaddr,
                                      (int) dev->param, ETHER_ADDR_LEN);
                    if (err) {
@@ -229,8 +235,8 @@ ed_probe_pcmcia_ne(parent, match, aux, pc_link)
                sc->type_str = dev->model;
                sc->sc_arpcom.ac_if.if_snd.ifq_maxlen=ifqmaxlen;
                return 1;
-       }
-       return 0;
+       } else
+           return 0;
 }
 
 /* modify config entry */
@@ -242,16 +248,20 @@ edmod(pc_link, self, pc_cf, cf)
        struct cfdata *cf;
 {
        int err;
-       struct pcmciadevs *dev=pc_link->device;
-       struct ed_softc *sc = (void *)self;
-       int svec_card = strcmp(dev->manufacturer, "SVEC") == 0;
+/*     struct pcmciadevs *dev=pc_link->device;*/
+/*     struct ed_softc *sc = (void *)self;*/
+       int svec_card =  pc_cf->memwin  == 5;
        int de650_0 = (pc_cf->memwin != 0) && !svec_card;
-       err = pc_link->adapter->bus_link->bus_config(pc_link, self, pc_cf, cf);
+       err = PCMCIA_BUS_CONFIG(pc_link->adapter, pc_link, self, pc_cf, cf);
        if (err)
                return err;
 
        if (svec_card) {
                pc_cf->memwin = 0;
+#if 0
+               pc_cf->cfgid = 32;  /* Try this if it still doesn't work */
+               pc_cf->cfgid |= 32;  /* or Try this if it still doesn't work */
+#endif
        }
        if (de650_0) {
                pc_cf->io[0].flags =
@@ -281,13 +291,15 @@ ed_remove(pc_link,self)
        shutdownhook_disestablish(sc->sc_sh);
        ifp->if_flags &= ~(IFF_RUNNING|IFF_UP);
        sc->spec_flags |= ED_NOTPRESENT;
-       return pc_link->adapter->bus_link->bus_unconfig(pc_link); 
+       isa_intr_disestablish(sc->sc_bc, sc->sc_ih);
+       return PCMCIA_BUS_UNCONFIG(pc_link->adapter, pc_link);
 }
 
 static struct pcmcia_dlink {
        struct pcmcia_device pcd;
-} pcmcia_dlink= {
-       "PCMCIA Novell compatible", edmod, ed_probe_pcmcia_ne, NULL, ed_remove
+} pcmcia_dlink = {
+       {"PCMCIA Novell compatible", edmod, ed_pcmcia_isa_attach,
+        NULL, ed_remove}
 };
 
 struct pcmciadevs pcmcia_ed_devs[]={
@@ -303,16 +315,61 @@ struct pcmciadevs pcmcia_ed_devs[]={
        "Socket EA PCMCIA LAN Adapter Revision D", "Ethernet ID 000000000000",
        NULL, (void *) -1,
        (void *)&pcmcia_dlink },
-       /* probably not right for ethernet address--card does not seem to
-          have it anywhere. */
+      /* something screwed up in ports requested */
       { "ed", 0, "SVEC", "FD605 PCMCIA EtherNet Card", "V1-1", NULL,
-       (void *)0xb4, (void *)&pcmcia_dlink },
-      { "ed", 0, "PMX   ", "PE-200", "ETHERNET", "R01", (void *) 0x110,
-        (void *)&pcmcia_dlink }, /* 0x110 is a guess */
+       (void *)-1, (void *)&pcmcia_dlink },
+#if 0
+      /* not quite right for ethernet adress */
+      { "ed", 0, "PMX   ", "PE-200", "ETHERNET", "R01", (void *)-1,
+        (void *)&pcmcia_dlink },
+#endif
       { NULL }
 };
+
+#define ned_pcmcia_devs sizeof(pcmcia_ed_devs)/sizeof(pcmcia_ed_devs[0])
+
+int
+ed_pcmcia_match(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       return pcmcia_slave_match(parent, match, aux, pcmcia_ed_devs,
+                                 ned_pcmcia_devs);
+}
+
+void
+ed_pcmcia_attach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct pcmcia_attach_args *paa = aux;
+       
+       printf("ed_pcmcia_attach %p %p %p\n", parent, self, aux);
+       delay(2000000);
+       if (!pcmcia_configure(parent, self, paa->paa_link)) {
+               struct ed_softc *sc = (void *)self;
+               sc->spec_flags |= ED_NOTPRESENT;
+               printf(": not attached\n");
+       }
+}
+
+/*
+ * No detach; network devices are too well linked into the rest of the
+ * kernel.
+ */
+int
+ed_pcmcia_detach(self)
+       struct device *self;
+{
+       return EBUSY;
+}
+
 #endif
 
+#define        NIC_PUT(bc, ioh, nic, reg, val) \
+       bus_io_write_1((bc), (ioh), ((nic) + (reg)), (val))
+#define        NIC_GET(bc, ioh, nic, reg)      \
+       bus_io_read_1((bc), (ioh), ((nic) + (reg)))
 
 /*
  * Determine if the device is present.
@@ -1499,7 +1556,6 @@ edinit(sc)
        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        int nicbase = sc->nic_base, asicbase = sc->asic_base;
        int i;
-       u_char command;
        u_long mcaf[2];
 
        /*
@@ -2412,7 +2468,6 @@ ed_pio_write_mbufs(sc, m, dst)
        bus_io_handle_t ioh = sc->sc_ioh;
        int nicbase = sc->nic_base, asicbase = sc->asic_base;
        u_short len;
-       struct mbuf *mp;
        int maxwait = 100; /* about 120us */
 
        len = m->m_pkthdr.len;
index 4102ad2..f9eab4b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_ep.c,v 1.11 1996/04/21 22:23:52 deraadt Exp $       */
+/*     $OpenBSD: if_ep.c,v 1.12 1996/04/29 14:16:41 hvozda Exp $       */
 /*     $NetBSD: if_ep.c,v 1.90 1996/04/11 22:29:15 cgd Exp $   */
 
 /*
@@ -31,8 +31,9 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/*#include "pcmciabus.h"*/
+#include "pcmcia.h"
 #include "bpfilter.h"
+#include "ep.h"
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
@@ -42,6 +43,7 @@
 #include <sys/syslog.h>
 #include <sys/select.h>
 #include <sys/device.h>
+#include <sys/systm.h>
 
 #include <net/if.h>
 #include <net/netisr.h>
@@ -114,26 +116,34 @@ struct ep_softc {
 #define EP_BUS_PCI             0x3
 
 #define EP_IS_BUS_32(a)        ((a) & 0x2)
+
+       u_char  pcmcia_flags;
+#define EP_REATTACH            0x01
+#define EP_ABSENT              0x02
 };
 
 static int epprobe __P((struct device *, void *, void *));
 static void epattach __P((struct device *, struct device *, void *));
 
 /* XXX the following two structs should be different. */
+#if NEP_ISA > 0
 struct cfattach ep_isa_ca = {
        sizeof(struct ep_softc), epprobe, epattach
 };
+#endif
 
+#if NEP_PCI > 0
 struct cfattach ep_pci_ca = {
        sizeof(struct ep_softc), epprobe, epattach
 };
+#endif
+
 
 struct cfdriver ep_cd = {
        NULL, "ep", DV_IFNET
 };
 
 int epintr __P((void *));
-static void epxstat __P((struct ep_softc *));
 static int epstatus __P((struct ep_softc *));
 void epinit __P((struct ep_softc *));
 int epioctl __P((struct ifnet *, u_long, caddr_t));
@@ -142,7 +152,7 @@ void epwatchdog __P((int));
 void epreset __P((struct ep_softc *));
 void epread __P((struct ep_softc *));
 struct mbuf *epget __P((struct ep_softc *, int));
-void epmbuffill __P((struct ep_softc *));
+void epmbuffill __P((void *));
 void epmbufempty __P((struct ep_softc *));
 void epstop __P((struct ep_softc *));
 void epsetfilter __P((struct ep_softc *));
@@ -177,31 +187,39 @@ epaddcard(iobase, irq, bustype)
        epcards[nepcards].bustype = bustype;
        nepcards++;
 }
+       
+#if NEP_PCMCIA > 0
+#include <dev/pcmcia/pcmciavar.h>
+
+int ep_pcmcia_match __P((struct device *, void *, void *));
+void ep_pcmcia_attach __P((struct device *, struct device *, void *));
+int ep_pcmcia_detach __P((struct device *));
 
-#if NPCMCIABUS > 0
-#include <dev/pcmcia/pcmciabus.h>
-static int ep_probe_pcmcia __P((struct device *, void *,
+static int ep_pcmcia_isa_attach __P((struct device *, void *,
                                void *, struct pcmcia_link *));
 static int epmod __P((struct pcmcia_link *, struct device *,
                      struct pcmcia_conf *, struct cfdata * cf));
 static int ep_remove __P((struct pcmcia_link *, struct device *));
 
+struct cfattach ep_pcmcia_ca = {
+       sizeof(struct ep_softc), ep_pcmcia_match, epattach, ep_pcmcia_detach
+};
+
 /* additional setup needed for pcmcia devices */
 static int
-ep_probe_pcmcia(parent, match, aux, pc_link)
+ep_pcmcia_isa_attach(parent, match, aux, pc_link)
        struct device   *parent;
        void            *match;
        void            *aux;
        struct pcmcia_link *pc_link;
 {
        struct ep_softc *sc = (void *) match;
-       struct cfdata  *cf = sc->sc_dev.dv_cfdata;
+/*     struct cfdata  *cf = sc->sc_dev.dv_cfdata;*/
        struct isa_attach_args *ia = aux;
-       struct pcmciadevs *dev = pc_link->device;
+/*     struct pcmciadevs *dev = pc_link->device;*/
        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        int             i;
        extern int      ifqmaxlen;
-       short           addr[3];
 
        outw(ia->ia_iobase + EP_COMMAND, WINDOW_SELECT | 0);
        outw(ia->ia_iobase + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
@@ -211,16 +229,15 @@ ep_probe_pcmcia(parent, match, aux, pc_link)
         * ok til here. Now try to figure out which link we have.
         * try coax first...
         */
-       sc->bustype = EP_BUS_PCMCIA;
 #ifdef EP_COAX_DEFAULT
        outw(ia->ia_iobase + EP_W0_ADDRESS_CFG, 0xC000);
 #else
-       /* COAX as default is reportet to be a problem */
+       /* COAX as default is reported to be a problem */
        outw(ia->ia_iobase + EP_W0_ADDRESS_CFG, 0x0000);
 #endif
        ifp->if_snd.ifq_maxlen = ifqmaxlen;
 
-       epaddcard(ia->ia_iobase, ia->ia_irq, 0);
+       epaddcard(ia->ia_iobase, ia->ia_irq, EP_BUS_PCMCIA);
 
        for (i = 0; i < nepcards; i++) {
                if (epcards[i].available == 0)
@@ -243,10 +260,11 @@ good:
        ia->ia_iosize = 0x10;
        ia->ia_msize = 0;
 
+       sc->bustype = epcards[i].bustype;
+       sc->pcmcia_flags = (pc_link->flags & PCMCIA_REATTACH) ? EP_REATTACH:0;
        return 1;
 }
 
-
 /* modify config entry */
 static int
 epmod(pc_link, self, pc_cf, cf)
@@ -256,11 +274,11 @@ epmod(pc_link, self, pc_cf, cf)
        struct cfdata  *cf;
 {
        int             err;
-       struct pcmciadevs *dev = pc_link->device;
-       struct ep_softc *sc = (void *) self;
+/*     struct pcmciadevs *dev = pc_link->device;*/
+/*     struct ep_softc *sc = (void *) self;*/
 
-       if ((err = pc_link->adapter->bus_link->bus_config(pc_link, self,
-                                                         pc_cf, cf)) != 0) {
+       if ((err = PCMCIA_BUS_CONFIG(pc_link->adapter, pc_link, self,
+                                    pc_cf, cf)) != 0) {
                printf("bus_config failed %d\n", err);
                return err;
        }
@@ -285,13 +303,14 @@ ep_remove(pc_link, self)
        if_down(ifp);
        epstop(sc);
        ifp->if_flags &= ~(IFF_RUNNING | IFF_UP);
-       return pc_link->adapter->bus_link->bus_unconfig(pc_link);
+       sc->pcmcia_flags = EP_ABSENT;
+       return PCMCIA_BUS_UNCONFIG(pc_link->adapter, pc_link);
 }
 
 static struct pcmcia_3com {
        struct pcmcia_device pcd;
 } pcmcia_3com = {
-       "PCMCIA 3COM 3C589", epmod, ep_probe_pcmcia, NULL, ep_remove
+       {"PCMCIA 3COM 3C589", epmod, ep_pcmcia_isa_attach, NULL, ep_remove}
 };
 
 struct pcmciadevs pcmcia_ep_devs[] = {
@@ -312,8 +331,47 @@ struct pcmciadevs pcmcia_ep_devs[] = {
 #endif
        { NULL }
 };
+#define nep_pcmcia_devs sizeof(pcmcia_ep_devs)/sizeof(pcmcia_ep_devs[0])
+
+int
+ep_pcmcia_match(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       return pcmcia_slave_match(parent, match, aux, pcmcia_ep_devs,
+                                 nep_pcmcia_devs);
+}
+
+void
+ep_pcmcia_attach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct pcmcia_attach_args *paa = aux;
+       
+       printf("ep_pcmcia_attach %p %p %p\n", parent, self, aux);
+       delay(2000000);
+       if (!pcmcia_configure(parent, self, paa->paa_link)) {
+               struct ep_softc *sc = (void *)self;
+               sc->pcmcia_flags |= EP_ABSENT;
+               printf(": not attached\n");
+       }
+}
+
+/*
+ * No detach; network devices are too well linked into the rest of the
+ * kernel.
+ */
+int
+ep_pcmcia_detach(self)
+       struct device *self;
+{
+       return EBUSY;
+}
+
 #endif
 
+
 /*
  * 3c579 cards on the EISA bus are probed by their slot number. 3c509
  * cards on the ISA bus are probed in ethernet address order. The probe
@@ -513,14 +571,15 @@ epconfig(sc, conn)
        ifp->if_flags =
            IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
 
-       if_attach(ifp);
-       ether_ifattach(ifp);
+       if ((sc->pcmcia_flags & EP_REATTACH) == 0) {
+               if_attach(ifp);
+               ether_ifattach(ifp);
 
 #if NBPFILTER > 0
-       bpfattach(&sc->sc_arpcom.ac_if.if_bpf, ifp, DLT_EN10MB,
-                 sizeof(struct ether_header));
+               bpfattach(&sc->sc_arpcom.ac_if.if_bpf, ifp, DLT_EN10MB,
+                         sizeof(struct ether_header));
 #endif
-
+       }
        sc->tx_start_thresh = 20;       /* probably a good starting point. */
 }
 
@@ -1219,6 +1278,13 @@ epioctl(ifp, cmd, data)
        int s, error = 0;
 
        s = splnet();
+       if (sc->bustype == EP_BUS_PCMCIA &&
+           (sc->pcmcia_flags & EP_ABSENT)) {
+           if_down(ifp);
+           printf("%s: device offline\n", sc->sc_dev.dv_xname);
+           splx(s);
+           return ENXIO;
+       }
 
        switch (cmd) {
 
@@ -1412,9 +1478,10 @@ epbusyeeprom(sc)
 }
 
 void
-epmbuffill(sc)
-       struct ep_softc *sc;
+epmbuffill(arg)
+       void *arg;
 {
+       struct ep_softc *sc = arg;
        int s, i;
 
        s = splnet();
index d2fd46e..5a485ca 100644 (file)
@@ -1,4 +1,6 @@
+/*     $Id: pcmcia_isa.c,v 1.2 1996/04/29 14:16:47 hvozda Exp $        */
 /*
+ * Copyright (c) 1995,1996 John T. Kohl.  All rights reserved.
  * Copyright (c) 1994 Stefan Grefen.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,7 +28,6 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- *      $Id: pcmcia_isa.c,v 1.1 1996/01/16 20:13:01 hvozda Exp $
  */
 
 /* TODO add modload support and loadable lists of devices */
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/device.h>
+#include <vm/vm.h>
 
-#include <dev/pcmcia/pcmcia.h>
-#include <dev/pcmcia/pcmciabus.h>
+#include <dev/pcmcia/pcmciavar.h>
+#include <dev/pcmcia/pcmciareg.h>
 
 #include <dev/isa/isareg.h>
 #include <dev/isa/isavar.h>
 #define PCMCIA_ISA_DEBUG
 #endif
 
-static int pcmcia_isa_init __P((struct device *, struct cfdata *,
+#ifdef PCMCIA_ISA_DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+STATIC int pcmcia_isa_init __P((struct device *, struct cfdata *,
                                void *, struct pcmcia_adapter *, int));
-static int pcmcia_isa_search __P((struct device *, void *, cfprint_t));
-static int pcmcia_isa_probe __P((struct device *, void *,
+STATIC int pcmcia_isa_search __P((struct device *, void *, cfprint_t));
+STATIC int pcmcia_isa_probe __P((struct device *, void *,
                                 void *, struct pcmcia_link *));
-static int pcmcia_isa_config __P((struct pcmcia_link *, struct device *,
+STATIC int pcmcia_isa_config __P((struct pcmcia_link *, struct device *,
                                  struct pcmcia_conf *, struct cfdata *));
-static int pcmcia_isa_unconfig __P((struct pcmcia_link *));
+STATIC int pcmcia_isa_unconfig __P((struct pcmcia_link *));
 
 struct pcmciabus_link pcmcia_isa_link = {
        pcmcia_isa_config,
@@ -67,7 +75,7 @@ struct pcmciabus_link pcmcia_isa_link = {
 };
 
 /* copy out the addr and length from machine specific attach struct */
-static int
+STATIC int
 pcmcia_isa_init(parent, cf, aux, pca, flag)
        struct device  *parent;
        struct cfdata  *cf;
@@ -75,22 +83,34 @@ pcmcia_isa_init(parent, cf, aux, pca, flag)
        struct pcmcia_adapter *pca;
        int             flag;
 {
-       struct isa_attach_args *ia = aux;
+       struct pcmciabus_attach_args *pa = aux;
+       bus_mem_handle_t memh;
+       vm_offset_t physaddr;
 
 #ifdef PCMCIA_ISA_DEBUG
        if (parent != NULL)
                printf("PARENT %s\n", parent->dv_xname);
 #endif
-       if (flag) {             /* attach */
-               pca->scratch_mem = (caddr_t) ISA_HOLE_VADDR(ia->ia_maddr);
-               pca->scratch_memsiz = ia->ia_msize;
+       if (flag == 0) {                /* match */
+               if (bus_mem_map(pa->pba_bc, pa->pba_maddr, pa->pba_msize, 0,
+                               &memh))
+                       return 0;
+               pca->scratch_memsiz = pa->pba_msize;
+               pca->scratch_memh = memh;
+               pca->pa_bc = pa->pba_bc;
+#ifdef PCMCIA_ISA_DEBUG
+               printf("pbaaddr %p maddr %x msize %x\n",
+                      pa, pa->pba_maddr, pa->pba_msize);
+               printf("PCA %p mem %p size %d chip %x memh %x\n",
+                      pca, pca->scratch_mem, pca->scratch_memsiz,
+                      pca->scratch_chipset, pca->scratch_memh);
+#endif
        }
-       ia->ia_iosize = 0;
        return 1;
 }
 
 /* probe and attach a device, the has to be configured already */
-static int
+STATIC int
 pcmcia_isa_probe(parent, match, aux, pc_link)
        struct device  *parent;
        void           *match;
@@ -103,23 +123,39 @@ pcmcia_isa_probe(parent, match, aux, pc_link)
        struct pcmciadevs *pcs = pc_link->device;
        int (*probe) () = (pcs != NULL) ? pcs->dev->pcmcia_probe : NULL;
 
+       if (cf->cf_loc[6] != -1 && cf->cf_loc[6] != pc_link->slot) {
+#ifdef PCMCIA_ISA_DEBUG
+           printf("- isa probe slot mismatch: cf %d <> link %d\n",
+                  cf->cf_loc[6], pc_link->slot);
+#endif
+           return 0;
+       }
+#if 0
+       if (pcs == NULL || pcs->dev->pcmcia_probe == NULL) {
+#ifdef PCMCIA_ISA_DEBUG
+               printf("- isa probe null proberoutine %p\n", pcs);
+#endif
+               return 0;
+       }
+#endif
        ia.ia_iobase = cf->cf_loc[0];
-       ia.ia_iosize = 0x666;
+       ia.ia_iosize = cf->cf_loc[1] == -1 ? 0x666 : cf->cf_loc[1];
        ia.ia_maddr = cf->cf_loc[2];
        ia.ia_msize = cf->cf_loc[3];
-       ia.ia_irq = cf->cf_loc[4];
+       ia.ia_irq = cf->cf_loc[4] == 2 ? 9 : cf->cf_loc[4] ;
        ia.ia_drq = cf->cf_loc[5];
+       ia.ia_bc = pc_link->bus->sc_bc;
        if (probe == NULL)
-               probe = cf->cf_driver->cd_match;
+               probe = cf->cf_attach->ca_match;
 
 #ifdef PCMCIA_ISA_DEBUG
-       printf("pcmcia probe %x %x %x\n", ia.ia_iobase, ia.ia_irq, probe);
+       printf("pcmcia probe %x %x %p\n", ia.ia_iobase, ia.ia_irq, probe);
        printf("parentname = %s\n", parent->dv_xname);
        printf("devname = %s\n", dev->dv_xname);
        printf("driver name = %s\n", cf->cf_driver->cd_name);
 #endif
        if ((*probe) (parent, dev, &ia, pc_link) > 0) {
-               extern          isaprint();
+               extern isaprint();
                config_attach(parent, dev, &ia, isaprint);
 #ifdef PCMCIA_ISA_DEBUG
                printf("biomask %x netmask %x ttymask %x\n",
@@ -128,7 +164,7 @@ pcmcia_isa_probe(parent, match, aux, pc_link)
 #endif
                return 1;
        }
-       else
+       else if (parent->dv_cfdata->cf_driver->cd_indirect == 0)
                free(dev, M_DEVBUF);
        return 0;
 }
@@ -140,7 +176,7 @@ pcmcia_isa_probe(parent, match, aux, pc_link)
  * contiguous windows and shift according to the offset for the first not
  * fixed window
  */
-static int
+STATIC int
 pcmcia_isa_config(pc_link, self, pc_cf, cf)
        struct pcmcia_link *pc_link;
        struct device  *self;
@@ -148,6 +184,7 @@ pcmcia_isa_config(pc_link, self, pc_cf, cf)
        struct cfdata  *cf;
 {
        struct isa_attach_args ia;
+       struct pcmciadevs *pcs = pc_link->device;
 
        ia.ia_iobase = cf->cf_loc[0];
        ia.ia_iosize = 0x666;
@@ -156,11 +193,19 @@ pcmcia_isa_config(pc_link, self, pc_cf, cf)
        ia.ia_irq = cf->cf_loc[4];
        ia.ia_drq = cf->cf_loc[5];
 #ifdef PCMCIA_ISA_DEBUG
-       printf("pcmcia_isa_config iobase=%x maddr=%x msize=%x irq=%x drq=%x\n",
+       printf("pcmcia_isa_config iobase=%x maddr=%x msize=%x irq=%d drq=%d slot=%d\n",
               ia.ia_iobase, ISA_HOLE_VADDR(ia.ia_maddr), ia.ia_msize,
-              ia.ia_irq, ia.ia_drq);
+              ia.ia_irq, ia.ia_drq, cf->cf_loc[6]);
 #endif
 
+       if (pcs && strcmp(pcs->devname, self->dv_cfdata->cf_driver->cd_name)) {
+#ifdef PCMCIA_ISA_DEBUG
+               printf("- wrong driver %s vs %s\n", pcs->devname,
+                      self->dv_cfdata->cf_driver->cd_name);
+#endif
+               return ENODEV;
+       }
+
        if (ia.ia_irq != IRQUNK) {
                int             irq = 1 << ia.ia_irq;
                /*
@@ -177,7 +222,10 @@ pcmcia_isa_config(pc_link, self, pc_cf, cf)
                        if (irq == (1 << 9) || irq == (1 << 2))
                                irq = (1 << 9) | (1 << 2);
                        if ((irq & pc_cf->irq_mask) == 0) {
-                               printf("irq %d mask %x\n", ia.ia_irq,
+                               printf("%s: slot %d requested irq %d, avail_mask %x\n",
+                                      self->dv_parent->dv_xname,
+                                      pc_link->slot,
+                                      ia.ia_irq,
                                       pc_cf->irq_mask);
                                return ENODEV;
                        }
@@ -247,24 +295,27 @@ pcmcia_isa_config(pc_link, self, pc_cf, cf)
 }
 
 
-static int
+STATIC int
 pcmcia_isa_unconfig(pc_link)
        struct pcmcia_link *pc_link;
 {
+#if 0
        if (pc_link && pc_link->intr > 0) {
                /* THIS IS A GUESS ... TODO check all possible drivers */
                struct softc {
                        struct device   sc_dev;
                        void *sc_ih;
+                       bus_chipset_tag_t sc_bc;
                } *sc = pc_link->devp;
                if (sc)
-                       isa_intr_disestablish(sc->sc_ih);
+                       isa_intr_disestablish(sc->sc_bc, sc->sc_ih);
        }
+#endif
        return 0;
 }
 
 /* Searches for for configured devices on the pcmciabus */
-static int
+STATIC int
 pcmcia_isa_search(parent, aux, print)
        struct device  *parent;
        void           *aux;
index 8e8f16f..dfcf2ea 100644 (file)
@@ -1,3 +1,32 @@
+/*     $Id: pcmcia_pcic.c,v 1.5 1996/04/29 14:16:53 hvozda Exp $       */
+/*
+ *  Copyright (c) 1995, 1996 John T. Kohl
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
 /*
  * Device Driver for Intel 82365 based pcmcia slots
  *
 #include <sys/device.h>
 #include <sys/proc.h>
 #include <sys/user.h>
+#include <sys/cpu.h>
 
 #include <machine/pio.h>
 
 #include <dev/isa/isavar.h>
 #include <dev/ic/i82365reg.h>
 
-#include <dev/pcmcia/pcmciabus.h>
+#include <dev/pcmcia/pcmciavar.h>
+#include <dev/pcmcia/pcmciareg.h>
+
 #ifdef IBM_WD
 #define PCIC_DEBUG 0xf
 #endif
 #define PCDINTR 0x04
 #define PCDSERV 0x08
 #define PCDRW   0x10
+#define PCDCONF 0x20
 int             pcic_debug = PCIC_DEBUG;
 #define DEBUG(a)       (pcic_debug & (a))
 #else
 #define DEBUG(a)       (0)
 #endif
 
-
 /*
  *  pcic_softc: per line info and status
  */
@@ -69,20 +101,26 @@ struct slot {
        struct pcmcia_link *link;
        struct pcic_softc *chip;
 };
+
 struct pcic_softc {
-       struct device   sc_dev;
+       struct device sc_dev;
+       bus_chipset_tag_t sc_bc;
+       struct pcmcia_adapter sc_adapter;
        void *sc_ih;
 
        int     sc_polltimo;
        int     sc_pcic_irq;
-       u_short         pcic_base;      /* base port for each board */
-       u_char          slot_id;
-       u_char          chip_inf;
-       struct slot     slot[2];
-} pcic_softc[4];
+       bus_io_handle_t sc_ioh;
+       bus_mem_handle_t sc_memh;
+       u_short pcic_base;      /* base port for each board */
+       u_char  chip_inf;
+       struct slot slot[4];            /* treat up to 4 as on the same pcic */
+};
+#define pcic_parent(sc) ((struct pcicmaster_softc *)(sc)->sc_dev.dv_parent)
 
 static int      pcic_map_io __P((struct pcmcia_link *, u_int, u_int, int));
-static int      pcic_map_mem __P((struct pcmcia_link *, caddr_t,
+static int      pcic_map_mem __P((struct pcmcia_link *, bus_chipset_tag_t,
+                                 bus_mem_handle_t,
                                  u_int, u_int, int));
 static int      pcic_map_intr __P((struct pcmcia_link *, int, int));
 static int      pcic_service __P((struct pcmcia_link *, int, void *, int));
@@ -94,15 +132,53 @@ static struct pcmcia_funcs pcic_funcs = {
        pcic_service
 };
 
-int             pcicprobe __P((struct device *, void *, void *));
-void            pcicattach __P((struct device  *, struct device *, void *));
+int pcic_probe __P((struct device *, void *, void *));
+void pcic_attach __P((struct device  *, struct device *, void *));
+int pcic_print __P((void *, char *));
+
+int pcicmaster_probe __P((struct device *, void *, void *));
+void pcicmaster_attach __P((struct device  *, struct device *, void *));
+int pcicmaster_print __P((void *, char *));
 
 extern struct pcmciabus_link pcmcia_isa_link;
 
-struct cfdriver pciccd = {
-       NULL, "pcic", pcicprobe, pcicattach, DV_DULL, sizeof(struct pcic_softc)
+struct cfattach pcic_ca = {
+       sizeof(struct pcic_softc), pcic_probe, pcic_attach,
 };
 
+struct cfdriver pcic_cd = {
+       NULL, "pcic", DV_DULL
+};
+
+struct pcicmaster_softc {
+       struct device sc_dev;
+       bus_chipset_tag_t sc_bc;
+       bus_io_handle_t sc_ioh;
+       struct pcic_softc *sc_ctlrs[2];
+       char sc_slavestate[2];
+#define SLAVE_NOTPRESENT       0
+#define SLAVE_FOUND            1
+#define SLAVE_CONFIGURED       2
+};
+
+struct cfattach pcicmaster_ca = {
+       sizeof(struct pcicmaster_softc), pcicmaster_probe, pcicmaster_attach,
+};
+
+struct cfdriver pcicmaster_cd = {
+       NULL, "pcicmaster", DV_DULL, 1
+};
+
+struct pcic_attach_args {
+       int     pia_ctlr;               /* pcic ctlr number */
+       bus_chipset_tag_t pia_bc;       /* bus chipset tag */
+       bus_io_handle_t pia_ioh;        /* base i/o address */
+       int     pia_iosize;             /* span of ports used */
+       int     pia_irq;                /* interrupt request */
+       int     pia_drq;                /* DMA request */
+       int     pia_maddr;              /* physical i/o mem addr */
+       u_int   pia_msize;              /* size of i/o memory */
+};
 
 static u_char pcic_rd __P((struct slot *, int));
 static void pcic_wr __P((struct slot *, int, int));
@@ -114,12 +190,13 @@ pcic_rd(slot, reg)
        int             reg;
 {
        u_char          res;
+       bus_chipset_tag_t bc = slot->chip->sc_bc;
+       bus_io_handle_t ioh =  slot->chip->sc_ioh;
        if (DEBUG(PCDRW))
-               printf("pcic_rd(%x [%x %x]) = ", reg, slot->reg_off,
-                      slot->chip->pcic_base);
-       outb(slot->chip->pcic_base, slot->reg_off + reg);
+               printf("pcic_rd(%x [%x %x]) = ", reg, slot->reg_off, ioh);
+       bus_io_write_1(bc, ioh, 0, slot->reg_off + reg);
        delay(1);
-       res = inb(slot->chip->pcic_base + 1);
+       res = bus_io_read_1(bc, ioh, 1);
        if (DEBUG(PCDRW))
                printf("%x\n", res);
        return res;
@@ -130,15 +207,17 @@ pcic_wr(slot, reg, val)
        struct slot    *slot;
        int             reg, val;
 {
-       outb(slot->chip->pcic_base, slot->reg_off + reg);
+       bus_chipset_tag_t bc = slot->chip->sc_bc;
+       bus_io_handle_t ioh =  slot->chip->sc_ioh;
+       bus_io_write_1(bc, ioh, 0, slot->reg_off + reg);
        delay(1);
-       outb(slot->chip->pcic_base + 1, val);
+       bus_io_write_1(bc, ioh, 1, val);
        if (DEBUG(PCDRW)) {
                int res;
                delay(1);
-               outb(slot->chip->pcic_base, slot->reg_off + reg);
+               bus_io_write_1(bc, ioh, 0, slot->reg_off + reg);
                delay(1);
-               res = inb(slot->chip->pcic_base + 1);
+               res = bus_io_read_1(bc, ioh, 1);
                printf("pcic_wr(%x %x) = %x\n", reg, val, res);
        }
 }
@@ -154,121 +233,214 @@ pcic_wait(slot, i)
 }
 
 int
-pcicprobe(parent, self, aux)
+pcic_probe(parent, self, aux)
        struct device   *parent;
        void            *self;
        void            *aux;
 {
-       struct pcic_softc *pcic = (void *) self;
-       struct isa_attach_args *ia = aux;
-       struct cfdata *cf = pcic->sc_dev.dv_cfdata;
-       u_int           chip_inf = 0;
-       int             i;
+       struct pcic_softc *pcic = self;
+       struct pcicmaster_softc *pcicm = (struct pcicmaster_softc *) parent;
+       struct pcic_attach_args *pia = aux;
+       bus_mem_handle_t memh;
+       u_int           chip_inf = 0, ochip_inf = 0;
+       int first = 1;
+       int             i, j, maxslot;
 
-       pcic->pcic_base = ia->ia_iobase;
-       pcic->slot_id = 0; /* XXX */
        bzero(pcic->slot, sizeof(pcic->slot));
-       pcic->slot[0].chip = pcic;
-       pcic->slot[0].reg_off = (pcic->slot_id & 1) * 0x80;
-       pcic->slot[1].chip = pcic;
-       pcic->slot[1].reg_off = ((pcic->slot_id & 1) * 0x80) + 0x40;
-       chip_inf = pcic_rd(&pcic->slot[0], PCIC_ID_REV);
-       switch (chip_inf) {
-       case PCIC_INTEL0:
+
+       if (DEBUG(PCDCONF)) {
+               printf("pcic_probe controller %d unit %d\n", pia->pia_ctlr,
+                      pcic->sc_dev.dv_unit);
+               delay(2000000);
+       }
+       if (pcicm->sc_slavestate[pia->pia_ctlr] != SLAVE_FOUND)
+               return 0;
+       if (pcic->sc_dev.dv_cfdata->cf_loc[1] == -1 ||
+           pcic->sc_dev.dv_cfdata->cf_loc[2] == 0)
+               return 0;
+
+       /*
+        * select register offsets based on which controller we are.
+        * 2 pcic controllers (w/ 2 slots each) possible at each
+        * IO port location, for a total of 8 possible PCMCIA slots.
+        *
+        * for VLSI controllers, we probe up to 4 slots for the same chip type,
+        * and handle them on one controller.  This is slightly
+        * cheating (two separate pcic's are required for 4 slots, according
+        * to the i82365 spec).
+        * 
+        * For other controllers, we only take up to 2 slots.
+        */
+       pcic->sc_ioh = pia->pia_ioh;
+       pcic->sc_bc = pia->pia_bc;
+       pcic->sc_adapter.nslots = 0;
+       maxslot = 2;
+       for (i = j = 0; i < maxslot; i++) {
+           pcic->slot[j].reg_off = 0x80 * pia->pia_ctlr + 0x40 * i;
+           pcic->slot[j].chip = pcic;
+
+           chip_inf = pcic_rd(&pcic->slot[j], PCIC_ID_REV);
+           if (DEBUG(PCDCONF)) {
+               printf("pcic_probe read info %x\n", chip_inf);
+               delay(2000000);
+           }
+           if (!first && ochip_inf != chip_inf)
+               continue;               /* don't attach, it's different */
+           ochip_inf = chip_inf;
+           switch (chip_inf) {
+           case PCIC_INTEL0:
                pcic->chip_inf = PCMICA_CHIP_82365_0;
                goto ok;
-       case PCIC_INTEL1:
+           case PCIC_INTEL1:
                pcic->chip_inf = PCMICA_CHIP_82365_1;
                goto ok;
-       case PCIC_IBM1:
+           case PCIC_IBM1:
                pcic->chip_inf = PCMICA_CHIP_IBM_1;
                goto ok;
-       case PCIC_IBM2:
+           case PCIC_146FC6:
+               pcic->chip_inf = PCMICA_CHIP_146FC6;
+               maxslot = 4;
+               goto ok;
+           case PCIC_146FC7:
+               pcic->chip_inf = PCMICA_CHIP_146FC7;
+               maxslot = 4;
+               goto ok;
+           case PCIC_IBM2:
                pcic->chip_inf = PCMICA_CHIP_IBM_2;
-ok:
-               ia->ia_msize = 0;
-               ia->ia_iosize = 2;
-               pcmcia_register(pcic, &pcmcia_isa_link, &pcic_funcs,
-                               pcic->slot_id);
+       ok:
+               if (first) {
+                   pcic->sc_adapter.adapter_softc = (void *)pcic;
+                   pcic->sc_adapter.chip_link = &pcic_funcs;
+                   pcic->sc_adapter.bus_link = &pcmcia_isa_link;
+                   pcicm->sc_ctlrs[pia->pia_ctlr] = pcic;
+                   pcicm->sc_slavestate[pia->pia_ctlr] = SLAVE_CONFIGURED;
+                   first = 0;
+               }
+               pcic->sc_adapter.nslots++;
+               j++;
+           default:
+               if (DEBUG(PCDCONF)) {
+                   printf("found ID %x at pcic%d position\n",
+                          chip_inf & 0xff, pcic->sc_dev.dv_unit);
+               }
+               continue;
+           }
+       }
+       if (pcic->sc_adapter.nslots != 0) {
+               pcic->sc_memh = memh;
                return 1;
-       default:
-               printf("found ID %x at pcic position\n", chip_inf & 0xff);
-               break;
        }
-       /* reset mappings .... */
-       pcic_wr(&pcic->slot[0], PCIC_POWER, pcic->slot[0].pow=PCIC_DISRST);
-       pcic_wr(&pcic->slot[1], PCIC_POWER, pcic->slot[1].pow=PCIC_DISRST);
-
-       delay(1000);
-
-       for (i = PCIC_INT_GEN; i < 0x40; i++) {
-               pcic_wr(&pcic->slot[0], i, 0);
-               pcic_wr(&pcic->slot[1], i, 0);
+       if (DEBUG(PCDCONF)) {
+               printf("pcic_probe failed\n");
+               delay(2000000);
        }
-       delay(10000);
+       bus_mem_unmap(pia->pia_bc, memh, pia->pia_msize);
        return 0;
 }
 
 int
 pcic_intr __P((void *));
 
+int
+pcic_print(aux, name)
+       void *aux;
+       char *name;
+{
+       if (name != NULL)       
+               printf("%s: pcmciabus ", name);
+       return UNCONF;
+}
 
 void
-pcicattach(parent, self, aux)
+pcic_attach(parent, self, aux)
        struct device  *parent, *self;
        void           *aux;
 {
        struct pcic_softc *pcic = (void *) self;
-       struct isa_attach_args *ia = aux;
+       struct pcic_attach_args *pia = aux;
+       struct pcmciabus_attach_args pba;
        struct slot *slot;
        int i;
        static char    *pcic_names[] = {
                "Intel 82365sl Rev. 0",
                "Intel 82365sl Rev. 1",
                "IBM 82365sl clone Rev. 1",
-       "IBM 82365sl clone Rev. 2"};
-       printf(": %s slots %d-%d (%x %x)\n", pcic_names[pcic->chip_inf -
-           PCMICA_CHIP_82365_0], pcic->slot_id * 2, pcic->slot_id * 2 + 1,
-              &pcic->slot[0], &pcic->slot[1]);
+               "IBM 82365sl clone Rev. 2",
+               "VL82146 (82365sl clone) Rev. 6",
+               "VL82146 (82365sl clone) Rev. 7" };
+       if (DEBUG(PCDCONF)) {
+               printf("pcic_attach found\n");
+               delay(2000000);
+       }
+       pia->pia_irq = self->dv_cfdata->cf_loc[0];
+       pia->pia_maddr = self->dv_cfdata->cf_loc[1];
+       pia->pia_msize = self->dv_cfdata->cf_loc[2];
+
+       printf(": %s slots %d-%d iomem %x-%x",
+              pcic_names[pcic->chip_inf - PCMICA_CHIP_82365_0],
+              pcic->sc_dev.dv_unit * 2,
+              pcic->sc_dev.dv_unit * 2 + pcic->sc_adapter.nslots - 1,
+              pia->pia_maddr, pia->pia_maddr + pia->pia_msize - 1);
+       if (pia->pia_irq != IRQUNK)
+               printf(" irq %d\n", pia->pia_irq);
+       else
+               printf("\n");
+       if (DEBUG(PCDCONF))
+               delay(2000000);
+
+#ifdef PCMCIA_ISA_DEBUG
+       printf("pcic %p slots %p,%p\nisaaddr %p ports %x size %d irq %d drq %d maddr %x msize %x\n",
+              pcic, &pcic->slot[0], &pcic->slot[1],
+              pia, pia->pia_ioh, pia->pia_iosize,
+              pia->pia_irq, pia->pia_drq, pia->pia_maddr, pia->pia_msize);
+       if (DEBUG(PCDCONF))
+               delay(2000000);
+#endif
+
        /* enable interrupts on events */
-       if (ia->ia_irq != IRQUNK)
-           pcic->sc_pcic_irq = ia->ia_irq;
+       if (pia->pia_irq != IRQUNK)
+           pcic->sc_pcic_irq = pia->pia_irq;
        else
            pcic->sc_pcic_irq = 0;
 
-       for (i = 0; i < 2; i++) {
-           slot = &pcic->slot[i];
-           slot->irq = pcic->sc_pcic_irq |  PCIC_INTR_ENA;
-           pcic_wr(slot, PCIC_STAT_INT,
-                   (pcic->sc_pcic_irq << 4) |PCIC_CDTCH | PCIC_STCH);
-           pcic_wr(&pcic->slot[i], PCIC_INT_GEN, slot->irq);
-           (void) pcic_rd(&pcic->slot[i], PCIC_STAT_CHG);
+       for (i = 0; i < pcic->sc_adapter.nslots; i++) {
+               slot = &pcic->slot[i];
+               /*
+                * Arrange for card status change interrupts
+                * to be steered to specified IRQ.
+                * Treat all cards as I/O cards for the moment so we get
+                * sensible card change interrupt codes (besides, we don't
+                * support memory cards :)
+                */
+               pcic_wr(slot, PCIC_STAT_INT,
+                       (pcic->sc_pcic_irq << 4) |
+                       PCIC_CDTCH | PCIC_IOCARD);
+               slot->irq = pcic_rd(slot, PCIC_INT_GEN) & ~PCIC_INTR_ENA;
+               pcic_wr(slot, PCIC_INT_GEN, slot->irq);
+               (void) pcic_rd(slot, PCIC_STAT_CHG);
        }
-       if (ia->ia_irq == IRQUNK) {
+       if (pia->pia_irq == IRQUNK) {
            pcic->sc_polltimo = hz/2;
            timeout((void (*)(void *))pcic_intr, pcic, pcic->sc_polltimo);
        } else {
-           pcic->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE,
-                                            IPL_NET, pcic_intr, pcic, pcic->sc_dev.dv_xname);
+           pcic->sc_ih = isa_intr_establish(pia->pia_bc,
+                                            pia->pia_irq, IST_EDGE,
+                                            IPL_PCMCIA, pcic_intr, pcic, pcic->sc_dev.dv_xname);
            pcic->sc_polltimo = 0;
        }
-}
-
-#ifdef DDB
-int pcic_intr_test(slot)
-struct slot *slot;
-{
-    printf("CSC interrupt state: %x\n", pcic_rd(slot, PCIC_STAT_INT));
-    printf("General interrupt state: %x\n", pcic_rd(slot, PCIC_INT_GEN));
-}
-
-int pcic_intr_set(slot)
-struct slot *slot;
-{
-    pcic_wr(slot, PCIC_INT_GEN, pcic_rd(slot, PCIC_INT_GEN)|PCIC_INTR_ENA);
-    pcic_intr_test(slot);
-}
+       /*
+        * Probe the pcmciabus at this controller.
+        */
+       pba.pba_bc = pia->pia_bc;
+       pba.pba_maddr = pia->pia_maddr;
+       pba.pba_msize = pia->pia_msize;
+       pba.pba_aux = &pcic->sc_adapter;
+#ifdef PCMCIA_DEBUG
+       printf("config_found(%p, %p, %p)\n",
+              self, &pba, pcic_print);
 #endif
+       config_found(self, (void *)&pba, pcic_print);
+}
 
 int
 pcic_intr(arg)
@@ -278,14 +450,17 @@ void *arg;
        u_char statchg, intgen;
        register int i;
 
+#ifdef PCMCIA_PCIC_DEBUG
        if (pcic->sc_polltimo == 0)
                printf("%s: interrupt:", pcic->sc_dev.dv_xname);
-       for (i = 0; i < 2; i++) {
+#endif
+       for (i = 0; i < pcic->sc_adapter.nslots; i++) {
                struct pcmcia_link *link = pcic->slot[i].link;
                statchg = pcic_rd(&pcic->slot[i], PCIC_STAT_CHG);
                if (statchg == 0)
                        continue;
                intgen = pcic_rd(&pcic->slot[i], PCIC_INT_GEN);
+#ifdef PCMCIA_PCIC_DEBUG
                if (intgen & PCIC_IOCARD) {
                        printf("%s: slot %d iocard status %s%s\n", 
                               pcic->sc_dev.dv_xname, i,
@@ -295,6 +470,7 @@ void *arg;
                        printf("%s: slot %d memcard status %x\n",
                               pcic->sc_dev.dv_xname, i, statchg);
                } 
+#endif
                if ((statchg & PCIC_CDTCH) &&
                    (link->flags & PCMCIA_SLOT_OPEN) == 0) {
 #if 0
@@ -330,7 +506,10 @@ pcic_map_io(link, start, len, flags)
        int             flags;
 {
        struct pcic_softc *sc = link->adapter->adapter_softc;
-       struct slot    *slot = &sc->slot[link->slot & 1];
+       struct slot    *slot;
+       if (link->slot >= sc->sc_adapter.nslots)
+               return ENXIO;
+       slot = &sc->slot[link->slot];
 
        len--;
        if (DEBUG(PCDIO)) {
@@ -403,10 +582,8 @@ pcic_map_io(link, start, len, flags)
                delay(1000);
                return 0;
        } else {
-               u_int           stop;
                int             window;
                int             winid;
-               int             ioflags;
                if (flags & PCMCIA_LAST_WIN) {
                        window = MAX_IOSECTION - 1;
                } else if (flags & PCMCIA_FIRST_WIN) {
@@ -440,26 +617,33 @@ pcic_map_io(link, start, len, flags)
 
                slot->io_addr[window] = start;
                slot->io_len[window] = len;
+               return 0;
        }
-
 }
+
 static int
-pcic_map_mem(link, haddr, start, len, flags)
+pcic_map_mem(link, bc, ioh, start, len, flags)
        struct pcmcia_link *link;
-       caddr_t         haddr;
+       bus_chipset_tag_t bc;
+       bus_mem_handle_t ioh;
        u_int           start, len;
        int             flags;
 {
-       struct pcic_softc *sc = link->adapter->adapter_softc;
-       struct slot    *slot = &sc->slot[link->slot & 1];
        vm_offset_t     physaddr;
+       struct pcic_softc *sc = link->adapter->adapter_softc;
+       struct slot    *slot;
+       caddr_t haddr = ioh;            /* XXX */
+       if (link->slot >= sc->sc_adapter.nslots)
+               return ENXIO;
+
+       slot = &sc->slot[link->slot];
 
        if (flags & PCMCIA_PHYSICAL_ADDR)
                physaddr = (vm_offset_t) haddr;
        else
                physaddr = pmap_extract(pmap_kernel(), (vm_offset_t) haddr);
        if (DEBUG(PCDMEM))
-               printf("pcic_map_mem %x %x %x %x %x\n", haddr, physaddr,
+               printf("pcic_map_mem %p %lx %x %x %x\n", haddr, physaddr,
                       start, len, flags);
 
        (u_long) physaddr >>= 12;
@@ -491,7 +675,7 @@ pcic_map_mem(link, haddr, start, len, flags)
 
                offs = (start - (u_long) physaddr) & 0x3fff;
                if (DEBUG(PCDMEM))
-                       printf("mapmem 2:%x %x %x\n", offs, physaddr + offs,
+                       printf("mapmem 2:%x %lx %x\n", offs, physaddr + offs,
                               start);
 
                stop = (u_long) physaddr + len;
@@ -503,7 +687,7 @@ pcic_map_mem(link, haddr, start, len, flags)
                        (u_long) physaddr & 0xff);
                pcic_wr(slot, winid | PCIC_START | PCIC_ADDR_HIGH,
                        (((u_long) physaddr >> 8) & 0x3f) |
-               /* PCIC_ZEROWS|/* */
+               /* PCIC_ZEROWS| */
                        ((flags & PCMCIA_MAP_16) ? PCIC_DATA16 : 0));
 
                pcic_wr(slot, winid | PCIC_END | PCIC_ADDR_LOW,
@@ -527,8 +711,6 @@ pcic_map_mem(link, haddr, start, len, flags)
                delay(1000);
                return 0;
        } else {
-               u_int           offs;
-               u_int           stop;
                int             window;
                int             winid;
 
@@ -571,20 +753,24 @@ pcic_map_mem(link, haddr, start, len, flags)
                return 0;
        }
 }
+
 static int
 pcic_map_intr(link, irq, flags)
        struct pcmcia_link *link;
        int             irq, flags;
 {
        struct pcic_softc *sc = link->adapter->adapter_softc;
-       struct slot    *slot = &sc->slot[link->slot & 1];
+       struct slot    *slot;
+       if (link->slot >= sc->sc_adapter.nslots)
+               return ENXIO;
+
+       slot = &sc->slot[link->slot];
 
        if (DEBUG(PCDINTR))
                printf("pcic_map_intr %x %x\n", irq, flags);
 
        if (flags & PCMCIA_UNMAP) {
-               slot->irq &= ~PCIC_INT_MASK;
-               slot->irq |= sc->sc_pcic_irq | PCIC_INTR_ENA;
+               slot->irq &= ~(PCIC_INT_MASK|PCIC_INTR_ENA);
                pcic_wr(slot, PCIC_INT_GEN, slot->irq);
        }
        else {
@@ -592,8 +778,8 @@ pcic_map_intr(link, irq, flags)
                        return EINVAL;
                if(irq==2)
                    irq=9;
-               slot->irq = (slot->irq & PCIC_INT_FLAGMASK) |
-                   irq | PCIC_INTR_ENA;
+               slot->irq &= ~(PCIC_INTR_ENA|PCIC_INT_MASK);
+               slot->irq |= irq | PCIC_CARDRESET;      /* reset is inverted */
                pcic_wr(slot, PCIC_INT_GEN, slot->irq);
        }
        return 0;
@@ -608,7 +794,11 @@ pcic_service(link, opcode, arg, flags)
        int             flags;
 {
        struct pcic_softc *sc = link->adapter->adapter_softc;
-       struct slot    *slot = &sc->slot[link->slot & 1];
+       struct slot    *slot;
+       if (link->slot >= sc->sc_adapter.nslots)
+               return ENXIO;
+
+       slot = &sc->slot[link->slot];
 
        slot->link = link;              /* save it for later :) */
        switch (opcode) {
@@ -656,7 +846,10 @@ pcic_service(link, opcode, arg, flags)
 
                        if (DEBUG(PCDSERV))
                                printf("pcic_service(reset)\n");
-                       slot->irq |= flags ? PCIC_IOCARD : 0;
+                       if (flags)
+                               slot->irq |= PCIC_IOCARD;
+                       else
+                               slot->irq &= ~PCIC_IOCARD; /* XXX? */
                        pcic_wr(slot, PCIC_POWER, slot->pow &= ~PCIC_DISRST);
                        slot->irq &= ~PCIC_CARDRESET;
                        pcic_wr(slot, PCIC_INT_GEN, slot->irq);
@@ -683,7 +876,8 @@ pcic_service(link, opcode, arg, flags)
                                printf("pcic_service(power): ");
                        if (flags & PCMCIA_POWER_ON) {
                                int nv = (PCIC_DISRST|PCIC_OUTENA);
-                               pcic_wr(slot, PCIC_INT_GEN, slot->irq = 0);
+                               pcic_wr(slot, PCIC_INT_GEN,
+                                       slot->irq = PCIC_IOCARD);
                                if(flags & PCMCIA_POWER_3V)
                                        nv |= PCIC_VCC3V;
                                if(flags & PCMCIA_POWER_5V)
@@ -731,3 +925,136 @@ pcic_service(link, opcode, arg, flags)
                return EINVAL;
        }
 }
+
+/*
+ * Handle I/O space mapping for children.  Thin layer.
+ */
+int
+pcicmaster_probe(parent, self, aux)
+       struct device *parent;
+       void *self;
+       void *aux;
+{
+       struct pcicmaster_softc *pcicm = self;
+       struct isa_attach_args *ia = aux;
+       struct cfdata *cf = pcicm->sc_dev.dv_cfdata;
+       bus_chipset_tag_t bc;
+       bus_io_handle_t ioh;
+
+       u_int           chip_inf = 0;
+       int             i, j;
+       int rval = 0;
+       struct pcic_softc pcic;         /* faked up for probing only */
+
+       if (DEBUG(PCDCONF)) {
+               printf("pcicmaster_probe\n");
+               delay(2000000);
+       }
+       bc = ia->ia_bc;
+       if (bus_io_map(bc, ia->ia_iobase, PCIC_NPORTS, &ioh))
+               return (0);
+       /*
+        * Probe the slots for each of the possible child controllers,
+        * and if any are there we return a positive indication.
+        */
+       pcic.sc_ioh = ioh;
+       for (i = 0; i < 2; i++) {
+               bzero(pcic.slot, sizeof(pcic.slot));
+               pcic.slot[0].chip = &pcic;
+               pcic.slot[0].reg_off = i * 0x80;
+               chip_inf = pcic_rd(&pcic.slot[0], PCIC_ID_REV);
+               switch (chip_inf) {
+               case PCIC_INTEL0:
+               case PCIC_INTEL1:
+               case PCIC_IBM1:
+               case PCIC_146FC6:
+               case PCIC_146FC7:
+               case PCIC_IBM2:
+                       if (DEBUG(PCDCONF)) {
+                               printf("pcicmaster_probe found, cf=%p\n", cf);
+                               delay(2000000);
+                       }
+                       pcicm->sc_slavestate[i] = SLAVE_FOUND;
+                       rval++;
+                       break;
+               default:
+                       pcicm->sc_slavestate[i] = SLAVE_NOTPRESENT;
+                       if (DEBUG(PCDCONF)) {
+                           printf("found ID %x at slave %d\n",
+                                  chip_inf & 0xff, i);
+                       }
+                       break;
+               }
+               if (pcicm->sc_slavestate[i] != SLAVE_FOUND) {
+                       /* reset mappings .... */
+                       pcic_wr(&pcic.slot[0], PCIC_POWER,
+                               pcic.slot[0].pow=PCIC_DISRST);
+                       delay(1000);
+                       for (j = PCIC_INT_GEN; j < 0x40; j++) {
+                               pcic_wr(&pcic.slot[0], j, 0);
+                       }
+                       delay(10000);
+               }
+       }
+       if (rval) {
+               ia->ia_iosize = 2;
+               pcicm->sc_bc = bc;
+               pcicm->sc_ioh = ioh;
+       } else
+           bus_io_unmap(bc, ioh, PCIC_NPORTS);
+       return rval;
+}
+
+void
+pcicmaster_attach(parent, self, aux)
+       struct device  *parent, *self;
+       void           *aux;
+{
+       struct pcicmaster_softc *pcicm = (void *) self;
+       struct isa_attach_args *ia = aux;
+       struct pcic_attach_args pia;
+       int i;
+       printf("\n");
+       if (DEBUG(PCDCONF)) {
+               printf("pcicmaster_attach\n");
+               delay(2000000);
+       }
+#ifdef PCMCIA_ISA_DEBUG
+       printf("pcicm %p isaaddr %p ports %x size %d irq %d drq %d maddr %x msize %x\n",
+              pcicm, ia, ia->ia_iobase, ia->ia_iosize,
+              ia->ia_irq, ia->ia_drq, ia->ia_maddr, ia->ia_msize);
+       if (DEBUG(PCDCONF))
+               delay(2000000);
+#endif
+       /* attach up to two PCICs at this I/O address */
+       for (i = 0; i < 2; i++) {
+               if (pcicm->sc_slavestate[i] == SLAVE_FOUND) {
+                       pia.pia_ctlr = i;
+                       /*
+                        * share the I/O space and memory mapping space.
+                        */
+                       pia.pia_bc = pcicm->sc_bc;
+                       pia.pia_ioh = pcicm->sc_ioh;
+                       pia.pia_iosize = ia->ia_iosize;
+                       pia.pia_drq = ia->ia_drq;
+#if 0
+                       pia.pia_irq = ia->ia_irq;
+                       pia.pia_irq = cf->cf_loc[0]; /* irq from master attach */
+                       pia.pia_maddr = ia->ia_maddr + (ia->ia_msize / 2) * i;
+                       pia.pia_msize = ia->ia_msize / 2;
+#endif
+
+                       config_found(self, &pia, pcicmaster_print);
+               }
+       }
+}
+
+int
+pcicmaster_print(aux, name)
+       void *aux;
+       char *name;
+{
+       if (name != NULL)       
+               printf("%s: master controller ", name);
+       return UNCONF;
+}
index 7626705..293048e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: wd.c,v 1.10 1996/04/21 22:24:40 deraadt Exp $ */
+/*     $OpenBSD: wd.c,v 1.11 1996/04/29 14:17:00 hvozda Exp $  */
 /*     $NetBSD: wd.c,v 1.148 1996/04/11 22:30:31 cgd Exp $     */
 
 /*
@@ -57,7 +57,8 @@
 #include <dev/isa/isadmavar.h>
 #include <dev/isa/wdreg.h>
 
-#define        WAITTIME        (4 * hz)        /* time to wait for a completion */
+#define        WAITTIME        (8 * hz)        /* time to wait for a completion
+                                          (long enough for disk spin-ups) */
 #define        RECOVERYTIME    (hz / 2)        /* time to recover from an error */
 
 #define WDCDELAY       100
@@ -67,7 +68,7 @@
 #define WDCNDELAY_DEBUG        10
 #endif
 
-#define        WDIORETRIES     5               /* number of retries before giving up */
+#define        WDIORETRIES     3               /* number of retries before giving up */
 
 #define        WDUNIT(dev)                     DISKUNIT(dev)
 #define        WDPART(dev)                     DISKPART(dev)
@@ -587,7 +588,7 @@ loop:
                wd->sc_blkno = blkno / (lp->d_secsize / DEV_BSIZE);
        } else {
 #ifdef WDDEBUG
-               printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts));
+               printf(" %d)%x", wd->sc_skip, inb(wdc->sc_iobase+wd_altsts));
 #endif
        }
 
@@ -696,7 +697,7 @@ loop:
 
 #ifdef WDDEBUG
                printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
-                   cylin, head, bp->b_data, inb(wd->sc_iobase+wd_altsts));
+                   cylin, head, bp->b_data, inb(wdc->sc_iobase+wd_altsts));
 #endif
        } else if (wd->sc_nblks > 1) {
                /* The number of blocks in the last stretch may be smaller. */
@@ -743,11 +744,9 @@ wdcintr(arg)
        struct wd_softc *wd;
        struct buf *bp;
 
-       if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
-               /* Clear the pending interrupt and abort. */
-               (void) inb(wdc->sc_iobase+wd_status);
+       if ((wdc->sc_flags & WDCF_ACTIVE) == 0)
+               /* leave it alone if we didn't ask for this interrupt */
                return 0;
-       }
 
        wdc->sc_flags &= ~WDCF_ACTIVE;
        untimeout(wdctimeout, wdc);
@@ -756,7 +755,7 @@ wdcintr(arg)
        bp = wd->sc_q.b_actf;
 
 #ifdef WDDEBUG
-       printf("I%d ", ctrlr);
+       printf("I%s ", wdc->sc_dev.dv_xname);
 #endif
 
        if (wait_for_unbusy(wdc) < 0) {
@@ -781,7 +780,6 @@ wdcintr(arg)
 
        /* Have we an error? */
        if (wdc->sc_status & WDCS_ERR) {
-       lose:
 #ifdef WDDEBUG
                wderror(wd, NULL, "wdcintr");
 #endif
@@ -795,8 +793,9 @@ wdcintr(arg)
                        goto bad;
 #endif
        
-               if (++wdc->sc_errors < WDIORETRIES)
-                       goto restart;
+               wdcunwedge(wdc);
+               if (wdc->sc_errors < WDIORETRIES)
+                       return 1;
                wderror(wd, bp, "hard error");
 
        bad:
index 3429486..a32bef3 100644 (file)
@@ -1,14 +1,21 @@
-#      $OpenBSD: files.pcmcia,v 1.3 1996/04/21 22:25:58 deraadt Exp $
+#      $OpenBSD: files.pcmcia,v 1.4 1996/04/29 14:17:10 hvozda Exp $
+#      $Id: files.pcmcia,v 1.4 1996/04/29 14:17:10 hvozda Exp $
 #
-# Config file and device description for machine-independent PCMCIA code.
+# Config.new file and device description for machine-independent PCMCIA code.
 # Included by ports that need it.
 
 # XXX Does this comment hold?
 # ports should define their own "device pcmcia" line (like the one below,
 # but with the correct bus attachment).
 
-device pcmcia: isa
-attach pcmcia at pcicbus
+#
+# needs all the parameters available on isa, so devices can attach here.
+#
+
+device pcmcia  {[port = -1], [size = 0],
+               [iomem = -1], [iosiz = 0],
+               [irq = -1], [drq = -1], [slot = -1]}
+attach pcmcia at pcmciabus
 
-file   dev/pcmcia/pcmcia.c             pcmcia needs-count
+file   dev/pcmcia/pcmcia.c             pcmcia  needs-flag
 file   dev/pcmcia/pcmcia_conf.c        pcmcia
index 7729774..f37de3e 100644 (file)
@@ -1,4 +1,6 @@
+/*     $Id: pcmcia.c,v 1.3 1996/04/29 14:17:15 hvozda Exp $    */
 /*
+ * Copyright (c) 1996 John T. Kohl.  All rights reserved.
  * Copyright (c) 1994 Stefan Grefen.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- *      $Id: pcmcia.c,v 1.2 1996/01/26 21:27:31 hvozda Exp $
  */
 
+/* XXX - these next two lines are just "glue" until the confusion over
+   pcmcia vs pcmciabus between the framework and sys/conf/files
+   gets resolved */
+#define pcmciabus_cd pcmcia_cd
+#define pcmciabus_ca pcmcia_ca
+
 /* derived from scsiconf.c writte by Julian Elischer et al */
 /* TODO add modload support and loadable lists of devices */
 #include <sys/types.h>
 #include <sys/device.h>
 #include <sys/ioctl.h>
 #include <sys/fcntl.h>
+#include <sys/proc.h>
+#include <sys/cpu.h>
 
-#include <dev/pcmcia/pcmcia.h>
-#include <dev/pcmcia/pcmciabus.h>
+#include <dev/pcmcia/pcmciavar.h>
+#include <dev/pcmcia/pcmciareg.h>
 #include <dev/pcmcia/pcmcia_ioctl.h>
 
-#include "ed.h"
-#include "com.h"
-#include "ep.h"
-
 #ifdef IBM_WD
 #define PCMCIA_DEBUG
 #endif
 # define PPRINTF(a)
 #endif
 
-static void pcmciadumpcf __P((struct pcmcia_conf *));
-static int pcmcia_strcmp __P((char *, char *, int, char *));
-
-void pcmcia_shuthook __P((void *));
-
-static struct pcmcia_adapter pcmcia_drivers[4];
-static int      pcmcia_cntrl = 0;
-static int      probed = 0;
-static struct device **deldevs = NULL;
-static int      ndeldevs = 0;
-
-/* I've decided to re-ifdef these.  It makes making a kernel easier
-    until I either get config(8) modified to deal somehow
-    or figure out a better to way declare the prototypes and
-    build up the knowndevs struct.  Stefan may have ideas...
-*/
-
-#if NED > 0
-extern struct pcmciadevs pcmcia_ed_devs[];
-#endif
-#if NCOM > 0
-extern struct pcmciadevs pcmcia_com_devs[];
-#endif
-#if NEP > 0
-extern struct pcmciadevs pcmcia_ep_devs[];
-#endif
-
-static struct pcmciadevs *knowndevs[] = {
-#if NED > 0
-       pcmcia_ed_devs,
-#endif
-#if NCOM > 0
-       pcmcia_com_devs,
-#endif
-#if NEP > 0
-       pcmcia_ep_devs,
+#ifdef PCMCIA_DEBUG
+void pcmciadumpcf __P((struct pcmcia_conf *));
 #endif
-       NULL
-};
 
-#ifdef notyet
-static struct pcmciadevs *knowndevs[10] = { NULL };
-#define KNOWNSIZE (sizeof(knowndevs) / sizeof(knowndevs[0]))
-#endif
+static struct old_devs {
+       struct device *dev;
+       struct pcmciadevs *pcdev;
+} *deldevs;
+static int      ndeldevs = 0;
 
 #define PCMCIA_SERVICE(a,b,c,d,e)   ((a)->chip_link->pcmcia_service(b,c,\
                                                                (void *) d,e))
 #define PCMCIA_MAP_IO(a,b,c,d,e)    ((a)->chip_link->pcmcia_map_io(b,c,d,e))
 #define PCMCIA_MAP_INTR(a,b,c,d)    ((a)->chip_link->pcmcia_map_intr(b,c,d))
-#define PCMCIA_MAP_MEM(a,b,c,d,e,f) ((a)->chip_link->pcmcia_map_mem(b,c,d,e,f))
-
-#define PCMCIA_BUS_INIT(a,b,c,d,e,f)((a)->bus_link->bus_init((b),(c),(d),(e)\
-                                                                       ,(f)))
-#define PCMCIA_BUS_SEARCH(a,b,c,d)  ((a)->bus_link->bus_search((b),(c),(d)))
-#define PCMCIA_BUS_PROBE(a,b,c,d,e) ((a)->bus_link->bus_probe((b),(c),(d),(e)))
-#define PCMCIA_BUS_CONFIG(a,b,c,d,e)((a)->bus_link->bus_config((b),(c),(d),(e)))
-#define PCMCIA_BUS_UNCONFIG(a,b)    ((a)->bus_link->bus_unconfig((b)))
+/* XXX
+ * this is quite broken in the face of various bus mapping stuff...
+ * drivers need to cooperate with the pcmcia framework to deal with
+ * bus mapped memory.  Whee.
+ */
+#define PCMCIA_MAP_MEM(a,b,c,d,e,f,g) ((a)->chip_link->pcmcia_map_mem(b,c,d,e,f,g))
 
-#define SCRATCH_MEM(a) ((a)->scratch_mem)
+#define SCRATCH_MEM(a) ((a)->scratch_memh)
+#define SCRATCH_BC(a)  ((a)->pa_bc)
 #define SCRATCH_SIZE(a)        ((a)->scratch_memsiz)
 #define SCRATCH_INUSE(a)((a)->scratch_inuse)
 
 /*
  * Declarations
  */
-struct pcmciadevs *pcmcia_probedev __P((struct pcmcia_link *));
-struct pcmciadevs *pcmcia_selectdev __P((char *, char *, char *, char *));
-int pcmcia_probe_bus __P((struct pcmcia_link *, int, int,
-                         struct pcmcia_conf *));
+int pcmcia_probedev __P((struct pcmcia_link *, struct pcmcia_cardinfo *));
+int pcmcia_probe_bus __P((int, int));
 int pcmciabusmatch __P((struct device *, void *, void *));
 void pcmciabusattach __P((struct device *, struct device *, void *));
+int  pcmcia_mapcard __P((struct pcmcia_link *, int, struct pcmcia_conf *));
 
-struct cfdriver pcmciabuscd = {
-       NULL, "pcmcia", pcmciabusmatch, pcmciabusattach, DV_DULL,
-       sizeof(struct pcmciabus_softc), 1
-};
-
-#ifdef notyet
-int
-pcmcia_add_device(devs)
-       struct pcmciadevs *devs;
-{
-       int i;
-
-       if (devs == NULL)
-               return 0;
+int pcmcia_unconfigure __P((struct pcmcia_link *));
+int pcmcia_unmapcard __P((struct pcmcia_link *));
 
-       for (i = 0; i < KNOWNSIZE; i++)
-               if (knowndevs[i] == NULL)
-                       break;
+int pcmcia_print __P((void *, char *));
+int pcmcia_submatch __P((struct device *, void *, void *));
+void pcmcia_probe_link __P((struct pcmcia_link *));
 
-       if (i == KNOWNSIZE)
-               panic("Too many pcmcia devices");
+struct cfattach pcmcia_ca = {
+       sizeof(struct pcmciabus_softc), pcmciabusmatch, pcmciabusattach,
+};
 
-       knowndevs[i] = devs;
-       for (; devs->devname != NULL; devs++)
-               printf("added %s\n", devs->devname);
-       return i;
-}
-#endif
+struct cfdriver pcmcia_cd = {
+       NULL, "pcmcia", DV_DULL, 1
+};
 
+#if 0
 int
 pcmcia_register(adapter_softc, bus_link, chip_link, slot)
        void           *adapter_softc;
@@ -178,6 +133,7 @@ pcmcia_register(adapter_softc, bus_link, chip_link, slot)
        }
        return 0;
 }
+#endif
 
 int
 pcmciabusmatch(parent, self, aux)
@@ -187,18 +143,16 @@ pcmciabusmatch(parent, self, aux)
 {
        struct pcmciabus_softc *sc = (void *)self;
        struct cfdata *cf = sc->sc_dev.dv_cfdata;
-       int             i, found = 0;
+       struct pcmciabus_attach_args *pba = aux;
+       struct pcmcia_adapter *pca = pba->pba_aux;
+       int found = 0;
 
-       PPRINTF(("- pcmciabusmatch\n"));
-       if (pcmcia_cntrl <= 0)
-               return 0;
+       PPRINTF(("- pcmciabusmatch %p %p\n", pba, pca));
 
-       for (i = 0; i < 4; i++)
-               if (pcmcia_drivers[i].bus_link) {
-                       if (PCMCIA_BUS_INIT(&pcmcia_drivers[i], parent, cf,
-                                           aux, &pcmcia_drivers[i], 0))
-                               found++;
-               }
+       if (pca->bus_link) {
+               if (PCMCIA_BUS_INIT(pca, parent, cf, aux, pca, 0))
+                       found++;
+       }
        return found != 0;
 }
 
@@ -214,19 +168,18 @@ pcmciabusattach(parent, self, aux)
 {
        struct pcmciabus_softc *sc = (struct pcmciabus_softc *) self;
        struct cfdata  *cf = self->dv_cfdata;
-       int             i, found = 0;
+       struct pcmciabus_attach_args *pba = aux;
+       struct pcmcia_adapter *pca = pba->pba_aux;
 
        PPRINTF(("- pcmciabusattach\n"));
-       for (i = 0; i < 4; i++)
-               if (pcmcia_drivers[i].bus_link) {
-                       if (PCMCIA_BUS_INIT(&pcmcia_drivers[i], parent, cf,
-                                           aux, &pcmcia_drivers[i], 1))
-                               found++;
-               }
-
+       if (pca->bus_link) {
+               PCMCIA_BUS_INIT(pca, parent, cf, aux, pca, 1);
+       }
        printf("\n");
 
-       pcmcia_probe_bus(NULL, sc->sc_dev.dv_unit, -1, NULL);
+       sc->sc_driver = pca;
+       sc->sc_bc = pba->pba_bc;
+       pcmcia_probe_bus(sc->sc_dev.dv_unit, -1);
 }
 
 /*
@@ -239,52 +192,52 @@ pcmcia_probe_busses(bus, slot)
 {
        PPRINTF(("- pcmcia_probe_busses\n"));
        if (bus == -1) {
-               for (bus = 0; bus < pcmciabuscd.cd_ndevs; bus++)
-                       if (pcmciabuscd.cd_devs[bus])
-                               pcmcia_probe_bus(NULL, bus, slot, NULL);
+               for (bus = 0; bus < pcmciabus_cd.cd_ndevs; bus++)
+                       if (pcmciabus_cd.cd_devs[bus])
+                               pcmcia_probe_bus(bus, slot);
                return 0;
        } else {
-               return pcmcia_probe_bus(NULL, bus, slot, NULL);
+               return pcmcia_probe_bus(bus, slot);
        }
 }
 
+/* Macros to clear/set/test flags. */
+#define        SET(t, f)       (t) |= (f)
+#define        CLR(t, f)       (t) &= ~(f)
+#define        ISSET(t, f)     ((t) & (f))
+
 /*
  * Probe the requested pcmcia bus. It must be already set up.
  */
 int
-pcmcia_probe_bus(link, bus, slot, cf)
-       struct pcmcia_link *link;
+pcmcia_probe_bus(bus, slot)
        int             bus, slot;
-       struct pcmcia_conf *cf;
 {
        struct pcmciabus_softc *pcmcia;
-       int             maxslot, minslot, maxlun, minlun;
-       struct pcmciadevs *bestmatch = NULL;
-       int             spec_probe = (link != NULL);
+       int             maxslot, minslot;
+       struct pcmcia_link *link;
 
        PPRINTF(("- pcmcia_probe_bus\n"));
-       if (bus < 0 || bus >= pcmciabuscd.cd_ndevs)
+       if (bus < 0 || bus >= pcmciabus_cd.cd_ndevs)
                return ENXIO;
-       pcmcia = pcmciabuscd.cd_devs[bus];
-       if (!pcmcia)
+       pcmcia = pcmciabus_cd.cd_devs[bus];
+       if (!pcmcia || pcmcia->sc_driver == NULL) /* bus is not configured */
                return ENXIO;
 
        if (slot == -1) {
-               maxslot = 7;
+               maxslot = pcmcia->sc_driver->nslots - 1;
                minslot = 0;
        } else {
-               if (slot < 0 || slot > 7)
+               if (slot < 0 || slot >= pcmcia->sc_driver->nslots)
                        return EINVAL;
                maxslot = minslot = slot;
        }
 
        for (slot = minslot; slot <= maxslot; slot++) {
-               if (link = pcmcia->sc_link[slot]) {
+               if ((link = pcmcia->sc_link[slot])) {
                        if (link->devp)
                                continue;
                }
-               if (pcmcia_drivers[slot >> 1].adapter_softc == NULL)
-                       continue;
 
                /*
                 * If we presently don't have a link block
@@ -297,88 +250,91 @@ pcmcia_probe_bus(link, bus, slot, cf)
                                return ENOMEM;
                        bzero(link, sizeof(*link));
                        link->opennings = 1;
-                       link->adapter = &pcmcia_drivers[slot >> 1];
+                       link->adapter = pcmcia->sc_driver;
+                       link->bus = pcmcia;
                        link->slot = slot;
                }
-               bestmatch = pcmcia_probedev(link);
-               /*
-                * We already know what the device is.  We use a
-                * special matching routine which insists that the
-                * cfdata is of the right type rather than putting
-                * more intelligence in individual match routines for
-                * each high-level driver.
-                * We must have the final probe do all of the comparisons,
-                * or we could get stuck in an infinite loop trying the same
-                * device repeatedly.  We use the `fordriver' field of
-                * the pcmcia_link for now, rather than inventing a new
-                * structure just for the config_search().
-                */
-               if (link->fordriver == NULL) {
-                       if (bestmatch)
-                               link->fordriver = bestmatch->devname;
-                       else {
-                               if (!spec_probe) {
-                                       link->device = NULL;
-                                       link->devp = NULL;
-                                       PCMCIA_SERVICE(link->adapter,
-                                                      link, PCMCIA_OP_POWER,
-                                                      0, 0);
-                               }
-                       }
-               }
+               (void) pcmcia_probe_link(link);
+       }
+       return 0;
+}
 
-               if (spec_probe) {
-                       if (cf && pcmcia_mapcard(link, -1, cf) != 0)
-                               link->fordriver = NULL;
-               }
+void
+pcmcia_probe_link(link)
+       struct pcmcia_link *link;
+{
+       struct pcmcia_cardinfo cardinfo;
+       struct pcmcia_attach_args paa;
+       struct pcmciabus_softc *pcmcia = link->bus;
+       int             i;
 
-               if (link->fordriver != NULL) {
-                       int             i;
-                       struct device **delp = deldevs;
-                       int             found = 0;
-                       link->device = bestmatch;
-                       link->flags = (link->flags &
-                                         ~(PCMCIA_ATTACH_TYPE)) |
-                                           PCMCIA_REATTACH;
-                       for (i = 0; i < ndeldevs; i++, delp++) {
-                               if (*delp &&
-                                   pcmcia_configure((*delp)->dv_parent, *delp,
-                                                    link)) {
-                                       link->flags = (link->flags &
-                                                         ~PCMCIA_ATTACH_TYPE)
-                                                      | PCMCIA_SLOT_INUSE;
-                                       found = 1;
-                                       *delp = NULL;
-                                       break;
-                               }
-                       }
-                       if (!found) {
-                               link->flags = (link->flags &
-                                      ~PCMCIA_ATTACH_TYPE) | PCMCIA_ATTACH;
-                               if (PCMCIA_BUS_SEARCH(link->adapter,
-                                                     &pcmcia->sc_dev,
-                                                     link, NULL)) {
-                                       link->flags = (link->flags &
-                                                         ~PCMCIA_ATTACH_TYPE)
-                                                      | PCMCIA_SLOT_INUSE;
-                               } else {
-                                       link->flags &= ~(PCMCIA_ATTACH_TYPE |
-                                                        PCMCIA_SLOT_INUSE);
-                                       link->device = NULL;
-                                       printf(
-                                           "No matching config entry %s.\n",
-                                              link->fordriver ? 
-                                              link->fordriver : "(NULL)");
-                                       if (!spec_probe)
-                                               PCMCIA_SERVICE(link->adapter,
-                                                              link,
-                                                              PCMCIA_OP_POWER,
-                                                              0, 0);
-                               }
+       PPRINTF(("- pcmcia_probe_link %p\n", link));
+       /*
+        * Set up card and fetch card info.
+        */
+       if (pcmcia_probedev(link, &cardinfo) == 0) {
+               /* could not fetch its strings, so give up on it. */
+               PCMCIA_SERVICE(link->adapter,
+                              link, PCMCIA_OP_POWER,
+                              0, 0);
+               return;
+       }
+
+       /*
+        * See if we can reattach a device.
+        */
+       CLR(link->flags, PCMCIA_ATTACH_TYPE);
+       SET(link->flags, PCMCIA_REATTACH);
+       for (i = 0; i < ndeldevs; i++) {
+               if (deldevs[i].dev) {
+                       PPRINTF(("trying device\n"));
+                       link->device = deldevs[i].pcdev;
+                       if (pcmcia_configure(deldevs[i].dev->dv_parent,
+                                            deldevs[i].dev, link)) {
+                               CLR(link->flags, PCMCIA_ATTACH_TYPE);
+                               SET(link->flags, PCMCIA_SLOT_INUSE);
+                               deldevs[i].dev = NULL;
+                               deldevs[i].pcdev = NULL;
+                               return;
                        }
                }
        }
-       return 0;
+
+
+       paa.paa_cardinfo = &cardinfo;
+       paa.paa_link = link;
+       paa.paa_aux = NULL;
+       paa.paa_bestmatch = 0;
+       paa.paa_matchonly = 1;
+       CLR(link->flags, PCMCIA_ATTACH_TYPE);
+       SET(link->flags, PCMCIA_ATTACH);
+
+       /* Run the config matching routines to find us a good match.
+        * match routines will flag on "matchonly" and fill in stuff
+        * into the link structure, but not return any match.
+        */
+       (void) config_found_sm(&pcmcia->sc_dev,
+                              &paa,
+                              pcmcia_print,
+                              pcmcia_submatch);
+
+       if (PCMCIA_BUS_SEARCH(link->adapter,
+                             &pcmcia->sc_dev,
+                             link, NULL)) {
+               CLR(link->flags, PCMCIA_ATTACH_TYPE);
+               SET(link->flags, PCMCIA_SLOT_INUSE);
+       } else {
+               CLR(link->flags, PCMCIA_ATTACH_TYPE|PCMCIA_SLOT_INUSE);
+               link->device = NULL;
+               printf("%s slot %d: No matching config entry.\n",
+                      pcmcia->sc_dev.dv_xname,
+                      link->slot);
+               PCMCIA_SERVICE(link->adapter,
+                              link, PCMCIA_OP_POWER,
+                              0, 0);
+               link->fordriver = NULL;
+       }
+       return;
 }
 
 /*
@@ -386,16 +342,13 @@ pcmcia_probe_bus(link, bus, slot, cf)
  * it is, and find the correct driver table
  * entry.
  */
-struct pcmciadevs *
-pcmcia_probedev(link)
+int
+pcmcia_probedev(link, cardinfo)
        struct pcmcia_link *link;
+       struct pcmcia_cardinfo *cardinfo;
 {
        struct pcmcia_adapter *pca = link->adapter;
        u_char          scratch[CIS_MAXSIZE];
-       char            manu[MAX_CIS_NAMELEN];
-       char            model[MAX_CIS_NAMELEN];
-       char            add_inf1[MAX_CIS_NAMELEN];
-       char            add_inf2[MAX_CIS_NAMELEN];
        int             card_stat;
        int             err;
        int             pow = 0;
@@ -403,22 +356,22 @@ pcmcia_probedev(link)
 
        PPRINTF(("- pcmcia_probe_dev\n"));
 
-       printf("%s slot %d:",
-              ((struct device *) link->adapter->adapter_softc)->dv_xname,
-              slot & 1);
+       printf("%s: slot %d ", ((struct device *) link->bus)->dv_xname, slot);
 
+       /* turn off power in case it's on, to get a fresh start on things: */
+       PCMCIA_SERVICE(pca, link, PCMCIA_OP_POWER, 0, 0);
        if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_STATUS,
                                  &card_stat, 0)) != 0) {
                printf("failed to get status %d\n", err);
                return NULL;
        }
 
-       if ((card_stat & PCMCIA_CARD_PRESENT) == 0) {
-               printf(" <slot empty>\n");
+       if (ISSET(card_stat, PCMCIA_CARD_PRESENT) == 0) {
+               printf("is empty\n");
                return NULL;
        }
 
-       if (!(card_stat & PCMCIA_POWER)) {
+       if (!ISSET(card_stat, PCMCIA_POWER)) {
                pow = 1;
                if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_POWER, 10000,
                                          PCMCIA_POWER_ON|
@@ -428,7 +381,7 @@ pcmcia_probedev(link)
                }
        }
 
-       if (!(link->flags & (PCMCIA_SLOT_INUSE | CARD_IS_MAPPED))) {
+       if (!ISSET(link->flags, (PCMCIA_SLOT_INUSE | CARD_IS_MAPPED))) {
                if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_RESET,
                                          500000, 0)) != 0) {
                        printf("failed to reset %d\n", err);
@@ -446,127 +399,25 @@ pcmcia_probedev(link)
        }
 
        if ((err = pcmcia_get_cisver1(link, scratch, sizeof(scratch),
-                                     manu, model, add_inf1,
-                                     add_inf2)) != 0) {
+                                     cardinfo->manufacturer,
+                                     cardinfo->model, cardinfo->add_info1,
+                                     cardinfo->add_info2)) != 0) {
                printf("failed to get cis info %d\n", err);
                goto bad;
        }
 
-       printf(" <%s, %s", manu, model);
-       if (add_inf1[0])
-               printf(", %s", add_inf1);
-       if (add_inf2[0])
-               printf(", %s", add_inf2);
+       printf("contains <%s, %s", cardinfo->manufacturer, cardinfo->model);
+       if (cardinfo->add_info1[0])
+               printf(", %s", cardinfo->add_info1);
+       if (cardinfo->add_info2[0])
+               printf(", %s", cardinfo->add_info2);
        printf(">\n");
 
-
-       /*
-        * Try make as good a match as possible with
-        * available sub drivers
-        */
-       return pcmcia_selectdev(manu, model, add_inf1, add_inf2);
+       return 1;
 bad:
        if (!pow)
                PCMCIA_SERVICE(pca, link, PCMCIA_OP_POWER, 0, 0);
-       return NULL;
-}
-
-/*
- * Try make as good a match as possible with
- * available sub drivers
- */
-struct pcmciadevs *
-pcmcia_selectdev(manu, model, add_inf1, add_inf2)
-       char *manu, *model, *add_inf1, *add_inf2;
-{
-       u_int bestmatches = 0;
-       struct pcmciadevs *bestmatch = (struct pcmciadevs *) 0;
-       struct pcmciadevs **dlist, *dentry;
-
-       PPRINTF(("- pcmcia_selectdev\n"));
-       for (dlist = knowndevs; *dlist; dlist++)
-               for (dentry = *dlist; dentry && 
-                                     dentry->devname != NULL; dentry++) {
-                       int match = 0;
-
-#ifdef PCMCIA_DEBUG
-                       dentry->flags |= PC_SHOWME;
-#endif
-                       match|=pcmcia_strcmp(dentry->manufacturer,
-                                   manu,dentry->flags,"manufacturer")<<6;
-                       match|=pcmcia_strcmp(dentry->model,
-                                   model,dentry->flags,"model")<<4;
-                       match|=pcmcia_strcmp(dentry->add_inf1,
-                                   add_inf1,dentry->flags,"info1")<<2;
-                       match|=pcmcia_strcmp(dentry->add_inf2,
-                                   add_inf2,dentry->flags,"info2");
-/* the following was replaced by the wildcard function called above */
-#if 0
-                       if (dentry->flags & PC_SHOWME)
-                               printf("manufacturer = `%s'-`%s'\n", 
-                                      dentry->manufacturer ?
-                                      dentry->manufacturer :
-                                      "X",
-                                      manu);
-                       if (dentry->manufacturer) {
-                           if (strcmp(dentry->manufacturer, manu) == 0) {
-                               match |= 8;
-                           } else {
-                               continue;
-                           }
-                       }
-
-                       if (dentry->flags & PC_SHOWME)
-                               printf("model = `%s'-`%s'\n",
-                                      dentry->model ? dentry->model :
-                                      "X",
-                                      model);
-                       if (dentry->model)  {
-                           if (strcmp(dentry->model, model) == 0) {
-                               match |= 4;
-                           } else {
-                               continue;
-                           }
-                       }
-
-
-                       if (dentry->flags & PC_SHOWME)
-                               printf("info1 = `%s'-`%s'\n",
-                                      dentry->add_inf1 ? dentry->add_inf1 :
-                                      "X",
-                                      add_inf1);
-                       if (dentry->add_inf1) {
-                           if (strcmp(dentry->add_inf1, add_inf1) == 0) {
-                               match |= 2;
-                           } else {
-                               continue;
-                           }
-                       }
-
-                       if (dentry->flags & PC_SHOWME)
-                               printf("info2 = `%s'-`%s'\n", 
-                                      dentry->add_inf2 ? dentry->add_inf2 :
-                                      "X",
-                                      add_inf2);
-                       if (dentry->add_inf2) {
-                           if (strcmp(dentry->add_inf2, add_inf2) == 0) {
-                               match |= 1;
-                           } else {
-                               continue;
-                           }
-                       }
-#endif
-#ifdef PCMCIA_DEBUG
-                       printf("match == %d [%d]\n",match,bestmatches);
-#endif
-
-                       if(match > bestmatches) {
-                               bestmatches = match;
-                               bestmatch = dentry;
-                       }
-               }
-
-       return bestmatch;
+       return 0;
 }
 
 int
@@ -579,26 +430,29 @@ pcmcia_configure(parent, self, aux)
        struct pcmcia_link *link = aux;
        struct cfdata  *cf = dev->dv_cfdata;
        struct cfdriver *cd = cf->cf_driver;
-       char           *devname = (char *) link->fordriver;
        struct pcmciadevs *pcs = link->device;
        struct pcmcia_device *pcd;
        struct pcmcia_adapter *pca = link->adapter;
        struct pcmcia_conf pc_cf;
+       char *devname = (char *) link->fordriver;
        u_char          scratch[CIS_MAXSIZE];
        int             mymap = 0;
 
        PPRINTF(("- pcmcia_configure\n"));
 
-       if (strcmp(devname, cd->cd_name) || !pca)
+       if ((devname && strcmp(devname, cd->cd_name)) || !pca)
                return 0;
 
+       if (link->devp)
+               return 0;               /* something else already attached */
+
        if (pcs == NULL)
                pcd = NULL;
        else
                pcd = pcs->dev;
 
-       PPRINTF(("pcmcia_configure: %x\n", pcd));
-       if (!(link->flags & CARD_IS_MAPPED)) {
+       PPRINTF(("pcmcia_configure: %p\n", pcd));
+       if (!ISSET(link->flags, CARD_IS_MAPPED)) {
                /* read 'suggested' configuration */
                PPRINTF(("pcmcia_configure: calling read cis\n"));
                if (pcmcia_read_cis(link, scratch, 0, sizeof(scratch)) != 0)
@@ -615,8 +469,9 @@ pcmcia_configure(parent, self, aux)
 #endif
                /* and modify it (device specific) */
                if (pcd && pcd->pcmcia_config) {
-                       PPRINTF(("pcmcia_configure: calling config\n"));
-                       if (pcd->pcmcia_config(link, dev, &pc_cf, cf))
+                       PPRINTF(("pcmcia_configure: calling config %p %p\n",
+                                pcd, pcd->pcmcia_config));
+                       if ((*pcd->pcmcia_config)(link, dev, &pc_cf, cf))
                                return 0;
 
                        if ((pc_cf.cfgtype & CFGENTRYMASK) == CFGENTRYID) {
@@ -649,7 +504,7 @@ pcmcia_configure(parent, self, aux)
        }
        link->devp = dev;
 
-       PPRINTF(("pcmcia_configure: calling bus probe\n"));
+       PPRINTF(("pcmcia_configure: calling bus attach\n"));
        if (!(PCMCIA_BUS_PROBE(pca, parent, dev, cf, link))) {
                PPRINTF(("pcmcia_configure: bus probe failed\n"));
                goto bad;
@@ -660,39 +515,34 @@ pcmcia_configure(parent, self, aux)
                goto bad;
        }
 
-       link->shuthook = shutdownhook_establish(pcmcia_shuthook,
-                                               (void *)link);
        return 1;
 
 bad:
        link->devp = NULL;
        if (mymap)
                pcmcia_unmapcard(link);
-       printf("pcmcia_configure: configuration error\n");
+       PPRINTF(("pcmcia_configure: configuration error\n"));
        return 0;
 }
 
 void
-pcmcia_shuthook(arg)
-void *arg;
+pcmcia_detach(dev, arg)
+       struct device *dev;
+       void *arg;
 {
-    struct pcmcia_link *link = (struct pcmcia_link *)arg;
-    if (pcmcia_unconfigure(link) == 0) {
-       /*
-        * turn off power too.
-        */
-       PCMCIA_SERVICE(link->adapter, link, PCMCIA_OP_RESET, 500000, 0);
-       PCMCIA_SERVICE(link->adapter, link, PCMCIA_OP_POWER, 0, 0);
-    }
+       struct pcmcia_link *link = arg;
+
+       link->devp = NULL;
+       printf("%s: device %s at slot %d detached/really\n",
+              dev->dv_parent->dv_xname,
+              dev->dv_xname, link->slot);
 }
 
 int
 pcmcia_unconfigure(link)
        struct pcmcia_link *link;
 {
-       int             status;
-       int             i, err;
-       struct device **delp;
+       int             i;
        struct device  *dev;
        struct pcmcia_adapter *pca = link->adapter;
        struct pcmcia_device *pcd;
@@ -706,9 +556,9 @@ pcmcia_unconfigure(link)
        else
                pcd = NULL;
 
-       if (link->flags & CARD_IS_MAPPED) {
+       if (ISSET(link->flags, CARD_IS_MAPPED)) {
                if (pcd && pcd->pcmcia_remove) {
-                       if (pcd->pcmcia_remove(link, link->devp))
+                       if ((*pcd->pcmcia_remove)(link, link->devp))
                                return EBUSY;
                }
                else {
@@ -718,39 +568,56 @@ pcmcia_unconfigure(link)
                if (pcmcia_unmapcard(link) != 0)
                        return EBUSY;
        }
-       delp = deldevs;
-       for (i = 0; delp && *delp && i < ndeldevs; i++, delp++)
-               continue;
-       if (i >= ndeldevs) {
-               int sz = ndeldevs ? (ndeldevs * 2) : 
-                                   (MINALLOCSIZE / sizeof(void *));
-               struct device **ndel = malloc(sz * sizeof(void *),
-                                             M_DEVBUF, M_NOWAIT);
-               if (!ndel) {
-                       PPRINTF(("pcmcia_delete: creating dev array"));
-                       return ENOMEM;
-               }
-               bzero(ndel, sz * sizeof(void *));
-               if (ndeldevs) {
-                       bcopy(deldevs, ndel, ndeldevs * sizeof(void *));
-                       free(deldevs, M_DEVBUF);
+       if (config_detach(link->devp->dv_cfdata, pcmcia_detach, link)) {
+               /* must be retained */
+               for (i = 0; deldevs && deldevs[i].dev && i < ndeldevs; i++)
+                       continue;
+
+               if (i >= ndeldevs) {
+                       int sz = ndeldevs ? (ndeldevs * 2) : 
+                               (MINALLOCSIZE / sizeof(deldevs[0]));
+                       struct old_devs *ndel = malloc(sz * sizeof(deldevs[0]),
+                                                     M_DEVBUF, M_NOWAIT);
+                       if (!ndel) {
+                               PPRINTF(("pcmcia_delete: creating dev array"));
+                               return ENOMEM;
+                       }
+                       bzero(ndel, sz * sizeof(ndel[0]));
+                       if (ndeldevs) {
+                               bcopy(deldevs, ndel,
+                                     ndeldevs * sizeof(deldevs[0]));
+                               free(deldevs, M_DEVBUF);
+                       }
+                       ndeldevs = sz - 1;
+                       deldevs = ndel;
                }
-               ndeldevs = sz - 1;
-               deldevs = ndel;
-               delp = deldevs + i;
+               dev = deldevs[i].dev = link->devp;
+               deldevs[i].pcdev = link->device;
+               link->devp = NULL;
+               TAILQ_REMOVE(&alldevs, dev, dv_list);
+               printf("%s: device %s at slot %d detached/retained\n",
+                      dev->dv_parent->dv_xname,
+                      dev->dv_xname, link->slot);
+               /*
+                * Make this node eligible to probe again.
+                * Since we're indirectly allocating state,
+                * this device data will not get trashed later and we
+                * can hold onto it.
+                */
+/*             dev->dv_cfdata->cf_fstate = FSTATE_NOTFOUND;*/
        }
-       dev = *delp = link->devp;
-       link->devp = NULL;
-       printf("device %s in pcmcia slot %d detached\n", dev->dv_xname,
-              link->slot);
-       shutdownhook_disestablish(link->shuthook);
-       link->shuthook = 0;
        return 0;
 }
 
+/*
+ * Map the card into I/O and memory space, using the details provided
+ * with pc_cf.
+ */
+
 int
 pcmcia_mapcard(link, unit, pc_cf)
        struct pcmcia_link *link;
+       int unit;
        struct pcmcia_conf *pc_cf;
 {
        struct pcmcia_adapter *pca = link->adapter;
@@ -768,6 +635,7 @@ pcmcia_mapcard(link, unit, pc_cf)
        splx(s);
        for (i = 0; i < pc_cf->memwin; i++) {
                if ((err = PCMCIA_MAP_MEM(pca, link,
+                                         pca->pa_bc,
                                          (caddr_t) pc_cf->mem[i].start,
                                          pc_cf->mem[i].caddr,
                                          pc_cf->mem[i].len,
@@ -797,7 +665,7 @@ pcmcia_mapcard(link, unit, pc_cf)
                }
        }
        /* Now we've mapped everything enable it */
-       if ((err = PCMCIA_MAP_MEM(pca, link, SCRATCH_MEM(pca),
+       if ((err = PCMCIA_MAP_MEM(pca, link, SCRATCH_BC(pca), SCRATCH_MEM(pca),
             pc_cf->cfg_off & (~(SCRATCH_SIZE(pca) - 1)), SCRATCH_SIZE(pca),
                                  PCMCIA_MAP_ATTR | PCMCIA_LAST_WIN)) != 0) {
                PPRINTF(("pcmcia_mapcard: enable err %d\n", err));
@@ -810,45 +678,59 @@ pcmcia_mapcard(link, unit, pc_cf)
                goto error;
        }
 
-#define GETMEM(x) SCRATCH_MEM(pca)[(pc_cf->cfg_off & \
-                                   (SCRATCH_SIZE(pca) - 1)) + x]
-       if ((pc_cf->cfgtype & DOSRESET)) {
-               GETMEM(0) = PCMCIA_SRESET;
+#define GETMEM(x) bus_mem_read_1(pca->scratch_bc, SCRATCH_MEM(pca), \
+                                (pc_cf->cfg_off & (SCRATCH_SIZE(pca)-1)) + x)
+#define PUTMEM(x,v) \
+       bus_mem_write_1(pca->scratch_bc, SCRATCH_MEM(pca), \
+                       (pc_cf->cfg_off & (SCRATCH_SIZE(pca)-1)) + x, v)
+
+       if (ISSET(pc_cf->cfgtype, DOSRESET)) {
+               PUTMEM(0, PCMCIA_SRESET);
                delay(50000);
        }
 
 
-       PPRINTF(("CMDR %x\n",((pc_cf->cfgtype & CFGENTRYID) ?
+       PPRINTF(("CMDR %x\n",(ISSET(pc_cf->cfgtype, CFGENTRYID) ?
                         pc_cf->cfgid |CFGENTRYID:
                         (pc_cf->cfgtype & CFGENTRYMASK)|1)|
                    (pc_cf->irq_level ? PCMCIA_LVLREQ : 0)
        ));
 
-       GETMEM(0) = ((pc_cf->cfgtype & CFGENTRYID) ?
-                        pc_cf->cfgid |CFGENTRYID:
-                        (pc_cf->cfgtype & CFGENTRYMASK)|1)|
-                   (pc_cf->irq_level ? PCMCIA_LVLREQ : 0);
+       PUTMEM(0, (ISSET(pc_cf->cfgtype, CFGENTRYID) ?
+                  pc_cf->cfgid |CFGENTRYID:
+                  (pc_cf->cfgtype & CFGENTRYMASK)|1)|
+              (pc_cf->irq_level ? PCMCIA_LVLREQ : 0));
        delay(50000);
 
-       if (pc_cf->cfg_regmask & (1 << (PCMCIA_SCR / 2)))
-               GETMEM(PCMCIA_SCR) = (link->slot & 1) | 0x10;
+       if (ISSET(pc_cf->cfg_regmask, (1 << (PCMCIA_SCR / 2))))
+               PUTMEM(PCMCIA_SCR, (link->slot & 1) | 0x10);
 
 #if 0
        DPRINTF(("CCSR %x\n", GETMEM(PCMCIA_CCSR]));
-       if (GETMEM(PCMCIA_CCSR] & PCMCIA_POWER_DOWN) {
-               GETMEM(PCMCIA_CCSR] &= ~PCMCIA_POWER_DOWN;
-               DPRINTF(("CCSR now %x\n", GETMEM(PCMCIA_CCSR]));
+       if (ISSET(GETMEM(PCMCIA_CCSR), PCMCIA_POWER_DOWN)) {
+               u_char val = GETMEM(PCMCIA_CCSR);
+               CLR(val, PCMCIA_POWER_DOWN);
+               PUTMEM(PCMCIA_CCSR, var);
+               DPRINTF(("CCSR now %x\n", GETMEM(PCMCIA_CCSR)));
        }
 #endif
 
+
+       PPRINTF(("pcmcia_mapcard: about to initialize...\n"));
+
        if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_WAIT,
-                                 500000, 0)) != 0)
+                                 1000, 0)) != 0) {
                PPRINTF(("failed to initialize %d\n", err));
+               err = 0;                /* XXX */
+       }
 error:
-       PCMCIA_MAP_MEM(pca, link, 0, 0, 0, PCMCIA_LAST_WIN | PCMCIA_UNMAP);
+       PCMCIA_MAP_MEM(pca, link, SCRATCH_BC(pca), SCRATCH_MEM(pca), 0,
+                      SCRATCH_SIZE(pca), PCMCIA_LAST_WIN | PCMCIA_UNMAP);
        if (err != 0) {
+               PPRINTF(("pcmcia_mapcard: unmaping\n"));
                for (i = 0; i < pc_cf->memwin; i++) {
                        PCMCIA_MAP_MEM(pca, link,
+                                      pca->pa_bc,
                                       (caddr_t) pc_cf->mem[i].start,
                                       pc_cf->mem[i].caddr,
                                       pc_cf->mem[i].len,
@@ -863,12 +745,12 @@ error:
                                      PCMCIA_MAP_8)) | i | PCMCIA_UNMAP);
                }
                PCMCIA_MAP_INTR(pca, link, pc_cf->irq_num, PCMCIA_UNMAP);
-               link->flags &= ~CARD_IS_MAPPED;
+               CLR(link->flags, CARD_IS_MAPPED);
                link->iowin = 0;
                link->memwin = 0;
                link->intr = 0;
        } else {
-               link->flags |= CARD_IS_MAPPED;
+               SET(link->flags, CARD_IS_MAPPED);
                link->iowin = pc_cf->iowin;
                link->memwin = pc_cf->memwin;
                link->intr = pc_cf->irq_num;
@@ -891,14 +773,15 @@ pcmcia_unmapcard(link)
                return ENODEV;
 
        for (i = 0; i < link->memwin; i++)
-               PCMCIA_MAP_MEM(pca, link, 0, 0, 0, (i | PCMCIA_UNMAP));
+               PCMCIA_MAP_MEM(pca, link, pca->pa_bc, 0, 0, 0,
+                              (i | PCMCIA_UNMAP));
 
        for (i = 0; i < link->iowin; i++)
                PCMCIA_MAP_IO(pca, link, 0, 0, (i | PCMCIA_UNMAP));
 
        PCMCIA_MAP_INTR(pca, link, link->intr, PCMCIA_UNMAP);
-       PCMCIA_SERVICE(pca, link, PCMCIA_OP_RESET, 0, 0);
-       link->flags &= ~(CARD_IS_MAPPED | PCMCIA_SLOT_INUSE);
+       PCMCIA_SERVICE(pca, link, PCMCIA_OP_RESET, 50000, 0);
+       CLR(link->flags, (CARD_IS_MAPPED | PCMCIA_SLOT_INUSE));
        link->iowin = 0;
        link->memwin = 0;
        link->intr = 0;
@@ -906,30 +789,28 @@ pcmcia_unmapcard(link)
 }
 
 
-static int
+int
 pcmcia_mapcard_and_configure(link, unit, pc_cf)
        struct pcmcia_link *link;
        struct pcmcia_conf *pc_cf;
        int             unit;
 {
-       int             err;
        int             mymap = 0;
+       int err;
 
        PPRINTF(("- pcmcia_mapcard_and_configure\n"));
        if (pc_cf->driver_name[0][0]) {
-#if 0
                if ((err = pcmcia_mapcard(link, unit, pc_cf)) != 0) {
                        return err;
                }
                mymap=1;
-#endif
                link->fordriver = pc_cf->driver_name[0];
-       } else {
+       } else
                link->fordriver = NULL;
-               pc_cf = NULL;
-       }
-       pcmcia_probe_bus(link, 0, link->slot, pc_cf);
-       if ((link->flags & PCMCIA_SLOT_INUSE) == 0) {
+       
+       pcmcia_probe_link(link);
+
+       if (!ISSET(link->flags, PCMCIA_SLOT_INUSE)) {
                if (mymap)
                        pcmcia_unmapcard(link);
                return ENODEV;
@@ -952,7 +833,7 @@ pcmcia_read_cis(link, scratch, offs, len)
        int size = SCRATCH_SIZE(pca);
        volatile int *inuse = &SCRATCH_INUSE(pca);
 
-       PPRINTF(("- pcmcia_read_cis\n"));
+       PPRINTF(("- pcmcia_read_cis: mem %p size %d\n", p, size));
        if (pca == NULL)
                return ENXIO;
 
@@ -968,15 +849,18 @@ pcmcia_read_cis(link, scratch, offs, len)
                int tlen = min(len + toff, size / 2) - toff;
                int i;
 
-               if ((err = PCMCIA_MAP_MEM(pca, link, p, pgoff, size,
+               if ((err = PCMCIA_MAP_MEM(pca, link, pca->pa_bc, p, pgoff,
+                                         size,
                                          PCMCIA_MAP_ATTR |
                                          PCMCIA_LAST_WIN)) != 0)
                        goto error;
 
+               PPRINTF(("- pcmcia_read_cis: mem mapped\n"));
+
                for (i = 0; i < tlen; j++, i++)
                        scratch[j] = p[toff + i * 2];
 
-               PCMCIA_MAP_MEM(pca, link, p, 0, size,
+               PCMCIA_MAP_MEM(pca, link, pca->pa_bc, p, 0, size,
                               PCMCIA_LAST_WIN | PCMCIA_UNMAP);
                len -= tlen;
        }
@@ -986,21 +870,25 @@ error:
        wakeup((caddr_t) inuse); 
        splx(s);
 
+       PPRINTF(("- pcmcia_read_cis return %d\n", err));
        return err;
 }
 
 /* here we start our pseudodev for controlling the slots */
 #define PCMCIABUS_UNIT(a)    (minor(a))
-#define PCMCIABUS_SLOT(a)    (a&0x7)
-#define PCMCIABUS_CHIPIID(a) (a&0x3)
-#define PCMCIABUS_CHIP       0x10
-#define PCMCIABUS_BUS        0x20
+#define PCMCIABUS_SLOT(a)    (a&0x3)   /* per-controller */
+#define PCMCIABUS_SLOTID(a)  (a&0xf)   /* system-wide assignment */
+#define PCMCIABUS_CHIPNO(a)  ((a&0xf)>>2)
+#define PCMCIABUS_CHIPID(a) (a&0x3)
+#define PCMCIABUS_CHIP       0x40
+#define PCMCIABUS_BUS        0x80
+#define PCMCIABUS_BUSID(a)   (a&0x3)
 #define PCMCIABUS_DEVTYPE(a) ((a)&(PCMCIABUS_CHIP|PCMCIABUS_BUS))
 static int      busopen = 0;
 static int      chipopen[4] = {0, 0, 0, 0};
 
 int
-pcmciabusopen(dev, flag, mode, p)
+pcmciaopen(dev, flag, mode, p)
        dev_t           dev;
        int             flag, mode;
        struct proc    *p;
@@ -1011,8 +899,6 @@ pcmciabusopen(dev, flag, mode, p)
        struct pcmciabus_softc *pcmcia;
 
        PPRINTF(("- pcmciabusopen\n"));
-       if (pcmcia_cntrl == 0)
-               return ENXIO;
        switch (PCMCIABUS_DEVTYPE(unit)) {
        case PCMCIABUS_BUS:
                if (unit != PCMCIABUS_BUS)
@@ -1023,10 +909,11 @@ pcmciabusopen(dev, flag, mode, p)
                break;
 
        case PCMCIABUS_CHIP:
-               chipid = PCMCIABUS_CHIPIID(unit);
-               if (chipid > 3)
+               chipid = PCMCIABUS_CHIPID(unit);
+               if (chipid < 0 || chipid >= pcmciabus_cd.cd_ndevs)
                        return ENXIO;
-               if (pcmcia_drivers[chipid].adapter_softc == NULL)
+               pcmcia = pcmciabus_cd.cd_devs[chipid];
+               if (pcmcia == NULL || pcmcia->sc_driver == NULL)
                        return ENXIO;
 
                if (chipopen[chipid])
@@ -1037,20 +924,22 @@ pcmciabusopen(dev, flag, mode, p)
 
        case 0:
                slot = PCMCIABUS_SLOT(unit);
-               chipid = slot >> 1;
+               chipid = PCMCIABUS_CHIPNO(unit);
 
-               if (chipid > 7)
+               if (chipid < 0 || chipid >= pcmciabus_cd.cd_ndevs)
                        return ENXIO;
 
-               if (pcmcia_drivers[chipid].adapter_softc == NULL)
+               pcmcia = pcmciabus_cd.cd_devs[chipid];
+               if (pcmcia == NULL || pcmcia->sc_driver == NULL)
                        return ENXIO;
-               pcmcia = pcmciabuscd.cd_devs[0];
                link = pcmcia->sc_link[slot];
+               if (!link)
+                       return ENXIO;
 
-               if (link->flags & PCMCIA_SLOT_OPEN)
+               if (ISSET(link->flags, PCMCIA_SLOT_OPEN))
                        return EBUSY;
 
-               link->flags |= PCMCIA_SLOT_OPEN;
+               SET(link->flags, PCMCIA_SLOT_OPEN);
                break;
 
        default:
@@ -1062,7 +951,7 @@ pcmciabusopen(dev, flag, mode, p)
 
 
 int
-pcmciabusclose(dev)
+pcmciaclose(dev)
 {
        int unit = PCMCIABUS_UNIT(dev);
        int chipid, slot;
@@ -1071,25 +960,24 @@ pcmciabusclose(dev)
        int s;
 
        PPRINTF(("- pcmciabusclose\n"));
-       if (pcmcia_cntrl == 0)
-               return ENXIO;
        switch (PCMCIABUS_DEVTYPE(unit)) {
        case PCMCIABUS_BUS:
                busopen = 0;
                break;
 
        case PCMCIABUS_CHIP:
-               chipid = PCMCIABUS_CHIPIID(unit);
+               chipid = PCMCIABUS_CHIPID(unit);
                chipopen[chipid] = 0;
                break;
 
        case 0:
                slot = PCMCIABUS_SLOT(unit);
-               pcmcia = pcmciabuscd.cd_devs[0];
+               chipid = PCMCIABUS_CHIPNO(unit);
+               pcmcia = pcmciabus_cd.cd_devs[chipid];
                link = pcmcia->sc_link[slot];
 
                s = splclock();
-               link->flags &= ~(PCMCIA_SLOT_OPEN|PCMCIA_SLOT_EVENT);
+               CLR(link->flags, (PCMCIA_SLOT_OPEN|PCMCIA_SLOT_EVENT));
                splx(s);
                break;
 
@@ -1104,8 +992,8 @@ pcmciachip_ioctl(chipid, cmd, data)
        int             chipid, cmd;
        caddr_t         data;
 {
-       int             err = 0;
-       struct pcmcia_adapter *pca = &pcmcia_drivers[chipid];
+       struct pcmciabus_softc *pcmcia = pcmciabus_cd.cd_devs[chipid];
+       struct pcmcia_adapter *pca = pcmcia->sc_driver;
        struct pcmcia_link link;
        struct pcmcia_regs *pi = (void *) data;
 
@@ -1117,7 +1005,7 @@ pcmciachip_ioctl(chipid, cmd, data)
        case PCMCIAIO_READ_REGS:
                pi->chip = chipid;
                link.adapter = pca;
-               link.slot = chipid << 1;
+               link.slot = 0;
                return PCMCIA_SERVICE(pca, &link, PCMCIA_OP_GETREGS,
                                      pi->chip_data, 0);
        }
@@ -1131,7 +1019,9 @@ pcmciaslot_ioctl(link, slotid, cmd, data)
        caddr_t         data;
 {
        int             err = 0;
-       struct pcmcia_adapter *pca = &pcmcia_drivers[slotid >> 1];
+       struct pcmciabus_softc *pcmcia =
+           pcmciabus_cd.cd_devs[PCMCIABUS_CHIPNO(slotid)];
+       struct pcmcia_adapter *pca = pcmcia->sc_driver;
 
        PPRINTF(("- pcmciaslot_ioctl\n"));
        if (link == NULL || pca->chip_link == NULL ||
@@ -1147,10 +1037,10 @@ pcmciaslot_ioctl(link, slotid, cmd, data)
                        err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_STATUS,
                                             &pi->status, 0);
                        if (!err) {
-                               pi->status |= ((link->flags & CARD_IS_MAPPED) ?
-                                              PCMCIA_CARD_IS_MAPPED : 0) |
-                                       ((link->flags & PCMCIA_SLOT_INUSE) ?
-                                        PCMCIA_CARD_INUSE : 0);
+                           if (ISSET(link->flags, CARD_IS_MAPPED))
+                               SET(pi->status, PCMCIA_CARD_IS_MAPPED);
+                           if (ISSET(link->flags, PCMCIA_SLOT_INUSE))
+                               SET(pi->status, PCMCIA_CARD_INUSE);
                        }
                        return err;
                }
@@ -1163,7 +1053,7 @@ pcmciaslot_ioctl(link, slotid, cmd, data)
                        if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_STATUS,
                                                  &status, 0)) != 0)
                                return err;
-                       if ((status & PCMCIA_CARD_PRESENT) == 0)
+                       if (!ISSET(status, PCMCIA_CARD_PRESENT))
                                return ENODEV;
                        pi->slot = slotid;
                        return pcmcia_read_cis(link, pi->cis_data, 0,
@@ -1180,6 +1070,8 @@ pcmciaslot_ioctl(link, slotid, cmd, data)
                return pcmcia_unconfigure(link);
 
        case PCMCIAIO_UNMAP:
+               if (ISSET(link->flags, PCMCIA_SLOT_INUSE))
+                       return EBUSY;
                return pcmcia_unmapcard(link);
 
        case PCMCIAIO_SET_POWER:
@@ -1226,11 +1118,11 @@ pcmciaslot_ioctl(link, slotid, cmd, data)
                                             &status, 0);
                        if (err)
                                return err;
-                       if ((status & PCMCIA_CARD_PRESENT) == 0
+                       if (!ISSET(status, PCMCIA_CARD_PRESENT)
                                return ENODEV;
 
-                       if (status = pcmcia_read_cis(link, pi->cis_data, 0,
-                                                    CIS_MAXSIZE))
+                       if ((status = pcmcia_read_cis(link, pi->cis_data, 0,
+                                                     CIS_MAXSIZE)))
                                return status;
 
                        bzero(&pc_cf, sizeof(pc_cf));
@@ -1246,7 +1138,9 @@ pcmciaslot_ioctl(link, slotid, cmd, data)
 
                        SCRATCH_INUSE(pca) = 1;
                        splx(s);
-                       if ((err = PCMCIA_MAP_MEM(pca, link, SCRATCH_MEM(pca),
+                       if ((err = PCMCIA_MAP_MEM(pca, link,
+                                                 SCRATCH_BC(pca),
+                                                 SCRATCH_MEM(pca),
                                                  pc_cf.cfg_off &
                                                  ~(SCRATCH_SIZE(pca)-1),
                                                  SCRATCH_SIZE(pca),
@@ -1264,7 +1158,9 @@ pcmciaslot_ioctl(link, slotid, cmd, data)
                                }
                                *d++ = 0xff;
                                *d++ = 0xff;
-                               PCMCIA_MAP_MEM(pca, link, SCRATCH_MEM(pca),
+                               PCMCIA_MAP_MEM(pca, link,
+                                              SCRATCH_BC(pca),
+                                              SCRATCH_MEM(pca),
                                               0,SCRATCH_SIZE(pca), 
                                               PCMCIA_LAST_WIN|PCMCIA_UNMAP);
                        } 
@@ -1281,49 +1177,56 @@ pcmciaslot_ioctl(link, slotid, cmd, data)
 }
 
 int
-pcmciabusioctl(dev, cmd, data, flag, p)
+pcmciaioctl(dev, cmd, data, flag, p)
        dev_t           dev;
        int             cmd;
        caddr_t         data;
        int             flag;
        struct proc    *p;
 {
-       int             unit = PCMCIABUS_UNIT(dev);
+       int unit = PCMCIABUS_UNIT(dev);
+       int chipid = PCMCIABUS_CHIPNO(unit);
        struct pcmciabus_softc *pcmcia;
        struct pcmcia_link *link;
 
-       PPRINTF(("- pcmciabus_ioctl\n"));
-       pcmcia = pcmciabuscd.cd_devs[0];
-       if (pcmcia_cntrl == 0 || pcmcia == NULL)
+       PPRINTF(("- pcmciabusioctl\n"));
+       if (chipid < 0 || chipid >= pcmciabus_cd.cd_ndevs)
                return ENXIO;
+
+       pcmcia = pcmciabus_cd.cd_devs[chipid];
+       if (pcmcia == NULL)
+               return ENXIO;
+
        switch (PCMCIABUS_DEVTYPE(unit)) {
 #if 0
        case PCMCIABUS_BUS:
-               return pcmciabus_ioctl(0, cmd, data);
+               return pcmciabus_ioctl(PCMCIABUS_BUSID(unit), cmd, data);
 #endif
        case PCMCIABUS_CHIP:
-               return pcmciachip_ioctl(PCMCIABUS_CHIPIID(unit), cmd, data);
+               return pcmciachip_ioctl(PCMCIABUS_CHIPID(unit), cmd, data);
        case 0:
                link = pcmcia->sc_link[PCMCIABUS_SLOT(unit)];
-               return pcmciaslot_ioctl(link, PCMCIABUS_SLOT(unit), cmd, data);
+               return pcmciaslot_ioctl(link, PCMCIABUS_SLOTID(unit),
+                                       cmd, data);
        default:
                return ENXIO;
        }
 }
 
 int
-pcmciabusselect(device, rw, p)
+pcmciaselect(device, rw, p)
        dev_t device;
        int rw;
        struct proc *p;
 {
        int s;
        int unit = PCMCIABUS_UNIT(device);
+       int chipid = PCMCIABUS_CHIPNO(unit);
        struct pcmciabus_softc *pcmcia;
        struct pcmcia_link *link;
 
-       PPRINTF(("- pcmciabus_ioctl\n"));
-       pcmcia = pcmciabuscd.cd_devs[0];
+       PPRINTF(("- pcmciabus_select\n"));
+       pcmcia = pcmciabus_cd.cd_devs[chipid];
        
        switch (PCMCIABUS_DEVTYPE(unit)) {
        case 0:
@@ -1335,14 +1238,14 @@ pcmciabusselect(device, rw, p)
                return 0;
        }
 
-       s = splclock();         /* XXX something higher than all devices that can plug in.... */
+       s = splpcmcia();
        switch (rw) {
        case FREAD:
        case FWRITE:
                break;
        case 0:
-               if (link->flags & PCMCIA_SLOT_EVENT) {
-                       link->flags &= ~PCMCIA_SLOT_EVENT;
+               if (ISSET(link->flags, PCMCIA_SLOT_EVENT)) {
+                       CLR(link->flags, PCMCIA_SLOT_EVENT);
                        splx(s);
                        return 1;
                }
@@ -1354,54 +1257,14 @@ pcmciabusselect(device, rw, p)
 }
 
 int
-pcmciabusmmap()
+pcmciammap()
 {
        return ENXIO;
 }
 
-/* pcmcia template string match. A '*' matches any number of characters.
-   A NULL template matches all strings.
-   return-value 
-    0 nomatch 
-    1 wildcard match 
-    2 excact match
- */
-static int
-pcmcia_strcmp(templ,val,flags,msg)
-    char *templ;
-    char *val;
-    int flags;
-    char *msg;
-{
-    char *ltempl=NULL,*lval=NULL;
-
-    if (flags & PC_SHOWME)
-           printf("%s = `%s'-`%s'\n", msg, templ ? templ : "X", val);
-
-    if(templ==NULL)
-        return 1;
-    while(*val) {
-        while(*templ=='*') {
-            ltempl=++templ;
-            lval=val;
-        }
-        if(*templ==*val) {
-            templ++;
-            val++;
-        } else {
-            if(ltempl==NULL)
-                return 0;
-            val=++lval;
-            templ=ltempl;
-        }
-    }
-    if(*templ!=0 && *templ!='*')
-        return 0;
-    return  ltempl?1:2;
-}
 
 #ifdef PCMCIA_DEBUG
-static void
+void
 pcmciadumpcf(cf)
        struct pcmcia_conf * cf;
 {
@@ -1414,6 +1277,7 @@ pcmciadumpcf(cf)
        printf("IRQ type %s%s\n", cf->irq_level ? "Level " : "", 
                                  cf->irq_pulse ? "Pulse" : "");
        printf("IRQ num %x\n", cf->irq_num);
+       printf("IRQ mask %x\n", cf->irq_mask);
        printf("CFG type %x %x\n", cf->cfgtype,cf->cfgid);
        printf("Cardtype %s\n", cf->iocard ? "IO" : "MEM");
        for (i = 0; i < cf->iowin; i++) {
@@ -1431,3 +1295,43 @@ pcmciadumpcf(cf)
        }
 }
 #endif
+
+int
+pcmcia_print(aux, pnp)
+       void *aux;
+       char *pnp;
+{
+#if 0
+       struct pcmcia_attach_args *paa = aux;
+       printf(" slot %d", paa->paa_link->slot);
+#endif
+       return (0);                     /* be silent */
+}
+
+/*
+ * Filter out inappropriate configurations before heading off to
+ * the device match routines.
+ */
+int
+pcmcia_submatch(parent, match, aux)
+       struct device *parent;
+       void *match, *aux;
+{
+       struct device *self = match;
+       struct cfdata *cf = self->dv_cfdata;
+       struct pcmcia_attach_args *paa = aux;
+       struct pcmcia_link *link = paa->paa_link;
+
+#if 0
+       printf("pcmcia_submatch: paa=%p link=%p, cf=%p\n", paa, link, cf);
+       delay(2000000);
+
+#endif
+
+       if (cf->cf_loc[6] != -1 && link->slot != cf->cf_loc[6]) {
+               printf("slot mismatch: %d cf_loc %d\n", link->slot, cf->cf_loc[6]);
+               return 0;
+       }
+
+       return ((*cf->cf_attach->ca_match)(parent, match, aux));
+}
index ab0e5b0..3e09e03 100644 (file)
@@ -1,11 +1,50 @@
+/*     $Id: pcmcia_conf.c,v 1.2 1996/04/29 14:17:21 hvozda Exp $       */
+/*
+ * Copyright (c) 1996 John T. Kohl.  All rights reserved.
+ * Copyright (c) 1994 Stefan Grefen.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Charles Hannum.
+ *     This product includes software developed by Stefan Grefen.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * This file is shared between user and kernel space, so be careful with the
+ * coding conventions.
+ */
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <sys/device.h>
+#include <sys/time.h>
+#include <sys/systm.h>
 
-#include <dev/pcmcia/pcmcia.h>
-#include <dev/pcmcia/pcmciabus.h>
+#include <dev/pcmcia/pcmciavar.h>
+#include <dev/pcmcia/pcmciareg.h>
 #include <dev/pcmcia/pcmcia_ioctl.h>
 
 #ifdef CFG_DEBUG
@@ -68,7 +107,7 @@ pcmcia_get_cf(pc_link, data, dlen, idx, pc_cf)
 }
 
 
-int
+void
 read_cfg_info(tbuf, len, pc_cf)
        u_char         *tbuf;
        int             len;
@@ -110,14 +149,15 @@ read_cfg_info(tbuf, len, pc_cf)
        }
 }
 
-int
+void
 parse_cfent(tbuf, len, slotid, pc_cf)
        u_char         *tbuf;
        int             len;
        int             slotid;
        struct pcmcia_conf *pc_cf;
 {
-       int i, idx, defp, iop, io_16, ios, ftrs, intface, k;
+       volatile int i, idx, defp, intface, k;
+       int ios, ftrs;
        int host_addr_p, addr_size, len_size;
 
 #ifdef CFG_DEBUG
@@ -164,7 +204,6 @@ parse_cfent(tbuf, len, slotid, pc_cf)
                        int io_16, io_block_len, io_block_size, io_lines;
                        int io_range;
 
-                       iop = 1;
                        io_lines = tbuf[i] & TPCE_FS_IO_LINES;
                        io_16 = tbuf[i] & TPCE_FS_IO_BUS16;
                        io_range = tbuf[i] &TPCE_FS_IO_RANGE;
@@ -178,6 +217,8 @@ parse_cfent(tbuf, len, slotid, pc_cf)
                                                TPCE_FS_IO_SIZE_SHIFT;
                                ios = (tbuf[i] & TPCE_FS_IO_NUM) + 1;
                                i++;
+                               elen=io_block_len+(io_block_len==3?1:0)+
+                                       io_block_size+(io_block_size==3?1:0);
                                if ((ftrs & TPCE_FS_IRQ) != 0) {
                                        iptr=(ios * elen) + i;
 #define IRQTYPE (TPCE_FS_IRQ_PULSE|TPCE_FS_IRQ_LEVEL)
@@ -249,7 +290,6 @@ parse_cfent(tbuf, len, slotid, pc_cf)
                        }
                }
                if (ftrs & TPCE_FS_IRQ) {
-                       int             irq_mask, irqp, irq;
                        pc_cf->irq_level = (tbuf[i] & TPCE_FS_IRQ_LEVEL) != 0;
                        pc_cf->irq_pulse = (tbuf[i] & TPCE_FS_IRQ_PULSE) != 0;
                        pc_cf->irq_share = (tbuf[i] & TPCE_FS_IRQ_SHARE) != 0;
@@ -339,6 +379,10 @@ parse_cfent(tbuf, len, slotid, pc_cf)
                                        mem_haddrs[j] <<= 8;
 
                                }
+                               break;
+                       default:
+                               mems = 0;
+                               break;
                        }
                        for (j = 0; j < mems; j++) {
                                pc_cf->mem[j].len = mem_lens[j];
@@ -384,7 +428,7 @@ parse_cfent(tbuf, len, slotid, pc_cf)
                                pc_cf->mem[i].start!=tmp_cf.mem[i].start)
                                    return;
 
-                       /* *pc_cf = tmp_cf;/**/
+                       /* *pc_cf = tmp_cf; */
                        pc_cf->cfgid = idx;
                }
                return;
@@ -472,6 +516,134 @@ pcmcia_get_cisver1(pc_link, data, len, manu, model, add_inf1, add_inf2)
                }
                p += clen + 2;
        }
-       printf("%x %x\n", p, end);
+#ifdef CFG_DEBUG
+       printf("get_cisver1 failed, buffer [%p,%p)\n", p, end);
+#endif
        return ENODEV;
 }
+
+#define NULLCP (void *)0
+
+/* pcmcia template string match. A '*' matches any number of characters.
+   A NULL template matches all strings.
+   return-value 
+    0 nomatch 
+    1 wildcard match 
+    2 excact match
+ */
+int
+pcmcia_strcmp(templ, val, flags, msg)
+       const char *templ;
+       const char *val;
+       int flags;
+       const char *msg;
+{
+       const char *ltempl = NULLCP;
+       const char *lval = NULLCP;
+
+       if (flags & PC_SHOWME)
+               printf("%s = `%s'-`%s'\n", msg, templ ? templ : "X", val);
+
+       if (templ == NULLCP) {
+           return 1;
+       }
+       while (*val) {
+               while (*templ == '*') {
+                       ltempl = ++templ;
+                       lval = val;
+               }
+               if (*templ == *val) {
+                       templ++;
+                       val++;
+               } else {
+                       if (ltempl == NULLCP)
+                               return 0;
+                       val = ++lval;
+                       templ = ltempl;
+               }
+       }
+       if (*templ != 0 && *templ != '*')
+               return 0;
+       return (ltempl ? 1 : 2);
+}
+
+/*
+ * Return a match value to estimate how good a match the specified driver
+ * is for this particular card.
+ */
+int
+pcmcia_matchvalue(card, dentry)
+       const struct pcmcia_cardinfo *card;
+       struct pcmciadevs *dentry;
+{
+       int match;
+
+#ifdef PCMCIA_DEBUG
+       dentry->flags |= PC_SHOWME;
+#endif
+       match = pcmcia_strcmp(dentry->manufacturer,
+                            card->manufacturer,
+                            dentry->flags, "manufacturer")<<6;
+       match |= pcmcia_strcmp(dentry->model,
+                              card->model, dentry->flags, "model")<<4;
+       match |= pcmcia_strcmp(dentry->add_inf1,
+                              card->add_info1, dentry->flags, "info1")<<2;
+       match |= pcmcia_strcmp(dentry->add_inf2,
+                              card->add_info2, dentry->flags, "info2");
+#ifdef PCMCIA_DEBUG
+       printf("match == %d\n", match);
+#endif
+       return match;
+}
+
+int
+pcmcia_bestvalue(card, dentries, nentries, rmatch)
+       struct pcmcia_cardinfo *card;
+       struct pcmciadevs *dentries;
+       int nentries;
+       struct pcmciadevs **rmatch;
+{
+       int bestmatch, thismatch;
+       register int i;
+       for (i = 0, bestmatch = 0; i < nentries; i++) {
+               if ((thismatch = pcmcia_matchvalue(card, &dentries[i])) >
+                   bestmatch) {
+                       bestmatch = thismatch;
+                       *rmatch = &dentries[i];
+               }
+       }
+       return bestmatch;
+}
+
+int
+pcmcia_slave_match(parent, match, aux, devs, ndevs)
+       struct device *parent;
+       void *match, *aux;
+       struct pcmciadevs *devs;
+       int ndevs;
+{
+       struct pcmcia_attach_args *paa = aux;
+       struct device *self = match;
+       struct pcmciadevs *devmatch;
+       int value;
+
+       if (paa->paa_link->fordriver &&
+           strcmp(paa->paa_link->fordriver,
+                  self->dv_cfdata->cf_driver->cd_name))
+           return 0;                   /* wrong driver */
+       value = pcmcia_bestvalue(paa->paa_cardinfo, devs, ndevs, &devmatch);
+       if (value > paa->paa_bestmatch) {
+               paa->paa_bestmatch = value;
+               paa->paa_link->device = devmatch;
+#ifdef PCMCIA_DEBUG
+               printf("pcmcia_slave_match: best so far, %p->%p\n",
+                      paa->paa_link, devmatch);
+               printf("pcmcia_slave_match returns %d\n", value);
+               delay(2000000);
+#endif
+               if (!paa->paa_matchonly)
+                   return value;
+       }
+       return 0;
+}
index 535e122..dd8b9e6 100644 (file)
@@ -1,3 +1,4 @@
+/*     $Id: pcmcia_ioctl.h,v 1.2 1996/04/29 14:17:25 hvozda Exp $      */
 /*
  * Copyright (c) 1993, 1994 Stefan Grefen.  All rights reserved.
  *
@@ -52,8 +53,7 @@ struct pcmcia_regs {
 #define PCMCIASIO_POWER_AUTO       0x7
 #define PCMCIASIO_POWER_OFF        0x0
 #define PCMCIAIO_CONFIGURE        _IOW('s', 140, struct pcmcia_conf)
-#define PCMCIAIO_UNMAP            _IOW('s', 141, int)
-#define PCMCIAIO_UNCONFIGURE      _IOW('s', 142, int)
+#define PCMCIAIO_UNMAP            _IO('s', 141)
+#define PCMCIAIO_UNCONFIGURE      _IO('s', 142)
 #define PCMCIAIO_READ_COR         _IOR('s', 143, struct pcmcia_info)
 #define PCMCIAIO_READ_REGS        _IOWR('s', 160, struct pcmcia_regs)
-
diff --git a/sys/dev/pcmcia/pcmciabus.h b/sys/dev/pcmcia/pcmciabus.h
deleted file mode 100644 (file)
index 4dceb98..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (c) 1993, 1994 Stefan Grefen.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following dipclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by Charles Hannum.
- * 4. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *     $Id: pcmciabus.h,v 1.1 1996/01/15 00:05:13 hvozda Exp $
- */
- /* derived from scsicconf.[ch] writenn by Julian Elischer et al */
-
-#ifndef        _PCMCIA_PCMCIABUS_H_
-#define _PCMCIA_PCMCIABUS_H_ 1
-
-#include <sys/queue.h>
-#include <sys/select.h>
-#include <machine/cpu.h>
-
-/*
- * The following documentation tries to describe the relationship between the
- * various structures defined in this file:
- *
- * each adapter type has a pcmcia_adapter struct. This describes the adapter and
- *    identifies routines that can be called to use the adapter.
- * each device type has a pcmcia_device struct. This describes the device and
- *    identifies routines that can be called to use the device.
- * each existing device position (pcmciabus + port)
- *    can be described by a pcmcia_link struct.
- *    Only port positions that actually have devices, have a pcmcia_link
- *    structure assigned. so in effect each device has pcmcia_link struct.
- *    The pcmcia_link structure contains information identifying both the
- *    device driver and the adapter driver for that port on that pcmcia bus,
- *    and can be said to 'link' the two.
- * each individual pcmcia bus has an array that points to all the pcmcia_link
- *    structs associated with that pcmcia bus. Slots with no device have
- *    a NULL pointer.
- * each individual device also knows the address of it's own pcmcia_link
- *    structure.
- *
- *                             -------------
- *
- * The key to all this is the pcmcia_link structure which associates all the 
- * other structures with each other in the correct configuration.  The
- * pcmcia_link is the connecting information that allows each part of the 
- * pcmcia system to find the associated other parts.
- */
-
-
-struct pcmcia_link;
-struct pcmcia_conf;
-struct pcmcia_adapter;
-
-/*
- * These entrypoints are called by the high-end drivers to get services from
- * whatever low-end drivers they are attached to each adapter type has one of
- * these statically allocated.
- */
-struct pcmcia_funcs {
-/* 4 map io range */
-       int (*pcmcia_map_io) __P((struct pcmcia_link *, u_int, u_int, int));
-/* 8 map memory window */
-       int (*pcmcia_map_mem) __P((struct pcmcia_link *, caddr_t,
-                                  u_int, u_int, int));
-/*12 map interrupt */
-       int (*pcmcia_map_intr) __P((struct pcmcia_link *, int, int));
-/*26 power on/off etc */
-       int (*pcmcia_service) __P((struct pcmcia_link *, int, void *, int));
-};
-
-struct pcmciabus_link {                        /* Link back to the bus we are on */
-       /* Bus specific configure    */
-       int (*bus_config) __P((struct pcmcia_link *, struct device *,
-                              struct pcmcia_conf *, struct cfdata *));
-       /* Bus specific unconfigure  */
-       int (*bus_unconfig) __P((struct pcmcia_link *));
-       /* Bus specific probe        */
-       int (*bus_probe) __P((struct device *, void *,
-                             void *, struct pcmcia_link *));
-       /* Bus specific search       */
-       int (*bus_search) __P((struct device *, void *, cfprint_t));
-       /* initialize scratch        */
-       int (*bus_init) __P((struct device *, struct cfdata *,
-                            void *, struct pcmcia_adapter *, int));
-};
-struct pcmcia_adapter {
-       struct pcmcia_funcs *chip_link;
-       struct pcmciabus_link *bus_link;
-        void *          adapter_softc;
-       caddr_t scratch_mem;            /* pointer to scratch window */
-       int scratch_memsiz;             /* size of scratch window    */
-       int scratch_inuse;              /* window in use             */
-};
-
-#define PCMCIA_MAP_ATTR                0x0100 /* for memory only */
-#define PCMCIA_MAP_8           0x0100 /* for io only */
-#define PCMCIA_MAP_16          0x0200
-#define PCMCIA_UNMAP           0x0400
-#define PCMCIA_PHYSICAL_ADDR    0x0800
-#define PCMCIA_UNMAP_ALL       0x0c00
-#define PCMCIA_FIXED_WIN       0x1000
-#define PCMCIA_LAST_WIN                0x0010
-#define PCMCIA_FIRST_WIN       0x0020
-#define PCMCIA_ANY_WIN         0x0030
-
-#define        PCMCIA_OP_RESET         0x0000
-#define        PCMCIA_OP_POWER         0x0001
-#define        PCMCIA_OP_STATUS        0x0002
-#define        PCMCIA_OP_GETREGS       0x0003
-#define        PCMCIA_OP_WAIT          0x0004
-
-#define PCMCIA_POWER_ON                0x0001
-#define PCMCIA_POWER_5V                0x0002
-#define PCMCIA_POWER_3V                0x0004
-#define PCMCIA_POWER_AUTO      0x0008
-
-#define PCMCIA_CARD_PRESENT     0x0001
-#define PCMCIA_BATTERY         0x0002
-#define PCMCIA_WRITE_PROT      0x0004
-#define PCMCIA_READY           0x0008
-#define PCMCIA_POWER           0x0010
-#define PCMCIA_POWER_PP                0x0020
-#define PCMCIA_CARD_IS_MAPPED   0x1000
-#define PCMCIA_CARD_INUSE       0x2000
-
-
-/*
- * This structure describes the connection between an adapter driver and
- * a device driver, and is used by each to call services provided by
- * the other, and to allow generic pcmcia glue code to call these services
- * as well.
- */
-struct pcmcia_link {
-               char    pcmciabus;              /* the Nth pcmciabus */
-               char    slot;                   /* slot of this dev */
-               char    flags;                  
-#define CARD_IS_MAPPED         0x01
-#define PCMCIA_ATTACH          0x02
-#define PCMCIA_REATTACH        0x04
-#define PCMCIA_SLOT_INUSE      0x08
-#define PCMCIA_ATTACH_TYPE     (PCMCIA_ATTACH|PCMCIA_REATTACH)
-#define PCMCIA_SLOT_EVENT      0x80
-#define PCMCIA_SLOT_OPEN       0x40
-        char   opennings;
-
-       char    iowin;
-       char    memwin;
-       char    intr;
-       char    dummy;
-               struct  pcmcia_adapter *adapter;        /* adapter entry points etc. */
-               struct  pcmciadevs *device;     /* device entry points etc. */
-       void    *devp;                  /* pointer to configured device */
-               void    *fordriver;             /* for private use by the driver */
-       void    *shuthook;              /* shutdown hook handle */
-       struct selinfo  pcmcialink_sel; /* for select users */
-};
-
-/*
- * One of these is allocated and filled in for each pcmcia bus.
- * it holds pointers to allow the pcmcia bus to get to the driver
- * it also has a template entry which is the prototype struct
- * supplied by the adapter driver, this is used to initialise
- * the others, before they have the rest of the fields filled in
- */
-struct pcmciabus_softc {
-       struct device sc_dev;
-       struct pcmcia_link *sc_link[8];
-};
-
-struct pcmcia_conf {
-    int irq_share:1; 
-    int irq_level:1; /* 1 level */
-    int irq_pulse:1; /* 1  pulse */
-    int irq_vend:1;
-    int irq_iock:1;
-    int irq_berr:1;
-    int irq_nmi:1;
-    int iocard:1;
-    u_char iowin;
-    u_char memwin;
-    u_char irq_num;
-    u_char cfgtype;
-#define CFGENTRYID     0x20
-#define CFGENTRYMASK   (CFGENTRYID|(CFGENTRYID-1))
-#define DOSRESET       0x40
-    int cfg_regmask;
-    int irq_mask;
-    int cfg_off;
-    struct iowin {
-       int start;
-       int len;
-       int flags;
-    }io[4];
-    struct memwin {
-       int start; 
-       int caddr;
-       int len;
-       int flags;
-    }mem[4];
-    char driver_name[8][4]; /* up to four different functions on a card */
-    int  unitid;
-    int  cfgid;
-};
-
-struct pcmcia_device {
-    char *name;
-    int (*pcmcia_config) __P((struct pcmcia_link *, struct device *,
-                             struct pcmcia_conf *, struct cfdata *));
-    int (*pcmcia_probe) __P((struct device *, void *,
-                            void *, struct pcmcia_link *));
-    int (*pcmcia_insert) __P((struct pcmcia_link *, struct device *,
-                             struct cfdata *));
-    int        (*pcmcia_remove) __P((struct pcmcia_link *, struct device *));
-};
-
-struct pcmciadevs {
-        char *devname;
-        int flags;              /* 1 show my comparisons during boot(debug) */
-#define PC_SHOWME       0x01
-        char *manufacturer;
-        char *model;
-        char *add_inf1;
-        char *add_inf2;
-        void *param;
-        struct pcmcia_device *dev;
-};
-
-#ifdef _KERNEL
-extern int pcmcia_add_device __P((struct pcmciadevs *));
-extern int pcmcia_get_cf __P((struct pcmcia_link *, u_char *, int, int,
-                             struct pcmcia_conf *));
-extern int pcmcia_targmatch __P((struct device *, struct cfdata *, void *));
-#endif
-
-/* in pcmcia_conf.c, available for user space too: */
-extern int pcmcia_get_cisver1 __P((struct pcmcia_link *, u_char *, int,
-                                  char *, char *, char *, char *));
-int      parse_cfent  __P((u_char *, int, int, struct pcmcia_conf *));
-int      read_cfg_info __P((u_char *, int, struct pcmcia_conf *));
-void   pcmcia_getstr __P((char *buf, u_char **, u_char *));
-
-#endif /* _PCMCIA_PCMCIABUS_H_ */
diff --git a/sys/dev/pcmcia/pcmciareg.h b/sys/dev/pcmcia/pcmciareg.h
new file mode 100644 (file)
index 0000000..f3f4446
--- /dev/null
@@ -0,0 +1,136 @@
+/*     $Id: pcmciareg.h,v 1.1 1996/04/29 14:17:35 hvozda Exp $ */
+/*
+ * This file was apparently first written by Stefan Grefen, although it
+ * contained no copyright notice at the time.
+ */
+#ifndef __PCMCIAREG_H__
+#define __PCMCIAREG_H__
+
+/*
+ * Configuration Registers
+ *
+ * These are the registers required by Release 2.0 of the standard
+ * (Section 4.15)
+ */
+
+/* Offsets for register ordering */
+#define PCMCIA_COR     0x00    /* Configuration and Option Register */
+#define PCMCIA_CCSR    0x02    /* Card Configuration and Status Register */
+#define PCMCIA_PIR     0x04    /* Pin Replacement Register */
+#define PCMCIA_SCR     0x06    /* Socket and Copy Register */
+
+/* Now register bits, ordered by reg # */
+
+/* For Configuration and Option Register (PCMCIA_COR) */
+#define PCMCIA_MEMIO   0x01    /* Use I/O Space */
+#define PCMCIA_CNFG    0x0e    /* I/O decoding configuration */
+#define PCMCIA_CNFGMASK 0x3f   /* Use template */
+#define PCMCIA_LVLREQ  0x40    /* Generate level mode interrupts */
+#define PCMCIA_SRESET  0x80    /* Reset Card */
+
+/* For Card Configuration and Status Register (PCMCIA_CCSR) */
+#define PCMCIA_INTR            0x02    /* Interrupt Pending */
+#define PCMCIA_POWER_DOWN      0x04
+#define PCMCIA_AUDIO_ENA       0x08
+#define PCMCIA_IOIS8           0x20
+#define PCMCIA_SIGCHG_ENA      0x40
+#define PCMCIA_CHANGED         0x80
+
+/* Pin Replacement Register (PCMCIA_PIR) */
+#define PCMCIA_WP_STATUS          0x01
+#define PCMCIA_READY_STATUS       0x02
+#define PCMCIA_BVD2_STATUS        0x04
+#define PCMCIA_BVD1_STATUS        0x08
+#define PCMCIA_WP_EVENT                   0x10
+#define PCMCIA_READY_EVENT        0x20
+#define PCMCIA_BVD2_EVENT         0x40
+#define PCMCIA_BVD1_EVENT         0x80
+
+
+/* For Socket and Copy Register (PCMCIA_SCR) */
+#define PCMCIA_SOCKNUM 0x0f    /* Which socket I'm sitting in */
+#define PCMCIA_COPNUM  0x70    /* Which instance I am. */
+
+/*
+ * CIS Tuple defines
+ */
+#define CIS_MAXSIZE    512
+
+/* Define tuple types */
+#define CIS_NULL       0x00    /* null tuple */
+#define CIS_DEVICE     0x01    /* Device descriptor, common mem */
+#define CIS_DEVICE_A   0x17    /* Device descriptor, attribute mem */
+#define                CIS_DEVICE_TYPE         0xf0    /* type mask */
+#define                CIS_DEVICE_TYPE_SHIFT   4       /* type offset */
+#define                CIS_DEVICE_WPS          0x08    /* WPS mask */
+#define                CIS_DEVICE_SPEED        0x07    /* speed mask */
+#define                CIS_DEVICE_ADDRS        0xf8    /* # addr units */
+#define                CIS_DEVICE_ADDRS_SHIFT  3       /* # addr units offset */
+#define                CIS_DEVICE_SIZE         0x07
+#define CIS_CSUM       0x10    /* Checksum field */
+#define CIS_NOLINK     0x14    /* No Link */
+#define CIS_VER1       0x15    /* Level 1 Version/Product info */
+#define CIS_CFG_INFO   0x1a    /* Configuration info map */
+#define                TPCC_RASZ               0x03    /* size of regaddr */
+#define                TPCC_RASZ_SHIFT         0
+#define                TPCC_RMSZ               0x3c    /* size of regmask */
+#define                TPCC_RMSZ_SHIFT         2
+#define                TPCC_LAST               0x3f    /* last con entry idx */
+#define                TPCC_LAST_SHIFT         0
+#define CIS_CFG_ENT    0x1b    /* Configuration info entry */
+#define                TPCE_INDX_ENTRY         0x3f    /* config entry # */
+#define                TPCE_INDX_DEF           0x40    /* default bit */
+#define                TPCE_INDX_INT           0x80    /* interface bit */
+#define                TPCE_IF_TYPE            0x0f    /* interface type */
+#define                TPCE_IF_BVD             0x10    /* BVD active bit */
+#define                TPCE_IF_WP              0x20    /* WP active bit */
+#define                TPCE_IF_RDYBSY          0x40    /* RdyBsy active bit */
+#define                TPCE_IF_MWAIT           0x80    /* Wait Sig req. bit */
+#define                TPCE_FS_PWR             0x03    /* Power */
+#define                        TPCE_FS_PWR_VCC         0x01    /* Vcc struct */
+#define                        TPCE_FS_PWR_VPP         0x02    /* Vpp struct */
+#define                TPCE_FS_TD              0x04    /* Timing */
+#define                        TPCE_FS_TD_WAIT         0x03    /* wait scale */
+#define                        TPCE_FS_TD_RDY          0x1c    /* rdy/bsy scale */
+#define                        TPCE_FS_TD_RDY_SHIFT    2
+#define                        TPCE_FS_TD_RSV          0xe0    /* reserved scale */
+#define                        TPCE_FS_TD_RSV_SHIFT    5
+#define                TPCE_FS_IO              0x08    /* I/O Space */
+#define                        TPCE_FS_IO_LINES        0x1f    /* IO addr lines */
+#define                        TPCE_FS_IO_BUS8         0x20    /* bus 8 bit */
+#define                        TPCE_FS_IO_BUS16        0x40    /* bus 16 bit */
+#define                        TPCE_FS_IO_RANGE        0x80    /* range bit */
+#define                        TPCE_FS_IO_LEN          0xc0    /* block len size */
+#define                        TPCE_FS_IO_LEN_SHIFT    6
+#define                        TPCE_FS_IO_SIZE         0x30    /* block size size */
+#define                        TPCE_FS_IO_SIZE_SHIFT   4
+#define                        TPCE_FS_IO_NUM          0x0f    /* # of blocks */
+#define                TPCE_FS_IRQ             0x10    /* IRQ */
+#define                        TPCE_FS_IRQ_SHARE       0x80    /* int sharing */
+#define                        TPCE_FS_IRQ_PULSE       0x40    /* pulse request */
+#define                        TPCE_FS_IRQ_LEVEL       0x20    /* level-trig int */
+#define                        TPCE_FS_IRQ_MASK        0x10    /* irq mask bit */
+#define                        TPCE_FS_IRQ_IRQN        0x0f    /* irqn mask */
+#define                        TPCE_FS_IRQ_VEND        0x08    /* vendor sig */
+#define                        TPCE_FS_IRQ_BERR        0x04    /* bus error */
+#define                        TPCE_FS_IRQ_IOCK        0x02    /* io check */
+#define                        TPCE_FS_IRQ_NMI         0x01    /* nmi */
+#define                TPCE_FS_MEM             0x60    /* Mem Space */
+#define                TPCE_FS_MEM_SHIFT       5
+#define                        TPCE_FS_MEM_HOST        0x80
+#define                        TPCE_FS_MEM_ADDR        0x60
+#define                        TPCE_FS_MEM_ADDR_SHIFT  5
+#define                        TPCE_FS_MEM_LEN         0x18
+#define                        TPCE_FS_MEM_LEN_SHIFT   3
+#define                        TPCE_FS_MEM_WINS        0x07
+#define                TPCE_FS_MISC            0x80    /* Misc */
+#define CIS_MFG                0x20    /* Manufacturer's ID */
+#define CIS_FUNC       0x21    /* Function ID */
+#define CIS_FUNE       0x22    /* Function Extension */
+#define CIS_DRIVER     0x77    /* Driver ID */
+#define CIS_END                0xff    /* Last Entry */
+
+#define splpcmcia spltty
+#define IPL_PCMCIA IPL_TTY
+
+#endif /* __PCMCIAREG_H__ */
diff --git a/sys/dev/pcmcia/pcmciavar.h b/sys/dev/pcmcia/pcmciavar.h
new file mode 100644 (file)
index 0000000..2e4f597
--- /dev/null
@@ -0,0 +1,327 @@
+/*     $Id: pcmciavar.h,v 1.1 1996/04/29 14:17:39 hvozda Exp $ */
+/*
+ * Copyright (c) 1995,1996 John T. Kohl.  All rights reserved.
+ * Copyright (c) 1993, 1994 Stefan Grefen.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following dipclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Charles Hannum.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+ /* derived from scsicconf.[ch] writenn by Julian Elischer et al */
+
+#ifndef        _PCMCIA_PCMCIAVAR_H_
+#define _PCMCIA_PCMCIAVAR_H_ 1
+
+#include <sys/queue.h>
+#include <sys/select.h>
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+/*
+ * The following documentation tries to describe the relationship between the
+ * various structures defined in this file:
+ *
+ * each adapter type has a pcmcia_adapter struct. This describes the adapter and
+ *    identifies routines that can be called to use the adapter.
+ * each device type has a pcmcia_device struct. This describes the device and
+ *    identifies routines that can be called to use the device.
+ * each existing device position (pcmciabus + port)
+ *    can be described by a pcmcia_link struct.
+ *    Only port positions that actually have devices, have a pcmcia_link
+ *    structure assigned. so in effect each device has pcmcia_link struct.
+ *    The pcmcia_link structure contains information identifying both the
+ *    device driver and the adapter driver for that port on that pcmcia bus,
+ *    and can be said to 'link' the two.
+ * each individual pcmcia bus has an array that points to all the pcmcia_link
+ *    structs associated with that pcmcia bus. Slots with no device have
+ *    a NULL pointer.
+ * each individual device also knows the address of it's own pcmcia_link
+ *    structure.
+ *
+ *                             -------------
+ *
+ * The key to all this is the pcmcia_link structure which associates all the 
+ * other structures with each other in the correct configuration.  The
+ * pcmcia_link is the connecting information that allows each part of the 
+ * pcmcia system to find the associated other parts.
+ */
+
+
+struct pcmcia_link;
+struct pcmcia_conf;
+struct pcmcia_adapter;
+
+/*
+ * These entrypoints are called by the high-end drivers to get services from
+ * whatever low-end drivers they are attached to each adapter type has one of
+ * these statically allocated.
+ */
+struct pcmcia_funcs {
+/* 4 map io range */
+       int (*pcmcia_map_io) __P((struct pcmcia_link *, u_int, u_int, int));
+/* 8 map memory window */
+       int (*pcmcia_map_mem) __P((struct pcmcia_link *, bus_chipset_tag_t,
+                                  caddr_t, u_int, u_int, int));
+/*12 map interrupt */
+       int (*pcmcia_map_intr) __P((struct pcmcia_link *, int, int));
+/*16 power on/off etc */
+       int (*pcmcia_service) __P((struct pcmcia_link *, int, void *, int));
+};
+
+struct pcmciabus_link {                        /* Link back to the bus we are on */
+       /* Bus specific configure    */
+       int (*bus_config) __P((struct pcmcia_link *, struct device *,
+                              struct pcmcia_conf *, struct cfdata *));
+       /* Bus specific unconfigure  */
+       int (*bus_unconfig) __P((struct pcmcia_link *));
+       /* Bus specific probe */
+       int (*bus_probe) __P((struct device *, void *,
+                              void *, struct pcmcia_link *));
+       /* Bus specific search       */
+       int (*bus_search) __P((struct device *, void *, cfprint_t));
+       /* initialize scratch        */
+       int (*bus_init) __P((struct device *, struct cfdata *,
+                            void *, struct pcmcia_adapter *, int));
+};
+#define PCMCIA_BUS_INIT(a,b,c,d,e,f) \
+       ((*(a)->bus_link->bus_init)((b),(c),(d),(e),(f)))
+#define PCMCIA_BUS_SEARCH(a,b,c,d) \
+       ((*(a)->bus_link->bus_search)((b),(c),(d)))
+#define PCMCIA_BUS_PROBE(a,b,c,d,e) \
+       ((*(a)->bus_link->bus_probe)((b),(c),(d),(e)))
+#define PCMCIA_BUS_CONFIG(a,b,c,d,e) \
+       ((*(a)->bus_link->bus_config)((b),(c),(d),(e)))
+#define PCMCIA_BUS_UNCONFIG(a,b) \
+       ((*(a)->bus_link->bus_unconfig)((b)))
+
+
+/*
+ * One of these goes at the front of each chip controller's softc, right
+ * after the struct device.
+ */
+struct pcmcia_adapter {
+       struct pcmcia_funcs *chip_link;
+       struct pcmciabus_link *bus_link;
+       bus_chipset_tag_t pa_bc;        /* bus chipset */
+        void *          adapter_softc;
+       caddr_t scratch_mem;            /* pointer to scratch window */
+       int scratch_memsiz;             /* size of scratch window    */
+       bus_mem_handle_t scratch_memh;  /* bus memory handle */
+       int scratch_inuse;              /* window in use             */
+       int nslots;                     /* # of slots controlled */
+};
+
+#define PCMCIA_MAP_ATTR                0x0100 /* for memory only */
+#define PCMCIA_MAP_8           0x0100 /* for io only */
+#define PCMCIA_MAP_16          0x0200
+#define PCMCIA_UNMAP           0x0400
+#define PCMCIA_PHYSICAL_ADDR    0x0800
+#define PCMCIA_UNMAP_ALL       0x0c00
+#define PCMCIA_FIXED_WIN       0x1000
+#define PCMCIA_LAST_WIN                0x0010
+#define PCMCIA_FIRST_WIN       0x0020
+#define PCMCIA_ANY_WIN         0x0030
+
+#define        PCMCIA_OP_RESET         0x0000
+#define        PCMCIA_OP_POWER         0x0001
+#define        PCMCIA_OP_STATUS        0x0002
+#define        PCMCIA_OP_GETREGS       0x0003
+#define        PCMCIA_OP_WAIT          0x0004
+
+#define PCMCIA_POWER_ON                0x0001
+#define PCMCIA_POWER_5V                0x0002
+#define PCMCIA_POWER_3V                0x0004
+#define PCMCIA_POWER_AUTO      0x0008
+
+#define PCMCIA_CARD_PRESENT     0x0001
+#define PCMCIA_BATTERY         0x0002
+#define PCMCIA_WRITE_PROT      0x0004
+#define PCMCIA_READY           0x0008
+#define PCMCIA_POWER           0x0010
+#define PCMCIA_POWER_PP                0x0020
+#define PCMCIA_CARD_IS_MAPPED   0x1000
+#define PCMCIA_CARD_INUSE       0x2000
+
+
+/*
+ * This structure describes the connection between an adapter driver and
+ * a device driver, and is used by each to call services provided by
+ * the other, and to allow generic pcmcia glue code to call these services
+ * as well.
+ */
+struct pcmcia_link {
+               u_char  pcmciabus;              /* the Nth pcmciabus */
+               u_char  slot;                   /* slot of this dev */
+               u_char  flags;                  
+#define CARD_IS_MAPPED         0x01
+#define PCMCIA_ATTACH          0x02
+#define PCMCIA_REATTACH        0x04
+#define PCMCIA_SLOT_INUSE      0x08
+#define PCMCIA_ATTACH_TYPE     (PCMCIA_ATTACH|PCMCIA_REATTACH)
+#define PCMCIA_SLOT_EVENT      0x80
+#define PCMCIA_SLOT_OPEN       0x40
+        u_char opennings;
+
+       u_char    iowin;
+       u_char    memwin;
+       u_char    intr;
+       u_char    dummy;
+               struct  pcmcia_adapter *adapter;        /* adapter entry points etc. */
+               struct  pcmciadevs *device;     /* device entry points etc. */
+       struct pcmciabus_softc *bus;    /* parent pcmcia bus */
+       struct device *devp;            /* pointer to configured device */
+               void    *fordriver;             /* for private use by the driver */
+       struct selinfo  pcmcialink_sel; /* for select users */
+};
+
+/*
+ * One of these is allocated and filled in for each pcmcia bus.
+ * it holds pointers to allow the pcmcia bus to get to the driver
+ * it also has a template entry which is the prototype struct
+ * supplied by the adapter driver, this is used to initialise
+ * the others, before they have the rest of the fields filled in
+ */
+struct pcmciabus_softc {
+       struct device sc_dev;
+       bus_chipset_tag_t sc_bc;
+       struct pcmcia_link *sc_link[4]; /* up to 4 slots per bus */
+       struct pcmcia_adapter *sc_driver;
+};
+
+struct pcmcia_conf {
+    int irq_share:1; 
+    int irq_level:1; /* 1 level */
+    int irq_pulse:1; /* 1  pulse */
+    int irq_vend:1;
+    int irq_iock:1;
+    int irq_berr:1;
+    int irq_nmi:1;
+    int iocard:1;
+    u_char iowin;
+    u_char memwin;
+    u_char irq_num;
+    u_char cfgtype;
+#define CFGENTRYID     0x20
+#define CFGENTRYMASK   (CFGENTRYID|(CFGENTRYID-1))
+#define DOSRESET       0x40
+    int cfg_regmask;
+    int irq_mask;
+    int cfg_off;
+    struct iowin {
+       int start;
+       int len;
+       int flags;
+    }io[4];
+    struct memwin {
+       int start; 
+       int caddr;
+       int len;
+       int flags;
+    }mem[4];
+    char driver_name[8][4]; /* up to four different functions on a card */
+    int  unitid;
+    int  cfgid;
+};
+
+struct pcmcia_device {
+    char *name;
+    int (*pcmcia_config) __P((struct pcmcia_link *, struct device *,
+                             struct pcmcia_conf *, struct cfdata *));
+    int (*pcmcia_probe) __P((struct device *, void *,
+                            void *, struct pcmcia_link *));
+    int (*pcmcia_insert) __P((struct pcmcia_link *, struct device *,
+                             struct cfdata *));
+    int        (*pcmcia_remove) __P((struct pcmcia_link *, struct device *));
+};
+
+#define MAX_CIS_NAMELEN        64              /* version info string len */
+
+struct pcmcia_cardinfo {
+    char manufacturer[MAX_CIS_NAMELEN];
+    char model[MAX_CIS_NAMELEN];
+    char add_info1[MAX_CIS_NAMELEN];
+    char add_info2[MAX_CIS_NAMELEN];
+};
+
+struct pcmciadevs {
+        char *devname;
+        int flags;              /* 1 show my comparisons during boot(debug) */
+#define PC_SHOWME       0x01
+        char *manufacturer;
+        char *model;
+        char *add_inf1;
+        char *add_inf2;
+        void *param;
+        struct pcmcia_device *dev;
+};
+
+/*
+ * PCMCIA driver attach arguments
+ */
+struct pcmcia_attach_args {
+       struct pcmcia_cardinfo *paa_cardinfo; /* card that we're looking at */
+       struct pcmcia_link *paa_link;   /* this nexus */
+       int paa_bestmatch;              /* best match so far */
+       int paa_matchonly;              /* only do matches, don't attach */
+       void    *paa_aux;               /* driver specific */
+};
+
+struct pcmciabus_attach_args {
+       bus_chipset_tag_t pba_bc;
+       int     pba_maddr;
+       int     pba_msize;
+       void    *pba_aux;               /* driver specific */
+};
+
+#ifdef _KERNEL
+extern int pcmcia_add_device __P((struct pcmciadevs *));
+extern int pcmcia_get_cf __P((struct pcmcia_link *, u_char *, int, int,
+                             struct pcmcia_conf *));
+extern int pcmcia_targmatch __P((struct device *, struct cfdata *, void *));
+#endif
+
+/* in pcmcia_conf.c, available for user space too: */
+extern int pcmcia_get_cisver1 __P((struct pcmcia_link *, u_char *, int,
+                                  char *, char *, char *, char *));
+void parse_cfent  __P((u_char *, int, int, struct pcmcia_conf *));
+void read_cfg_info __P((u_char *, int, struct pcmcia_conf *));
+void pcmcia_getstr __P((char *buf, u_char **, u_char *));
+extern int   pcmcia_configure __P((struct device *, void *, void *));
+extern int   pcmcia_register __P((void *, struct pcmciabus_link *,
+                                 struct pcmcia_funcs *, int));
+extern int pcmcia_read_cis __P((struct pcmcia_link *, u_char *, int, int));
+extern int pcmcia_strcmp __P((const char *, const char *, int, const char *));
+extern int pcmcia_matchvalue __P((const struct pcmcia_cardinfo *,
+                                 struct pcmciadevs *));
+extern int pcmcia_bestvalue __P((struct pcmcia_cardinfo *,
+                                struct pcmciadevs *,
+                                int,
+                                struct pcmciadevs **));
+extern int pcmcia_slave_match __P((struct device *,
+                                  void *,
+                                  void *aux,
+                                  struct pcmciadevs *,
+                                  int));
+#endif /* _PCMCIA_PCMCIAVAR_H_ */
index 1e9ab0a..ab73c7d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: subr_autoconf.c,v 1.4 1996/04/21 22:27:13 deraadt Exp $       */
+/*     $OpenBSD: subr_autoconf.c,v 1.5 1996/04/29 14:17:45 hvozda Exp $        */
 /*     $NetBSD: subr_autoconf.c,v 1.21 1996/04/04 06:06:18 cgd Exp $   */
 
 /*
@@ -52,6 +52,9 @@
 #include <sys/malloc.h>
 #include <sys/systm.h>
 #include <machine/limits.h>
+/* Extra stuff from Matthias Drochner <drochner@zelux6.zel.kfa-juelich.de>
+ */
+#include <sys/queue.h>
 
 /*
  * Autoconfiguration subroutines.
@@ -75,6 +78,12 @@ struct matchinfo {
        int     indirect, pri;
 };
 
+struct cftable_head allcftables;
+
+static struct cftable staticcftable = {
+       cfdata
+};
+
 static char *number __P((char *, int));
 static void mapply __P((struct matchinfo *, struct cfdata *));
 
@@ -90,6 +99,8 @@ config_init()
 
        TAILQ_INIT(&alldevs);
        TAILQ_INIT(&allevents);
+       TAILQ_INIT(&allcftables);
+       TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list);
 }
 
 /*
@@ -150,6 +161,7 @@ config_search(fn, parent, aux)
        register struct cfdata *cf;
        register short *p;
        struct matchinfo m;
+       struct cftable *t;
 
        m.fn = fn;
        m.parent = parent;
@@ -157,16 +169,18 @@ config_search(fn, parent, aux)
        m.aux = aux;
        m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
        m.pri = 0;
-       for (cf = cfdata; cf->cf_driver; cf++) {
-               /*
-                * Skip cf if no longer eligible, otherwise scan through
-                * parents for one matching `parent', and try match function.
-                */
-               if (cf->cf_fstate == FSTATE_FOUND)
-                       continue;
-               for (p = cf->cf_parents; *p >= 0; p++)
-                       if (parent->dv_cfdata == &cfdata[*p])
-                               mapply(&m, cf);
+       for(t = allcftables.tqh_first; t; t = t->list.tqe_next){
+         for (cf = t->tab; cf->cf_driver; cf++) {
+           /*
+            * Skip cf if no longer eligible, otherwise scan through
+            * parents for one matching `parent', and try match function.
+            */
+           if (cf->cf_fstate == FSTATE_FOUND)
+             continue;
+           for (p = cf->cf_parents; *p >= 0; p++)
+             if (parent->dv_cfdata == &(t->tab)[*p])
+               mapply(&m, cf);
+         }
        }
        return (m.match);
 }
@@ -188,23 +202,26 @@ config_scan(fn, parent)
        register short *p;
        void *match;
        int indirect;
+       struct cftable *t;
 
        indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
-       for (cf = cfdata; cf->cf_driver; cf++) {
-               /*
-                * Skip cf if no longer eligible, otherwise scan through
-                * parents for one matching `parent', and try match function.
-                */
-               if (cf->cf_fstate == FSTATE_FOUND)
-                       continue;
-               for (p = cf->cf_parents; *p >= 0; p++)
-                       if (parent->dv_cfdata == &cfdata[*p]) {
-                               if (indirect)
-                                       match = config_make_softc(parent, cf);
-                               else
-                                       match = cf;
-                               (*fn)(parent, match);
-                       }
+       for (t = allcftables.tqh_first; t; t = t->list.tqe_next) {
+         for (cf = t->tab; cf->cf_driver; cf++) {
+           /*
+            * Skip cf if no longer eligible, otherwise scan through
+            * parents for one matching `parent', and try match function.
+            */
+           if (cf->cf_fstate == FSTATE_FOUND)
+             continue;
+           for (p = cf->cf_parents; *p >= 0; p++)
+             if (parent->dv_cfdata == &(t->tab)[*p]) {
+               if (indirect)
+                 match = config_make_softc(parent, cf);
+               else
+                 match = cf;
+               (*fn)(parent, match);
+             }
+         }
        }
 }
 
@@ -313,6 +330,7 @@ config_attach(parent, match, aux, print)
        register struct device *dev;
        register struct cfdriver *cd;
        register struct cfattach *ca;
+       struct cftable *t;
 
        if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {
                dev = match;
@@ -346,13 +364,15 @@ config_attach(parent, match, aux, print)
         * otherwise identical, or bump the unit number on all starred
         * cfdata for this device.
         */
-       for (cf = cfdata; cf->cf_driver; cf++)
-               if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit) {
+       for (t = allcftables.tqh_first; t; t = t->list.tqe_next) {
+               for (cf = t->tab; cf->cf_driver; cf++)
+           if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit) {
                        if (cf->cf_fstate == FSTATE_NOTFOUND)
                                cf->cf_fstate = FSTATE_FOUND;
                        if (cf->cf_fstate == FSTATE_STAR)
                                cf->cf_unit++;
-               }
+           }
+       }
        (*ca->ca_attach)(parent, dev, aux);
        return (dev);
 }
@@ -447,3 +467,185 @@ evcnt_attach(dev, name, ev)
        strcpy(ev->ev_name, name);
        TAILQ_INSERT_TAIL(&allevents, ev, ev_list);
 }
+
+typedef int (*cond_predicate_t) __P((struct device*, void*));
+
+static int haschild __P((struct device *));
+static int detach_devices __P((cond_predicate_t, void *,
+                              config_detach_callback_t, void *));
+
+static int
+haschild(dev)
+       struct device *dev;
+{
+       struct device *d;
+
+       for (d = alldevs.tqh_first;
+            d != NULL;
+            d = d->dv_list.tqe_next) {
+               if (d->dv_parent == dev)
+                       return(1);
+       }
+       return(0);
+}
+
+static int
+detach_devices(cond, condarg, callback, arg)
+       cond_predicate_t cond;
+       void *condarg;
+       config_detach_callback_t callback;
+       void *arg;
+{
+       struct device *d;
+       int alldone = 1;
+
+       /*
+        * XXX should use circleq and run around the list backwards
+        * to allow for predicates to match children.
+        */
+       d = alldevs.tqh_first;
+       while (d != NULL) {
+               if ((*cond)(d, condarg)) {
+                       struct cfdriver *drv = d->dv_cfdata->cf_driver;
+
+                       /* device not busy? */
+                       /* driver's detach routine decides, upper
+                          layer (eg bus dependent code) is notified
+                          via callback */
+#ifdef DEBUG
+                       printf("trying to detach device %s (%p)\n",
+                              d->dv_xname, d);
+#endif
+                       if (!haschild(d) &&
+                           d->dv_cfdata->cf_attach->ca_detach &&
+                           ((*(d->dv_cfdata->cf_attach->ca_detach))(d)) == 0) {
+                               int needit, i;
+                               struct device *help;
+
+                               if (callback)
+                                       (*callback)(d, arg);
+
+                               /* remove reference in driver's devicelist */
+                               if ((d->dv_unit >= drv->cd_ndevs) ||
+                                   (drv->cd_devs[d->dv_unit]!=d))
+                                       panic("bad unit in detach_devices");
+                               drv->cd_devs[d->dv_unit] = NULL;
+
+                               /* driver is not needed anymore? */
+                               needit = 0;
+                               for(i = 0; i<drv->cd_ndevs; i++)
+                                       if (drv->cd_devs[i])
+                                               needit = 1;
+
+                               if (!needit) {
+                                       /* free devices array (alloc'd
+                                           in config_make_softc) */
+                                       free(drv->cd_devs, M_DEVBUF);
+                                       drv->cd_ndevs = 0;
+                               }
+
+                               /* remove entry in global device list */
+                               help = d->dv_list.tqe_next;
+                               TAILQ_REMOVE(&alldevs, d, dv_list);
+#ifdef DEBUG
+                               printf("%s removed\n", d->dv_xname);
+#endif
+                               d->dv_cfdata->cf_fstate = FSTATE_NOTFOUND;
+                               /* free memory for dev data (alloc'd
+                                   in config_make_softc) */
+                               free(d, M_DEVBUF);
+                               d = help;
+                               continue;
+                       } else
+                               alldone = 0;
+               }
+               d = d->dv_list.tqe_next;
+       }
+       return(!alldone);
+}
+
+int dev_matches_cfdata __P((struct device *dev, void *));
+
+int
+dev_matches_cfdata(dev, arg)
+       struct device *dev;
+       void *arg;
+{
+       struct cfdata *cfdata = arg;
+       return(/* device uses same driver ? */
+               (dev->dv_cfdata->cf_driver == cfdata->cf_driver)
+               /* device instance described by this cfdata? */
+               && ((cfdata->cf_fstate == FSTATE_STAR)
+                   || ((cfdata->cf_fstate == FSTATE_FOUND)
+                       && (dev->dv_unit == cfdata->cf_unit)))
+               );
+}
+
+int
+config_detach(cf, callback, arg)
+       struct cfdata *cf;
+       config_detach_callback_t callback;
+       void *arg;
+{
+       return(detach_devices(dev_matches_cfdata, cf, callback, arg));
+}
+
+int
+attach_loadable(parentname, parentunit, cftable)
+       char *parentname;
+       int parentunit;
+       struct cftable *cftable;
+{
+       int found = 0;
+       struct device *d;
+
+       TAILQ_INSERT_TAIL(&allcftables, cftable, list);
+
+       for(d = alldevs.tqh_first;
+           d != NULL;
+           d = d->dv_list.tqe_next) {
+               struct cfdriver *drv = d->dv_cfdata->cf_driver;
+
+               if ((!strcmp(parentname, drv->cd_name))
+                   && ((parentunit == -1) || (parentunit == d->dv_unit))) {
+                       int s;
+
+                       s = splhigh(); /* ??? */
+                       found |= (*d->dv_cfdata->cf_attach->ca_reprobe)(d, &(cftable->tab[0]));
+                       splx(s);
+               }
+       }
+
+       if (!found)
+               TAILQ_REMOVE(&allcftables, cftable, list);
+
+       return(found);
+}
+
+static int
+devcf_intable __P((struct device *, void *));
+
+static int
+devcf_intable(dev, arg)
+       struct device *dev;
+       void *arg;
+{
+       struct cftable *tbl = arg;
+       struct cfdata *cf;
+
+       for(cf = tbl->tab; cf->cf_driver; cf++) {
+               if (dev->dv_cfdata == cf)
+                       return(1);
+       }
+       return(0);
+}
+
+int
+detach_loadable(cftable)
+       struct cftable *cftable;
+{
+       if (!detach_devices(devcf_intable, cftable, 0, 0))
+               return(0);
+       TAILQ_REMOVE(&allcftables, cftable, list);
+       return(1);
+}
index 99208f4..37df553 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: device.h,v 1.4 1996/04/21 22:31:38 deraadt Exp $      */
+/*     $OpenBSD: device.h,v 1.5 1996/04/29 14:17:53 hvozda Exp $       */
 /*     $NetBSD: device.h,v 1.15 1996/04/09 20:55:24 cgd Exp $  */
 
 /*
@@ -122,7 +122,8 @@ struct cfattach {
        size_t    ca_devsize;           /* size of dev data (for malloc) */
        cfmatch_t ca_match;             /* returns a match level */
        void    (*ca_attach) __P((struct device *, struct device *, void *));
-       /* XXX should have detach */
+       int     (*ca_detach) __P((struct device*));
+       int     (*ca_reprobe) __P((struct device*, struct cfdata*));
 };
 
 struct cfdriver {
@@ -153,6 +154,11 @@ struct pdevinit {
 };
 
 #ifdef _KERNEL
+struct cftable {
+       struct cfdata *tab;
+       TAILQ_ENTRY(cftable) list;
+};
+TAILQ_HEAD(cftable_head, cftable);
 
 extern struct devicelist alldevs;      /* list of all devices */
 extern struct evcntlist allevents;     /* list of all event counters */
@@ -169,6 +175,12 @@ void evcnt_attach __P((struct device *, const char *, struct evcnt *));
 
 /* compatibility definitions */
 #define config_found(d, a, p)  config_found_sm((d), (a), (p), NULL)
+extern int attach_loadable __P((char *, int, struct cftable *));
+extern int detach_loadable __P((struct cftable *));
+typedef void (*config_detach_callback_t) __P((struct device *, void *));
+extern int config_detach __P((struct cfdata *, config_detach_callback_t,
+                             void *));
+
 #endif /* _KERNEL */
 
 #endif /* !_SYS_DEVICE_H_ */