summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorhvozda <hvozda@cvs.openbsd.org>1996-04-29 14:17:54 +0000
committerhvozda <hvozda@cvs.openbsd.org>1996-04-29 14:17:54 +0000
commit7a9ddc83f934914d39af72bf24b67290a9e5700f (patch)
treed4e40de8eec73b77be31c346455984224213ff31 /sys
parentfdecada6f88b495c1afc81ad3a15c0cedffa2338 (diff)
Pull in John Kohl's [jtk@netbsd.org] most recent (15Apr96) APM and PCMCIA work
(original PCMCIA framework by Stefan Grefen [grefen@convex.com]).
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/i386/apm_init/Makefile56
-rw-r--r--sys/arch/i386/apm_init/Makefile.inc39
-rw-r--r--sys/arch/i386/apm_init/apm_bios.h185
-rw-r--r--sys/arch/i386/apm_init/apm_init.S215
-rw-r--r--sys/arch/i386/apm_init/apm_segments.h30
-rw-r--r--sys/arch/i386/apm_init/apm_setup.h24
-rw-r--r--sys/arch/i386/apm_init/bin2asm.sh21
-rw-r--r--sys/arch/i386/apm_init/real_prot.S186
-rw-r--r--sys/arch/i386/apm_init/real_prot.h57
-rw-r--r--sys/arch/i386/apm_init/rmaouthdr6
-rw-r--r--sys/arch/i386/apm_init/table.c25
-rw-r--r--sys/arch/i386/conf/HELIOS_PCMCIA39
-rw-r--r--sys/arch/i386/conf/Makefile.i3868
-rw-r--r--sys/arch/i386/conf/PCMCIA138
-rw-r--r--sys/arch/i386/conf/files.i38625
-rw-r--r--sys/arch/i386/i386/apm.c844
-rw-r--r--sys/arch/i386/i386/conf.c17
-rw-r--r--sys/arch/i386/i386/gdt.c12
-rw-r--r--sys/arch/i386/i386/genassym.c20
-rw-r--r--sys/arch/i386/i386/locore.s196
-rw-r--r--sys/arch/i386/i386/machdep.c28
-rw-r--r--sys/arch/i386/i386/mainbus.c17
-rw-r--r--sys/arch/i386/include/apmvar.h263
-rw-r--r--sys/arch/i386/include/gdt.h5
-rw-r--r--sys/arch/i386/include/segments.h5
-rw-r--r--sys/dev/ic/com.c312
-rw-r--r--sys/dev/ic/i82365reg.h29
-rw-r--r--sys/dev/isa/com.c312
-rw-r--r--sys/dev/isa/files.isa47
-rw-r--r--sys/dev/isa/if_ed.c119
-rw-r--r--sys/dev/isa/if_ep.c123
-rw-r--r--sys/dev/isa/pcmcia_isa.c107
-rw-r--r--sys/dev/isa/pcmcia_pcic.c553
-rw-r--r--sys/dev/isa/wd.c25
-rw-r--r--sys/dev/pcmcia/files.pcmcia17
-rw-r--r--sys/dev/pcmcia/pcmcia.c904
-rw-r--r--sys/dev/pcmcia/pcmcia_conf.c190
-rw-r--r--sys/dev/pcmcia/pcmcia_ioctl.h6
-rw-r--r--sys/dev/pcmcia/pcmciareg.h136
-rw-r--r--sys/dev/pcmcia/pcmciavar.h (renamed from sys/dev/pcmcia/pcmciabus.h)113
-rw-r--r--sys/kern/subr_autoconf.c260
-rw-r--r--sys/sys/device.h16
42 files changed, 4808 insertions, 922 deletions
diff --git a/sys/arch/i386/apm_init/Makefile b/sys/arch/i386/apm_init/Makefile
new file mode 100644
index 00000000000..44e521eba13
--- /dev/null
+++ b/sys/arch/i386/apm_init/Makefile
@@ -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
index 00000000000..715da6093c5
--- /dev/null
+++ b/sys/arch/i386/apm_init/Makefile.inc
@@ -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
index 00000000000..5354b9ccfb7
--- /dev/null
+++ b/sys/arch/i386/apm_init/apm_bios.h
@@ -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
index 00000000000..945c251446a
--- /dev/null
+++ b/sys/arch/i386/apm_init/apm_init.S
@@ -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
index 00000000000..5e5fcdbe7e4
--- /dev/null
+++ b/sys/arch/i386/apm_init/apm_segments.h
@@ -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
index 00000000000..fdc380e50be
--- /dev/null
+++ b/sys/arch/i386/apm_init/apm_setup.h
@@ -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
index 00000000000..6694b49d9b5
--- /dev/null
+++ b/sys/arch/i386/apm_init/bin2asm.sh
@@ -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
index 00000000000..5f9e97ecf68
--- /dev/null
+++ b/sys/arch/i386/apm_init/real_prot.S
@@ -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
index 00000000000..51e91cf05d9
--- /dev/null
+++ b/sys/arch/i386/apm_init/real_prot.h
@@ -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
index 00000000000..608715015fe
--- /dev/null
+++ b/sys/arch/i386/apm_init/rmaouthdr
@@ -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
index 00000000000..d3cc1d98670
--- /dev/null
+++ b/sys/arch/i386/apm_init/table.c
@@ -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 };
diff --git a/sys/arch/i386/conf/HELIOS_PCMCIA b/sys/arch/i386/conf/HELIOS_PCMCIA
index b412cdfb0ad..2b91d0e76f8 100644
--- a/sys/arch/i386/conf/HELIOS_PCMCIA
+++ b/sys/arch/i386/conf/HELIOS_PCMCIA
@@ -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
diff --git a/sys/arch/i386/conf/Makefile.i386 b/sys/arch/i386/conf/Makefile.i386
index aee08091430..0edf4047ae1 100644
--- a/sys/arch/i386/conf/Makefile.i386
+++ b/sys/arch/i386/conf/Makefile.i386
@@ -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
index 00000000000..2544e06c62c
--- /dev/null
+++ b/sys/arch/i386/conf/PCMCIA
@@ -0,0 +1,138 @@
+# $Id: PCMCIA,v 1.1 1996/04/29 14:12:24 hvozda Exp $
+# $Source: /cvs/OpenBSD/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
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index c434f132f04..2bd8ee7cb59 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -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
@@ -69,6 +70,12 @@ 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
index 00000000000..03483c7a868
--- /dev/null
+++ b/sys/arch/i386/i386/apm.c
@@ -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 */
diff --git a/sys/arch/i386/i386/conf.c b/sys/arch/i386/i386/conf.c
index c56ad7712fd..9b68b21902b 100644
--- a/sys/arch/i386/i386/conf.c
+++ b/sys/arch/i386/i386/conf.c
@@ -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 */
diff --git a/sys/arch/i386/i386/gdt.c b/sys/arch/i386/i386/gdt.c
index a511ab550b7..37361fba4a2 100644
--- a/sys/arch/i386/i386/gdt.c
+++ b/sys/arch/i386/i386/gdt.c
@@ -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)
diff --git a/sys/arch/i386/i386/genassym.c b/sys/arch/i386/i386/genassym.c
index d3e01c4094d..8bba187b0d9 100644
--- a/sys/arch/i386/i386/genassym.c
+++ b/sys/arch/i386/i386/genassym.c
@@ -51,6 +51,11 @@
#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);
}
diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s
index e7af2889ce0..65f33efa92e 100644
--- a/sys/arch/i386/i386/locore.s
+++ b/sys/arch/i386/i386/locore.s
@@ -41,6 +41,7 @@
#include "npx.h"
#include "assym.h"
+#include "apm.h"
#include <sys/errno.h>
#include <sys/syscall.h>
@@ -142,6 +143,16 @@
.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 */
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index e3bdb4ad24b..27438f0608e 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -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 $ */
/*-
@@ -93,6 +93,12 @@
#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)
diff --git a/sys/arch/i386/i386/mainbus.c b/sys/arch/i386/i386/mainbus.c
index 5de4b476180..c20a774c307 100644
--- a/sys/arch/i386/i386/mainbus.c
+++ b/sys/arch/i386/i386/mainbus.c
@@ -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 $ */
/*
@@ -45,6 +45,11 @@
#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
index 00000000000..75dfd2c155d
--- /dev/null
+++ b/sys/arch/i386/include/apmvar.h
@@ -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__ */
diff --git a/sys/arch/i386/include/gdt.h b/sys/arch/i386/include/gdt.h
index ebb8d5b0d57..7b7a6ea5ac5 100644
--- a/sys/arch/i386/include/gdt.h
+++ b/sys/arch/i386/include/gdt.h
@@ -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));
diff --git a/sys/arch/i386/include/segments.h b/sys/arch/i386/include/segments.h
index a1a332e23f3..4558ccce6aa 100644
--- a/sys/arch/i386/include/segments.h
+++ b/sys/arch/i386/include/segments.h
@@ -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)
diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c
index 77dd24748f4..5570f7ef424 100644
--- a/sys/dev/ic/com.c
+++ b/sys/dev/ic/com.c
@@ -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;
@@ -1042,6 +1257,18 @@ comparam(tp, t)
}
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))
diff --git a/sys/dev/ic/i82365reg.h b/sys/dev/ic/i82365reg.h
index fb05f10c0c2..1f0a8f77858 100644
--- a/sys/dev/ic/i82365reg.h
+++ b/sys/dev/ic/i82365reg.h
@@ -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 */
@@ -107,6 +108,8 @@
#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 */
@@ -128,7 +131,7 @@
/* 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
@@ -136,12 +139,20 @@
#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 */
@@ -194,7 +205,7 @@
/* 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__
diff --git a/sys/dev/isa/com.c b/sys/dev/isa/com.c
index 77dd24748f4..5570f7ef424 100644
--- a/sys/dev/isa/com.c
+++ b/sys/dev/isa/com.c
@@ -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;
@@ -1042,6 +1257,18 @@ comparam(tp, t)
}
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))
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa
index f145e7b4d30..6303824ce85 100644
--- a/sys/dev/isa/files.isa
+++ b/sys/dev/isa/files.isa
@@ -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
diff --git a/sys/dev/isa/if_ed.c b/sys/dev/isa/if_ed.c
index d770c80a73e..8f2499c9d18 100644
--- a/sys/dev/isa/if_ed.c
+++ b/sys/dev/isa/if_ed.c
@@ -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;
diff --git a/sys/dev/isa/if_ep.c b/sys/dev/isa/if_ep.c
index 4102ad294e4..f9eab4b8368 100644
--- a/sys/dev/isa/if_ep.c
+++ b/sys/dev/isa/if_ep.c
@@ -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();
diff --git a/sys/dev/isa/pcmcia_isa.c b/sys/dev/isa/pcmcia_isa.c
index d2fd46ee66f..5a485ca8b7a 100644
--- a/sys/dev/isa/pcmcia_isa.c
+++ b/sys/dev/isa/pcmcia_isa.c
@@ -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 */
@@ -36,9 +37,10 @@
#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>
@@ -49,14 +51,20 @@
#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;
diff --git a/sys/dev/isa/pcmcia_pcic.c b/sys/dev/isa/pcmcia_pcic.c
index 8e8f16f1594..dfcf2ea4a81 100644
--- a/sys/dev/isa/pcmcia_pcic.c
+++ b/sys/dev/isa/pcmcia_pcic.c
@@ -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
*
@@ -20,13 +49,16 @@
#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
@@ -36,13 +68,13 @@
#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;
+}
diff --git a/sys/dev/isa/wd.c b/sys/dev/isa/wd.c
index 76267053725..293048e8981 100644
--- a/sys/dev/isa/wd.c
+++ b/sys/dev/isa/wd.c
@@ -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:
diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia
index 3429486e007..a32bef3b0e6 100644
--- a/sys/dev/pcmcia/files.pcmcia
+++ b/sys/dev/pcmcia/files.pcmcia
@@ -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
diff --git a/sys/dev/pcmcia/pcmcia.c b/sys/dev/pcmcia/pcmcia.c
index 7729774be59..f37de3ef3a4 100644
--- a/sys/dev/pcmcia/pcmcia.c
+++ b/sys/dev/pcmcia/pcmcia.c
@@ -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
@@ -27,9 +29,14 @@
* (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>
@@ -39,15 +46,13 @@
#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
@@ -57,107 +62,57 @@
# 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));
+}
diff --git a/sys/dev/pcmcia/pcmcia_conf.c b/sys/dev/pcmcia/pcmcia_conf.c
index ab0e5b0d741..3e09e0368bc 100644
--- a/sys/dev/pcmcia/pcmcia_conf.c
+++ b/sys/dev/pcmcia/pcmcia_conf.c
@@ -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;
+}
diff --git a/sys/dev/pcmcia/pcmcia_ioctl.h b/sys/dev/pcmcia/pcmcia_ioctl.h
index 535e12241b7..dd8b9e6174e 100644
--- a/sys/dev/pcmcia/pcmcia_ioctl.h
+++ b/sys/dev/pcmcia/pcmcia_ioctl.h
@@ -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/pcmciareg.h b/sys/dev/pcmcia/pcmciareg.h
new file mode 100644
index 00000000000..f3f4446c37d
--- /dev/null
+++ b/sys/dev/pcmcia/pcmciareg.h
@@ -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/pcmciabus.h b/sys/dev/pcmcia/pcmciavar.h
index 4dceb987690..2e4f597b703 100644
--- a/sys/dev/pcmcia/pcmciabus.h
+++ b/sys/dev/pcmcia/pcmciavar.h
@@ -1,4 +1,6 @@
+/* $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
@@ -26,16 +28,16 @@
* (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
+#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
@@ -80,11 +82,11 @@ 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));
+ 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));
-/*26 power on/off etc */
+/*16 power on/off etc */
int (*pcmcia_service) __P((struct pcmcia_link *, int, void *, int));
};
@@ -94,22 +96,41 @@ struct pcmciabus_link { /* Link back to the bus we are on */
struct pcmcia_conf *, struct cfdata *));
/* Bus specific unconfigure */
int (*bus_unconfig) __P((struct pcmcia_link *));
- /* Bus specific probe */
+ /* Bus specific probe */
int (*bus_probe) __P((struct device *, void *,
- void *, struct pcmcia_link *));
+ 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 */
@@ -151,9 +172,9 @@ struct pcmcia_adapter {
* as well.
*/
struct pcmcia_link {
- char pcmciabus; /* the Nth pcmciabus */
- char slot; /* slot of this dev */
- char flags;
+ 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
@@ -161,17 +182,17 @@ struct pcmcia_link {
#define PCMCIA_ATTACH_TYPE (PCMCIA_ATTACH|PCMCIA_REATTACH)
#define PCMCIA_SLOT_EVENT 0x80
#define PCMCIA_SLOT_OPEN 0x40
- char opennings;
+ u_char opennings;
- char iowin;
- char memwin;
- char intr;
- char dummy;
+ 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. */
- void *devp; /* pointer to configured device */
+ struct pcmciabus_softc *bus; /* parent pcmcia bus */
+ struct device *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 */
};
@@ -184,7 +205,9 @@ struct pcmcia_link {
*/
struct pcmciabus_softc {
struct device sc_dev;
- struct pcmcia_link *sc_link[8];
+ 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 {
@@ -233,6 +256,15 @@ struct pcmcia_device {
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) */
@@ -245,6 +277,24 @@ struct pcmciadevs {
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,
@@ -255,8 +305,23 @@ extern int pcmcia_targmatch __P((struct device *, struct cfdata *, void *));
/* 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_ */
+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_ */
diff --git a/sys/kern/subr_autoconf.c b/sys/kern/subr_autoconf.c
index 1e9ab0ae6ba..ab73c7d2416 100644
--- a/sys/kern/subr_autoconf.c
+++ b/sys/kern/subr_autoconf.c
@@ -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);
+}
diff --git a/sys/sys/device.h b/sys/sys/device.h
index 99208f4ac03..37df553bc2a 100644
--- a/sys/sys/device.h
+++ b/sys/sys/device.h
@@ -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_ */