diff options
author | hvozda <hvozda@cvs.openbsd.org> | 1996-04-29 13:09:12 +0000 |
---|---|---|
committer | hvozda <hvozda@cvs.openbsd.org> | 1996-04-29 13:09:12 +0000 |
commit | fdecada6f88b495c1afc81ad3a15c0cedffa2338 (patch) | |
tree | cd585c73f87e814d831d52c48087f539fe1fed93 /usr.sbin | |
parent | 66dbdef25563581a0d393d8d919df22c43de70c7 (diff) |
Pull in John Kohl's most recent (15Apr96) APM and PCMCIA work
(original PCMCIA framework by Stefan Grefen).
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/apm/Makefile | 15 | ||||
-rw-r--r-- | usr.sbin/apm/apm.8 | 114 | ||||
-rw-r--r-- | usr.sbin/apm/apm.c | 283 | ||||
-rw-r--r-- | usr.sbin/apmd/Makefile | 11 | ||||
-rw-r--r-- | usr.sbin/apmd/apm-proto.h | 57 | ||||
-rw-r--r-- | usr.sbin/apmd/apmd.8 | 175 | ||||
-rw-r--r-- | usr.sbin/apmd/apmd.c | 471 | ||||
-rw-r--r-- | usr.sbin/apmd/apmsubr.c | 79 | ||||
-rw-r--r-- | usr.sbin/apmd/pathnames.h | 37 | ||||
-rw-r--r-- | usr.sbin/pcmciad/Makefile | 20 | ||||
-rw-r--r-- | usr.sbin/pcmciad/README.dump-progs | 11 | ||||
-rw-r--r-- | usr.sbin/pcmciad/dumpcor/Makefile | 10 | ||||
-rw-r--r-- | usr.sbin/pcmciad/dumpcor/dumpcor.c | 70 | ||||
-rw-r--r-- | usr.sbin/pcmciad/dumpinfo/Makefile | 11 | ||||
-rw-r--r-- | usr.sbin/pcmciad/dumpinfo/dumpinfo.c | 659 | ||||
-rw-r--r-- | usr.sbin/pcmciad/dumpreg/Makefile | 10 | ||||
-rw-r--r-- | usr.sbin/pcmciad/dumpreg/dumpreg.c | 143 | ||||
-rw-r--r-- | usr.sbin/pcmciad/pathnames.h | 32 | ||||
-rw-r--r-- | usr.sbin/pcmciad/pcmciad.8 | 76 | ||||
-rw-r--r-- | usr.sbin/pcmciad/pcmciad.c | 459 | ||||
-rw-r--r-- | usr.sbin/pcmciad/test.config | 2 |
22 files changed, 2748 insertions, 3 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index c85fd5d0a21..2a4138e183b 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,14 +1,14 @@ # from: @(#)Makefile 5.6.1.2 (Berkeley) 5/8/91 -# $Id: Makefile,v 1.8 1996/04/18 21:32:46 deraadt Exp $ +# $Id: Makefile,v 1.9 1996/04/29 13:08:37 hvozda Exp $ # not yet done: catman -SUBDIR= ac accton arp bootpd bootpgw bootpef bootptest \ +SUBDIR= ac accton arp apm apmd bootpd bootpgw bootpef bootptest \ chown chroot config cron dev_mkdb \ diskpart edquota gettable gspa htable inetd iostat \ ipftest ipmon ipsend kgmon \ kvm_mkdb lpr map-mbone mrinfo mrouted mtrace mtree named \ - netgroup_mkdb portmap pppd pstat pwd_mkdb quot quotaon \ + netgroup_mkdb pcmciad portmap pppd pstat pwd_mkdb quot quotaon \ rarpd rbootd rdconfig rdate repquota rmt \ rpc.bootparamd rpc.pcnfsd rwhod \ sa sendmail sliplogin slstats spray sysctl \ diff --git a/usr.sbin/apm/Makefile b/usr.sbin/apm/Makefile new file mode 100644 index 00000000000..6ce957a7f89 --- /dev/null +++ b/usr.sbin/apm/Makefile @@ -0,0 +1,15 @@ +# $Id: Makefile,v 1.1 1996/04/29 13:08:39 hvozda Exp $ + +SRCS= apm.c apmsubr.c +#LDADD+= -lutil + +.PATH: ${.CURDIR}/../apmd + +CFLAGS+= -g -O2 -Wmissing-prototypes -Wall -I${.CURDIR}/../apmd +PROG= apm +MAN= apm.8 +MLINKS= apm.8 zzz.8 +LINKS= ${BINDIR}/apm ${BINDIR}/zzz + +.include <bsd.prog.mk> +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/usr.sbin/apm/apm.8 b/usr.sbin/apm/apm.8 new file mode 100644 index 00000000000..e3f71882893 --- /dev/null +++ b/usr.sbin/apm/apm.8 @@ -0,0 +1,114 @@ +.\" Copyright (c) 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. +.\" +.\" $Id: apm.8,v 1.1 1996/04/29 13:08:40 hvozda Exp $ +.\" +.Dd March 18, 1996 +.Dt APM 8 +.Os OpenBSD +.Sh NAME +.Nm apm +.Nd Advanced Power Management control program +.Sh SYNOPSIS +.Nm zzz +.Op Fl S +.Op Fl z +.Op Fl f Ar sockname +.Br +.Nm apm +.Op Fl z +.Op Fl S +.Op Fl s +.Op Fl l +.Op Fl b +.Op Fl a +.Op Fl v +.Op Fl f Ar sockname +.Sh DESCRIPTION +.Nm +communicates with the Advanced Power Management daemon, +.Xr apmd 8 , +making requests of it for current power status or to place the system +int a suspend or stand-by state. +With no flags, +.Nm +displays the current power management state in verbose form. +.Pp +Available command-line flags are: +.Bl -tag -width indent -compact +.It Fl z +Put the system into suspend (deep sleep) mode. +.It Fl S +Put the system into stand-by (light sleep) mode. +.It Fl l +Display the estimated battery lifetime (in percent). +.It Fl b +Display the battery status. 0 means high, 1 means low, 2 means +critical, 3 means charging, 4 means absent, and 255 means unknown. +.It Fl a +Display the external charger (A/C status). 0 means disconnected, 1 +means connected, 2 means backup power source, and 255 means unknown. +.It Fl v +Request more verbose description of the displayed states. +.It Fl f Ar sockname +Set the name of the socket via which to contact +.Xr apmd 8 +to +.Pa sockname . +.El +.Pp +The +.Nm zzz +variant on this command is an alternative for suspending the system. +With no arguments, +.Nm +places the system into suspend mode. +The command line flags serve the same purpose as for the +.Nm apm +variant of this command. +.Pp +This command does not wait for positive confirmation that the requested +mode has been entered; to do so would mean the command does not return +until the system resumes from its sleep state. +.Sh FILES +.Pa /var/run/apmdev +is the default UNIX-domain socket used for communication with +.Xr apm 8 . +The +.Fl f +flag may be used to specify an alternate socket name. +The protection modes on this socket govern which users may access the +APM functions. +.Sh SEE ALSO +.Xr apmd 8 , +.Xr apm 4 . +.Sh REFERENCES +Advanced Power Management (APM) BIOS Interface Specification (revision +1.1), Intel Corporation and Microsoft Corporation +.Sh HISTORY +The +.Nm apm +command appeared in OpenBSD 1.1B. diff --git a/usr.sbin/apm/apm.c b/usr.sbin/apm/apm.c new file mode 100644 index 00000000000..12c8deffe61 --- /dev/null +++ b/usr.sbin/apm/apm.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 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. + * + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <err.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/ioctl.h> +#include <machine/apmvar.h> +#include "pathnames.h" +#include "apm-proto.h" + +#define FALSE 0 +#define TRUE 1 + +extern char *__progname; +extern char *optarg; +extern int optind; +extern int optopt; +extern int opterr; +extern int optreset; + +void usage(void); +void zzusage(void); +int do_zzz(const char *pn, enum apm_action action); +int open_socket(const char *pn); +int send_command(int fd, + struct apm_command *cmd, + struct apm_reply *reply); + +void +usage(void) +{ + fprintf(stderr,"usage: %s [-v] [-z | -S] [-slba] [-f socket]\n", + __progname); + exit(1); +} + +void +zzusage(void) +{ + fprintf(stderr,"usage: %s [-z | -S] [-f socket]\n", + __progname); + exit(1); +} + +int +send_command(int fd, + struct apm_command *cmd, + struct apm_reply *reply) +{ + /* send a command to the apm daemon */ + cmd->vno = APMD_VNO; + + if (send(fd, cmd, sizeof(*cmd), 0) == sizeof(*cmd)) { + if (recv(fd, reply, sizeof(*reply), 0) != sizeof(*reply)) { + warn("invalid reply from APM daemon\n"); + return 1; + } + } else { + warn("invalid send to APM daemon"); + return 1; + } + return 0; +} + +int +do_zzz(const char *pn, enum apm_action action) +{ + struct apm_command command; + struct apm_reply reply; + int fd; + + switch (action) { + case NONE: + case SUSPEND: + command.action = SUSPEND; + break; + case STANDBY: + command.action = STANDBY; + break; + default: + zzusage(); + } + fd = open_socket(pn); + + if (fd == -1) + err(1, "cannot open connection to APM daemon"); + printf("Suspending system...\n"); + exit(send_command(fd, &command, &reply)); +} + +int +open_socket(const char *sockname) +{ + int sock, errr; + struct sockaddr_un s_un; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock == -1) + err(1, "cannot create local socket"); + + s_un.sun_family = AF_UNIX; + strncpy(s_un.sun_path, sockname, sizeof(s_un.sun_path)); + s_un.sun_len = SUN_LEN(&s_un); + if (connect(sock, (struct sockaddr *)&s_un, s_un.sun_len) == -1) { + errr = errno; + close(sock); + errno = errr; + return -1; + } + return sock; +} + +void +main(int argc, char *argv[]) +{ + char *sockname = _PATH_APM_SOCKET; + int ch; + int dostatus = FALSE; + int doac = FALSE; + int dopct = FALSE; + int dobstate = FALSE; + int fd; + int rval; + int verbose = FALSE; + enum apm_action action = NONE; + struct apm_command command; + struct apm_reply reply; + + while ((ch = getopt(argc, argv, "lbvadsSzf:")) != -1) + switch(ch) { + case 'v': + verbose = TRUE; + break; + case 'f': + sockname = optarg; + break; + case 'z': + if (action != NONE) + usage(); + action = SUSPEND; + break; + case 'S': + if (action != NONE) + usage(); + action = STANDBY; + break; + case 's': + if (action != NONE && action != GETSTATUS) + usage(); + dostatus = TRUE; + action = GETSTATUS; + break; + case 'b': + if (action != NONE && action != GETSTATUS) + usage(); + dobstate = TRUE; + action = GETSTATUS; + break; + case 'l': + if (action != NONE && action != GETSTATUS) + usage(); + dopct = TRUE; + action = GETSTATUS; + break; + case 'a': + if (action != NONE && action != GETSTATUS) + usage(); + doac = TRUE; + action = GETSTATUS; + break; + case '?': + default: + usage(); + } + + if (!strcmp(__progname, "zzz")) { + exit(do_zzz(sockname, action)); + } + + fd = open_socket(sockname); + + switch (action) { + case NONE: + verbose = doac = dopct = dobstate = dostatus = TRUE; + action = GETSTATUS; + /* fallthrough */ + case GETSTATUS: + if (fd == -1) { + /* open the device directly and get status */ + fd = open(_PATH_APM_NORMAL, O_RDONLY); + if (fd == -1) { + err(1, "cannot contact APM daemon and cannot open " _PATH_APM_NORMAL); + } + if (ioctl(fd, APM_IOC_GETPOWER, &reply.batterystate) == 0) + goto printval; + } + case SUSPEND: + case STANDBY: + command.action = action; + break; + default: + usage(); + } + + if ((rval = send_command(fd, &command, &reply)) == 0) { + switch (action) { + case GETSTATUS: + printval: + if (verbose) { + if (dobstate) + printf("Battery charge state: %s\n", + battstate(reply.batterystate.battery_state)); + if (dopct) + printf("Battery remaining: %d percent\n", + reply.batterystate.battery_life); + if (doac) + printf("A/C adapter state: %s\n", ac_state(reply.batterystate.ac_state)); + if (dostatus) + printf("Power management enabled\n"); + } else { + if (dobstate) + printf("%d\n", reply.batterystate.battery_state); + if (dopct) + printf("%d\n", reply.batterystate.battery_life); + if (doac) + printf("%d\n", reply.batterystate.ac_state); + if (dostatus) + printf("1\n"); + } + break; + default: + break; + } + switch (reply.newstate) { + case SUSPEND: + printf("System will enter suspend mode momentarily.\n"); + break; + case STANDBY: + printf("System will enter standby mode momentarily.\n"); + break; + default: + break; + } + } else + errx(rval, "cannot get reply from APM daemon\n"); + + exit(0); +} diff --git a/usr.sbin/apmd/Makefile b/usr.sbin/apmd/Makefile new file mode 100644 index 00000000000..7b8f69640c6 --- /dev/null +++ b/usr.sbin/apmd/Makefile @@ -0,0 +1,11 @@ +# $Id: Makefile,v 1.1 1996/04/29 13:08:42 hvozda Exp $ + +SRCS= apmd.c apmsubr.c +#LDADD+= -lutil + +CFLAGS+= -g -O2 -Wmissing-prototypes -Wall +PROG= apmd +MAN= apmd.8 + +.include <bsd.prog.mk> +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/usr.sbin/apmd/apm-proto.h b/usr.sbin/apmd/apm-proto.h new file mode 100644 index 00000000000..818b2f2c8d8 --- /dev/null +++ b/usr.sbin/apmd/apm-proto.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 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. + * + */ + +enum apm_action { + NONE, + SUSPEND, + STANDBY, + GETSTATUS +}; + +enum apm_state { + NORMAL, + SUSPENDING, + STANDING_BY +}; + +struct apm_command { + int vno; + enum apm_action action; +}; + +struct apm_reply { + int vno; + enum apm_state newstate; + struct apm_power_info batterystate; +}; + +#define APMD_VNO 1 + +extern const char *battstate __P((int state)); +extern const char *ac_state __P((int state)); diff --git a/usr.sbin/apmd/apmd.8 b/usr.sbin/apmd/apmd.8 new file mode 100644 index 00000000000..2e77d13f87c --- /dev/null +++ b/usr.sbin/apmd/apmd.8 @@ -0,0 +1,175 @@ +.\" 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. +.\" +.\" $Id: apmd.8,v 1.1 1996/04/29 13:08:45 hvozda Exp $ +.\" +.Dd March 24, 1996 +.Dt APMD 8 +.Os OpenBSD +.Sh NAME +.Nm apmd +.Nd Advanced Power Management monitor daemon +.Sh SYNOPSIS +.Nm +.Op Fl d +.Op Fl s +.Op Fl a +.Op Fl q +.Op Fl t Ar seconds +.Op Fl S Ar sockname +.Op Fl f Ar devname +.Sh DESCRIPTION +.Nm +monitors the advanced power management (APM) pseudo-device, acting on +signaled events and upon user requests as sent by the +.Xr apm 8 +program. +For suspend and standby request events delivered by the BIOS, or via +.Xr apm 8 , +.Nm +runs the appropriate configuration program (if one exists), +syncs the buffer cache to disk and initiates the requested mode. +When resuming after suspend or standby, +.Nm +runs the appropriate configuration program (if one exists). +For power status change events, +.Nm +fetches the current status and reports it via +.Xr syslog 3 +with logging facility +.Dv LOG_DAEMON . +.Pp +.Nm +announces the transition to standby mode with a single high tone on the +speaker (using the +.Pa /dev/speaker +device). +Suspends are announced with two high tones. +.Pp +.Nm +periodically polls the APM driver for the current power state. +If the battery charge level changes substantially or the external power +status changes, the new status is logged. The polling rate defaults to +once per 10 minutes, but may be specified using the +.Fl t +command-line flag. +.Pp +If the +.Fl s +flag is specified, the current battery statistics are reported via +.Xr syslog 3 +and +.Nm +exits without monitoring the APM status. +.Pp +If the +.Fl a +flag is specified, any BIOS-initiated suspend or standby requests are +ignored if the system is connected to line current and not running from +batteries (user requests are still honored). +.Pp +If the +.Fl d +flag is specified, +.Nm +enters debug mode, logging to facility +.Dv LOG_LOCAL1 +and staying in the foreground on the controlling terminal. +.Pp +If the +.Fl q +flag is specified, +.Nm +does not announce suspend and standby requests on the speaker. +.Pp +When a client requests a suspend or stand-by mode, +.Nm +does not wait for positive confirmation that the requested +mode has been entered before replying to the client; to do so would mean +the client does not get a reply until the system resumes from its sleep state. +Rather, +.Nm +replies with the intended state to the client and then places the system +in the requested mode after running the configuration script and +flushing the buffer cache. +.Pp +Actions can be configured for the three transitions: +.Cm suspend , +.Cm standby +and +.Cm resume . +The suspend and standby actions are run prior to +.Nm +performing any other actions (such as disk syncs) and entering the new +mode. The resume program is run after resuming from a stand-by or +suspended state. +.Sh FILES +.Pa /etc/apm/suspend , +.Pa /etc/apm/standby +and +.Pa /etc/apm/resume +are the files that contain the host's customized actions. +Each file must be an executable binary or shell script suitable +for execution by the +.Xr execve 2 +function. +If you wish to have the same program or script control all transitions, it +may determine which transition is in progress by examining its +.Va argv[0] +which is set to one of +.Ar suspend , +.Ar standby , +or +.Ar resume . +.Pp +.Pa /var/run/apmdev +is the default UNIX-domain socket used for communication with +.Xr apm 8 . +The +.Fl S +flag may be used to specify an alternate socket name. +The socket is protected to mode 0660, UID 0, GID 0; this protects access +to suspend requests to authorized users only. +.Pp +.Pa /dev/apmctl +is the default device used to control the APM kernel driver. +The +.Fl f +flag may be used to specify an alternate device file name. +.Sh SEE ALSO +.Xr apm 4 , +.Xr apm 8 , +.Xr execv 2 , +.Xr speaker 4 , +.Xr syslog 3 , +.Xr syslogd 8 . +.Sh REFERENCES +Advanced Power Management (APM) BIOS Interface Specification (revision +1.1), Intel Corporation and Microsoft Corporation. +.Sh HISTORY +The +.Nm apmd +command appeared in OpenBSD 1.1B. diff --git a/usr.sbin/apmd/apmd.c b/usr.sbin/apmd/apmd.c new file mode 100644 index 00000000000..d7456a68f7f --- /dev/null +++ b/usr.sbin/apmd/apmd.c @@ -0,0 +1,471 @@ +/* + * 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. + * + */ + +#include <stdio.h> +#include <errno.h> +#include <syslog.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> +#include <machine/apmvar.h> +#include <err.h> +#include "pathnames.h" +#include "apm-proto.h" + +#define MAX(a,b) (a > b ? a : b) +#define TRUE 1 +#define FALSE 0 + +const char apmdev[] = _PATH_APM_CTLDEV; +const char sockfile[] = _PATH_APM_SOCKET; + +static int debug = 0; + +extern char *__progname; +extern char *optarg; +extern int optind; +extern int optopt; +extern int opterr; +extern int optreset; + +void usage (void); +int power_status (int fd, int force, struct apm_power_info *pinfo); +int bind_socket (const char *sn); +enum apm_state handle_client(int sock_fd, int ctl_fd); +void suspend(int ctl_fd); +void stand_by(int ctl_fd); +void resume(int ctl_fd); +void sigexit(int signo); +void make_noise(int howmany); +void do_etc_file(const char *file); + +void +sigexit(int signo) +{ + exit(1); +} + +void +usage(void) +{ + fprintf(stderr,"usage: %s [-d] [-t timo] [-s] [-a] [-f devfile] [-S sockfile]\n", __progname); + exit(1); +} + + +int +power_status(int fd, int force, struct apm_power_info *pinfo) +{ + struct apm_power_info bstate; + static struct apm_power_info last; + int acon = 0; + + if (ioctl(fd, APM_IOC_GETPOWER, &bstate) == 0) { + /* various conditions under which we report status: something changed + enough since last report, or asked to force a print */ + if (bstate.ac_state == APM_AC_ON) + acon = 1; + if (force || + bstate.ac_state != last.ac_state || + bstate.battery_state != last.battery_state || + (bstate.minutes_left && bstate.minutes_left < 15) || + abs(bstate.battery_life - last.battery_life) > 20) { + if (bstate.minutes_left) + syslog(LOG_NOTICE, + "battery status: %s. external power status: %s. " + "estimated battery life %d%% (%d minutes)", + battstate(bstate.battery_state), + ac_state(bstate.ac_state), bstate.battery_life, + bstate.minutes_left); + else + syslog(LOG_NOTICE, + "battery status: %s. external power status: %s. " + "estimated battery life %d%%", + battstate(bstate.battery_state), + ac_state(bstate.ac_state), bstate.battery_life); + last = bstate; + } + if (pinfo) + *pinfo = bstate; + } else + syslog(LOG_ERR, "cannot fetch power status: %m"); + return acon; +} + +static char *socketname; + +static void sockunlink(void); + +static void +sockunlink(void) +{ + if (socketname) + (void) remove(socketname); +} + +int +bind_socket(const char *sockname) +{ + int sock; + struct sockaddr_un s_un; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock == -1) + err(1, "cannot create local socket"); + + s_un.sun_family = AF_UNIX; + strncpy(s_un.sun_path, sockname, sizeof(s_un.sun_path)); + s_un.sun_len = SUN_LEN(&s_un); + /* remove it if present, we're moving in */ + (void) remove(sockname); + if (bind(sock, (struct sockaddr *)&s_un, s_un.sun_len) == -1) + err(1, "cannot connect to APM socket"); + if (chmod(sockname, 0660) == -1 || chown(sockname, 0, 0) == -1) + err(1, "cannot set socket mode/owner/group to 666/0/0"); + listen(sock, 1); + socketname = strdup(sockname); + atexit(sockunlink); + return sock; +} + +enum apm_state +handle_client(int sock_fd, int ctl_fd) +{ + /* accept a handle from the client, process it, then clean up */ + int cli_fd; + struct sockaddr_un from; + int fromlen; + struct apm_command cmd; + struct apm_reply reply; + + cli_fd = accept(sock_fd, (struct sockaddr *)&from, &fromlen); + if (cli_fd == -1) { + syslog(LOG_INFO, "client accept failure: %m"); + return NORMAL; + } + if (recv(cli_fd, &cmd, sizeof(cmd), 0) != sizeof(cmd)) { + (void) close(cli_fd); + syslog(LOG_INFO, "client size botch"); + return NORMAL; + } + if (cmd.vno != APMD_VNO) { + close(cli_fd); /* terminate client */ + /* no error message, just drop it. */ + return NORMAL; + } + power_status(ctl_fd, 0, &reply.batterystate); + switch (cmd.action) { + default: + reply.newstate = NORMAL; + break; + case SUSPEND: + reply.newstate = SUSPENDING; + break; + case STANDBY: + reply.newstate = STANDING_BY; + break; + } + reply.vno = APMD_VNO; + if (send(cli_fd, &reply, sizeof(reply), 0) != sizeof(reply)) { + syslog(LOG_INFO, "client reply botch"); + } + close(cli_fd); + return reply.newstate; +} + +static int speaker_ok = TRUE; + +void +make_noise(howmany) +int howmany; +{ + int spkrfd; + int trycnt; + + if (!speaker_ok) /* don't bother after sticky errors */ + return; + + for (trycnt = 0; trycnt < 3; trycnt++) { + spkrfd = open(_PATH_DEV_SPEAKER, O_WRONLY); + if (spkrfd == -1) { + switch (errno) { + case EBUSY: + usleep(500000); + errno = EBUSY; + continue; + case ENOENT: + case ENODEV: + case ENXIO: + case EPERM: + case EACCES: + syslog(LOG_INFO, + "speaker device " _PATH_DEV_SPEAKER " unavailable: %m"); + speaker_ok = FALSE; + return; + } + } else + break; + } + if (spkrfd == -1) { + syslog(LOG_WARNING, "cannot open " _PATH_DEV_SPEAKER ": %m"); + return; + } + syslog(LOG_DEBUG, "sending %d tones to speaker\n", howmany); + write (spkrfd, "o4cc", 2 + howmany); + close(spkrfd); + return; +} + + +void +suspend(int ctl_fd) +{ + do_etc_file(_PATH_APM_ETC_SUSPEND); + sync(); + make_noise(2); + sync(); + sync(); + sleep(1); + ioctl(ctl_fd, APM_IOC_SUSPEND, 0); +} + +void +stand_by(int ctl_fd) +{ + do_etc_file(_PATH_APM_ETC_STANDBY); + sync(); + make_noise(1); + sync(); + sync(); + sleep(1); + ioctl(ctl_fd, APM_IOC_STANDBY, 0); +} + +#define TIMO (10*60) /* 10 minutes */ + +void +resume(int ctl_fd) +{ + do_etc_file(_PATH_APM_ETC_RESUME); +} + +void +main(int argc, char *argv[]) +{ + const char *fname = apmdev; + int ctl_fd, sock_fd, ch, ready; + int statonly = 0; + fd_set devfds; + fd_set selcopy; + struct apm_event_info apmevent; + int suspends, standbys, resumes; + int noacsleep = 0; + struct timeval tv = {TIMO, 0}, stv; + const char *sockname = sockfile; + + while ((ch = getopt(argc, argv, "qadsf:t:S:")) != -1) + switch(ch) { + case 'q': + speaker_ok = FALSE; + break; + case 'a': + noacsleep = 1; + break; + case 'd': + debug = 1; + break; + case 'f': + fname = optarg; + break; + case 'S': + sockname = optarg; + break; + case 't': + tv.tv_sec = strtoul(optarg, 0, 0); + if (tv.tv_sec == 0) + usage(); + break; + case 's': /* status only */ + statonly = 1; + break; + case '?': + + default: + usage(); + } + argc -= optind; + argv += optind; + if ((ctl_fd = open(fname, O_RDWR)) == -1) { + (void)err(1, "cannot open device file `%s'", fname); + } + if (debug) { + openlog(__progname, LOG_CONS, LOG_LOCAL1); + } else { + openlog(__progname, LOG_CONS, LOG_DAEMON); + setlogmask(LOG_UPTO(LOG_NOTICE)); + daemon(0, 0); + } + power_status(ctl_fd, 1, 0); + if (statonly) + exit(0); + (void) signal(SIGTERM, sigexit); + (void) signal(SIGHUP, sigexit); + (void) signal(SIGINT, sigexit); + + sock_fd = bind_socket(sockname); + + FD_ZERO(&devfds); + FD_SET(ctl_fd, &devfds); + FD_SET(sock_fd, &devfds); + + for (selcopy = devfds, errno = 0, stv = tv; + (ready = select(MAX(ctl_fd,sock_fd)+1, &selcopy, 0, 0, &stv)) >= 0 || + errno == EINTR; + selcopy = devfds, errno = 0, stv = tv) { + if (errno == EINTR) + continue; + if (ready == 0) { + /* wakeup for timeout: take status */ + power_status(ctl_fd, 0, 0); + } + if (FD_ISSET(ctl_fd, &selcopy)) { + suspends = standbys = resumes = 0; + while (ioctl(ctl_fd, APM_IOC_NEXTEVENT, &apmevent) == 0) { + syslog(LOG_DEBUG, "apmevent %04x index %d", apmevent.type, + apmevent.index); + switch (apmevent.type) { + case APM_SUSPEND_REQ: + case APM_USER_SUSPEND_REQ: + case APM_CRIT_SUSPEND_REQ: + case APM_BATTERY_LOW: + suspends++; + break; + case APM_USER_STANDBY_REQ: + case APM_STANDBY_REQ: + standbys++; + break; +#if 0 + case APM_CANCEL: + suspends = standbys = 0; + break; +#endif + case APM_NORMAL_RESUME: + case APM_CRIT_RESUME: + case APM_SYS_STANDBY_RESUME: + resumes++; + break; + case APM_POWER_CHANGE: + power_status(ctl_fd, 1, 0); + break; + default: + break; + } + } + if ((standbys || suspends) && noacsleep && + power_status(ctl_fd, 0, 0)) { + syslog(LOG_DEBUG, "not sleeping cuz AC is connected"); + } else if (suspends) { + suspend(ctl_fd); + } else if (standbys) { + stand_by(ctl_fd); + } else if (resumes) { + resume(ctl_fd); + syslog(LOG_NOTICE, "system resumed from APM sleep"); + } + ready--; + } + if (ready == 0) + continue; + if (FD_ISSET(sock_fd, &selcopy)) { + switch (handle_client(sock_fd, ctl_fd)) { + case NORMAL: + break; + case SUSPENDING: + suspend(ctl_fd); + break; + case STANDING_BY: + stand_by(ctl_fd); + break; + } + } + } + syslog(LOG_ERR, "select failed: %m"); + exit(1); +} + +void +do_etc_file(const char *file) +{ + pid_t pid; + int status; + const char *prog; + + /* If file doesn't exist, do nothing. */ + if (access(file, X_OK|R_OK)) { + syslog(LOG_DEBUG, "do_etc_file(): cannot access file %s", file); + return; + } + + prog = strrchr(file, '/'); + if (prog) + prog++; + else + prog = file; + + pid = fork(); + switch (pid) { + case -1: + syslog(LOG_ERR, "failed to fork(): %m"); + return; + case 0: + /* We are the child. */ + execl(file, prog, NULL); + _exit(-1); + /* NOTREACHED */ + default: + /* We are the parent. */ + wait4(pid, &status, 0, 0); + if (WIFEXITED(status)) + syslog(LOG_DEBUG, "%s exited with status %d", file, + WEXITSTATUS(status)); + else { + syslog(LOG_ERR, "%s exited abnormally.", file); + } + break; + } +} diff --git a/usr.sbin/apmd/apmsubr.c b/usr.sbin/apmd/apmsubr.c new file mode 100644 index 00000000000..014361ec20c --- /dev/null +++ b/usr.sbin/apmd/apmsubr.c @@ -0,0 +1,79 @@ +/* + * 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. + * + */ + +#include <stdio.h> +#include <errno.h> +#include <syslog.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <machine/apmvar.h> +#include <err.h> +#include "apm-proto.h" + +const char * +battstate(int state) +{ + switch (state) { + case APM_BATT_HIGH: + return "high"; + case APM_BATT_LOW: + return "low"; + case APM_BATT_CRITICAL: + return "CRITICAL"; + case APM_BATT_CHARGING: + return "charging"; + case APM_BATTERY_ABSENT: + return "absent"; + case APM_BATT_UNKNOWN: + return "unknown (absent?)"; + default: + return "invalid battery state"; + } +} + +const char * +ac_state(int state) +{ + switch (state) { + case APM_AC_OFF: + return "not connected"; + case APM_AC_ON: + return "connected"; + case APM_AC_BACKUP: + return "backup power source"; + case APM_AC_UNKNOWN: + return "not known"; + default: + return "invalid AC status"; + } +} diff --git a/usr.sbin/apmd/pathnames.h b/usr.sbin/apmd/pathnames.h new file mode 100644 index 00000000000..393f19f9151 --- /dev/null +++ b/usr.sbin/apmd/pathnames.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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. + * + */ + +#define _PATH_APM_SOCKET "/var/run/apmdev" +#define _PATH_APM_CTLDEV "/dev/apmctl" +#define _PATH_APM_ETC_DIR "/etc/apm" +#define _PATH_APM_ETC_SUSPEND _PATH_APM_ETC_DIR"/suspend" +#define _PATH_APM_ETC_STANDBY _PATH_APM_ETC_DIR"/standby" +#define _PATH_APM_ETC_RESUME _PATH_APM_ETC_DIR"/resume" +#define _PATH_APM_NORMAL "/dev/apm" +#define _PATH_DEV_SPEAKER "/dev/speaker" diff --git a/usr.sbin/pcmciad/Makefile b/usr.sbin/pcmciad/Makefile new file mode 100644 index 00000000000..99a28031105 --- /dev/null +++ b/usr.sbin/pcmciad/Makefile @@ -0,0 +1,20 @@ +# $Id: Makefile,v 1.1 1996/04/29 13:08:51 hvozda Exp $ + +SRCS= pcmciad.c pcmcia_conf.c +#LIBS= -lutil +VPATH= ${.CURDIR}/../../sys/dev/pcmcia + +CFLAGS+= -g -Wmissing-prototypes -I${.CURDIR}/../../sys +PROG= pcmciad +MAN= pcmciad.8 + +pcmcia_conf.o: pcmcia_conf.c + $(CC) $(CFLAGS) -D_KERNEL -c $< +clean:: + rm -f a.out [Ee]rrs mklog core *.core pcmciad pcmcia_conf.o pcmciad.o + + +SUBDIR=dumpcor dumpinfo dumpreg +.include <bsd.subdir.mk> +.include <bsd.prog.mk> +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/usr.sbin/pcmciad/README.dump-progs b/usr.sbin/pcmciad/README.dump-progs new file mode 100644 index 00000000000..99aa9f75845 --- /dev/null +++ b/usr.sbin/pcmciad/README.dump-progs @@ -0,0 +1,11 @@ +The progams here are ports of Barry Jaspan's stuff. + +From the original README: + +Copyright 1993 Barry Jaspan. Everything contained in this release +(with the exception of some #defines in pcmcia.h) is original work. +Permission is granted to distribute this system under the terms of the +GNU General Public License. + +Barry Jaspan, bjaspan@gza.com + diff --git a/usr.sbin/pcmciad/dumpcor/Makefile b/usr.sbin/pcmciad/dumpcor/Makefile new file mode 100644 index 00000000000..58b43551a75 --- /dev/null +++ b/usr.sbin/pcmciad/dumpcor/Makefile @@ -0,0 +1,10 @@ +# $Id: Makefile,v 1.1 1996/04/29 13:09:02 hvozda Exp $ + +SRCS = dumpcor.c + +CFLAGS += -g -I/sys +PROG=dumpcor +NOMAN= + +.include <bsd.prog.mk> +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/usr.sbin/pcmciad/dumpcor/dumpcor.c b/usr.sbin/pcmciad/dumpcor/dumpcor.c new file mode 100644 index 00000000000..662e86cac31 --- /dev/null +++ b/usr.sbin/pcmciad/dumpcor/dumpcor.c @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <sys/types.h> +#include <sys/device.h> +#include <sys/file.h> +#include <sys/ioctl.h> + +#include <dev/ic/i82365reg.h> +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmcia_ioctl.h> + + +struct reg_t { + int addr; + char *name; + int width; +}; + +struct reg_t cor_regs[] = { + {PCMCIA_COR , "Configuration and Option Register", 1,}, + {PCMCIA_CCSR, "Card Configuration and Status Register", 1,}, + {PCMCIA_PIR, "Pin Replacement Register", 1,}, + {PCMCIA_SCR,"Socket and Copy Register", 1,}, + {0, NULL, 0,} +}; + +struct pcmcia_info data; + +main(int argc, char **argv) +{ + int i, j, idx; + int fd; + char nmbuf[80]; + + if (argc < 2) + exit(1); + idx=atoi(argv[1]); + + sprintf(nmbuf,"/dev/pcmcia/slot%d",idx); + + if((fd=open(nmbuf,O_RDWR))<0) { + perror("open"); + exit(1); + } + + if(ioctl(fd,PCMCIAIO_READ_COR,&data)<0) { + perror("ioctl"); + exit(1); + } + + dump_cor_regs(&data.cis_data); + printf("\n"); + return 0; +} + +dump_cor_regs(unsigned char *data) +{ + int i; + + for(;;) { + unsigned int idx=*data++; + unsigned int val=*data++; + if(idx==0xff) + return; + if(idx<4) + printf("%s: 0x%x\n", cor_regs[idx].name,val); + else + printf("unkown 0x%x: %x\n", idx,val); + } +} diff --git a/usr.sbin/pcmciad/dumpinfo/Makefile b/usr.sbin/pcmciad/dumpinfo/Makefile new file mode 100644 index 00000000000..51a82e34885 --- /dev/null +++ b/usr.sbin/pcmciad/dumpinfo/Makefile @@ -0,0 +1,11 @@ +# $Id: Makefile,v 1.1 1996/04/29 13:09:05 hvozda Exp $ + +SRCS = dumpinfo.c +#dumpreg.c + +CFLAGS += -g +PROG=dumpinfo +NOMAN= + +.include <bsd.prog.mk> +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/usr.sbin/pcmciad/dumpinfo/dumpinfo.c b/usr.sbin/pcmciad/dumpinfo/dumpinfo.c new file mode 100644 index 00000000000..79c2070e489 --- /dev/null +++ b/usr.sbin/pcmciad/dumpinfo/dumpinfo.c @@ -0,0 +1,659 @@ +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/device.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmcia_ioctl.h> + +void parse_device(u_char *, int, int); +void parse_ver1(u_char *, int, int); +void parse_config(u_char *, int, int); +void parse_cfent_dumpinfo(u_char *, int, int); +void read_extended_speed(u_char *, int *); +const char *tuple_name(int), *dtype_name(int), *dsize_name(int), + *dspeed_name(int); +void parse_tuples(u_char *buf, int print_tuples); +dbuf(u_char *buf,int len,int verb) { + int i; + for(i=0;i<len;i++) { + if(i%8==0) + printf("%04x : ",i); + printf(" %02x(%c)",buf[i],buf[i]<' '||buf[i]>126?'.':buf[i]); + if(i%8==7) + printf("\n"); + } + if(i%16!=0) + printf("\n"); +} + +main(int argc,char **argv) { + int fd; + char namebuf[64]; + int sockid=-1; + int verb=0; + struct pcmcia_status stbuf; + struct pcmcia_info inbuf; + char *file; + + if(argc<2) { + exit(1); + } + + if(*(argv[1])<'0' || *(argv[1])>'9') { + file=argv[1]; + } else { + sockid=atoi(argv[1]); + } + if(argc>2) { + verb=atoi(argv[2]); + } + + if(sockid>=0) { + sprintf(namebuf,"/dev/pcmcia/slot%d",sockid); + + if((fd=open(namebuf,O_RDWR))<0) { + printf("errno %d\n",errno); + perror("open"); + exit(1); + } + printf("open ok\n",stbuf.slot,stbuf.status); + if(ioctl(fd,PCMCIAIO_GET_STATUS,&stbuf)<0) { + printf("errno %d\n",errno); + perror("ioctl PCMCIAIO_GET_STATUS"); + exit(1); + } + printf("Status slot %d %x\n",stbuf.slot,stbuf.status); + if(!(stbuf.status&PCMCIA_CARD_PRESENT)) { + printf("No card in slot %d\n",stbuf.slot); + exit(1); + } + if(!(stbuf.status&PCMCIA_POWER)) { + int pw=PCMCIA_POWER_5V; + printf("Card in slot %d no power\n",stbuf.slot); + if(ioctl(fd,PCMCIAIO_SET_POWER,&pw)<0) { + printf("errno %d\n",errno); + perror("ioctl PCMCIAIO_SET_POWER"); + exit(1); + } + /*exit(1);/**/ + } + if(!(stbuf.status&PCMCIA_READY)) { + printf("Card in slot %d not ready\n",stbuf.slot); + /*exit(1);/**/ + } + if(ioctl(fd,PCMCIAIO_GET_INFO,&inbuf)<0) { + printf("errno %d\n",errno); + perror("ioctl PCMCIAIO_GET_INFO"); + exit(1); + } + } else if(file) { + fd=open(file,O_RDONLY); + if(fd==-1) { + perror("Can't open file"); + exit(1); + } + if(read(fd,inbuf.cis_data,512)==-1) { + perror("Can't read file"); + exit(1); + } + } + if(verb) + dbuf(inbuf.cis_data,512,verb);/**/ + parse_tuples(inbuf.cis_data,1); + exit(0); + +} + +void parse_tuples(u_char *buf, int print_tuples) +{ + u_char code, len,*tbuf; + int done; + + done = 0; + while (!done) { + code=*buf++; + if (code == CIS_NULL) { + if (print_tuples) + printf("NULL tuple\n"); + continue; + } + + len=*buf++; + if(code!=CIS_END) + if (print_tuples) + printf("%s (%d):\n", tuple_name(code), len); + + + tbuf=buf; + buf+=len; + switch (code) { + case CIS_NULL: + if (print_tuples) + printf("NULL\n"); + break; + case CIS_END: + done = 1; + break; + case CIS_DEVICE: + case CIS_DEVICE_A: + if (!print_tuples) + break; + parse_device(tbuf, len, print_tuples); + break; + case CIS_VER1: + parse_ver1(tbuf, len, print_tuples); + break; + case CIS_CFG_INFO: + parse_config(tbuf, len, print_tuples); + break; + case CIS_CFG_ENT: + parse_cfent_dumpinfo(tbuf, len, print_tuples); + break; + default: + if (print_tuples) + printf("\tskpping\n"); + break; + } + } +} + +void parse_device(u_char *tbuf, int tlen, int print_tuples) +{ + int i, idx, addr_units; + + i = 0; + while (i < tlen) { + /* last info structure? */ + if (tbuf[i] == 0xff) { + break; + } + + /* device id */ + idx = (tbuf[i] & CIS_DEVICE_TYPE) >> CIS_DEVICE_TYPE_SHIFT; + printf("\tType %s, ", dtype_name(idx)); + printf("WPS %s, ", tbuf[i] & CIS_DEVICE_WPS ? "set" : "clear"); + idx = tbuf[i] & CIS_DEVICE_SPEED; + printf("Speed %s, ", dspeed_name(idx)); + + /* device size */ + i++; + if (tbuf[i] != 0xff) { + addr_units = ((tbuf[i] & CIS_DEVICE_ADDRS) >> + CIS_DEVICE_ADDRS_SHIFT) + 1; + idx = tbuf[i] & CIS_DEVICE_SIZE; + printf("Size %s * %d", dsize_name(idx), addr_units); + } else { + printf("IGNORED"); + /* ignore this device info entry */ + } + + printf("\n"); + + i++; + } +} + +void parse_ver1(u_char *tbuf, int len, int print_tuples) +{ + int i; + char manufacturer[33],prod_name[33],addl_info1[33],addl_info2[33]; + + i = 0; + if (tbuf[i++] != 0x04) { + if (print_tuples) + fprintf(stderr, "Major version != 0x04\n"); + return; + } + if (tbuf[i++] != 0x01) { + if (print_tuples) + fprintf(stderr, "Minor version != 0x01\n"); + return; + } + strncpy(manufacturer, &tbuf[i], sizeof(manufacturer)-1); + i += strlen(manufacturer) + 1; + strncpy(prod_name, &tbuf[i], sizeof(prod_name)-1); + i += strlen(&tbuf[i]) + 1; + if(tbuf[i]==0xff) + addl_info1[0]=0; + else { + strncpy(addl_info1, &tbuf[i], sizeof(addl_info1)-1); + i += strlen(&tbuf[i]) + 1; + } + if(tbuf[i]==0xff) + addl_info2[0]=0; + else { + strncpy(addl_info2, &tbuf[i], sizeof(addl_info2)-1); + i += strlen(&tbuf[i]) + 1; + } + if (print_tuples) { + printf("\tManufacturer: %s\n", manufacturer); + printf("\tProduct name: %s\n", prod_name); + printf("\tAddl info 1: %s\n", addl_info1); + printf("\tAddl info 2: %s\n", addl_info2); + } + if (tbuf[i] != 0xff) { + fprintf(stderr, "Tuple not ended by 0xff!\n"); + return; + } +} + +void parse_config(u_char *tbuf, int len, int print_tuples) +{ + int i, rasz, rmsz,config_midx,base_addr,regmask[4]; + + i = 0; + rasz = (tbuf[i] & TPCC_RASZ) >> TPCC_RASZ_SHIFT; + rmsz = (tbuf[i] & TPCC_RMSZ) >> TPCC_RMSZ_SHIFT; + if (print_tuples) + printf("\tRASZ %d, RMSZ %d, ", rasz+1, rmsz+1); + + i++; + config_midx = (tbuf[i] & TPCC_LAST) >> TPCC_LAST_SHIFT; + if (print_tuples) + printf("last idx %d, ", config_midx); + + i++; + base_addr = 0; + switch (rasz) { + case 3: + base_addr |= (tbuf[i+3] << 24); + case 2: + base_addr |= (tbuf[i+2] << 16); + case 1: + base_addr |= (tbuf[i+1] << 8); + case 0: + base_addr |= tbuf[i]; + } + if (print_tuples) + printf("base addr 0x%08x\n", base_addr); + + i += rasz + 1; + regmask[0] = regmask[1] = 0; + regmask[2] = regmask[3] = 0; + switch (rmsz) { + case 15: + regmask[3] |= (tbuf[i+15] << 24); + case 14: + regmask[3] |= (tbuf[i+14] << 16); + case 13: + regmask[3] |= (tbuf[i+13] << 8); + case 12: + regmask[3] |= tbuf[i+12]; + case 11: + regmask[2] |= (tbuf[i+11] << 24); + case 10: + regmask[2] |= (tbuf[i+10] << 16); + case 9: + regmask[2] |= (tbuf[i+9] << 8); + case 8: + regmask[2] |= tbuf[i+8]; + case 7: + regmask[1] |= (tbuf[i+7] << 24); + case 6: + regmask[1] |= (tbuf[i+6] << 16); + case 5: + regmask[1] |= (tbuf[i+5] << 8); + case 4: + regmask[1] |= tbuf[i+4]; + case 3: + regmask[0] |= (tbuf[i+3] << 24); + case 2: + regmask[0] |= (tbuf[i+2] << 16); + case 1: + regmask[0] |= (tbuf[i+1] << 8); + case 0: + regmask[0] |= tbuf[i+0]; + break; + } + if (print_tuples) + printf("\treg mask 0x%04x%04x%04x%04x, ", + regmask[3], regmask[2], + regmask[1], regmask[0]); + + i += rmsz + 1; + if (print_tuples) + printf("\n\t%d bytes in subtuples\n", len - i); +} + +void parse_cfent_dumpinfo(u_char *tbuf, int len, int print_tuples) +{ + int i, j, k, intface, ftrsm,idx,defp,iop,io_16,ios,ftrs; + int pwr_desc, wait_scale, rdy_scale, rsv_scale; + int io_block_len, io_block_size; + int host_addr_p, addr_size, len_size,elen; + + + i = 0; + intface = (tbuf[i] & TPCE_INDX_INT); + idx = (tbuf[i] & TPCE_INDX_ENTRY); + defp = (tbuf[i] & TPCE_INDX_DEF); + if (print_tuples) + printf("\tEntry %d, %sdefault, %sinterface\n", idx, + defp ? "" : "not ", intface ? "" : "no "); + if (intface) { + i++; + if (print_tuples) + printf("\ttype %d, BVD %d, WP %d, RdyBsy %d, " + "wait sig %d\n", + tbuf[i] & TPCE_IF_TYPE, + !!tbuf[i] & TPCE_IF_BVD, + !!tbuf[i] & TPCE_IF_WP, + !!tbuf[i] & TPCE_IF_RDYBSY, + !!tbuf[i] & TPCE_IF_MWAIT); + } + i++; + + ftrs = tbuf[i++]; + if (print_tuples) + printf("\tfeatures 0x%02x (%x)\n", ftrs,ftrs&TPCE_FS_PWR); + + /* XXX skip all power description structures */ + for (j = 0; j < (ftrs & TPCE_FS_PWR); j++) { + pwr_desc = tbuf[i++]; + printf("PWR %x\n",pwr_desc); + /* for each struct, skip all parameter defns */ + for (k = 0; k < 8; pwr_desc >>= 1, k++) { + if (pwr_desc & 0x01) { + printf("%d: ",k); + /* skip bytes until non-ext found */ + printf("%x ",tbuf[i]); + while (tbuf[i++] & 0x80) + printf("%x ",tbuf[i]); + ;/**/ + printf("\n"); + } + } + } + + if (ftrs & TPCE_FS_TD) { + wait_scale = tbuf[i] & TPCE_FS_TD_WAIT; + rdy_scale = (tbuf[i] & TPCE_FS_TD_RDY) >> + TPCE_FS_TD_RDY_SHIFT; + rsv_scale = (tbuf[i] & TPCE_FS_TD_RSV) >> + TPCE_FS_TD_RSV_SHIFT; + i++; + if (wait_scale != 3) { + read_extended_speed(tbuf, &i); + if (print_tuples) + printf("\twait scale %d\n", wait_scale); + } + if (rdy_scale != 7) { + read_extended_speed(tbuf, &i); + if (print_tuples) + printf("\tReady/Busy scale %d\n", rdy_scale); + } + if (rsv_scale != 7) { + read_extended_speed(tbuf, &i); + if (print_tuples) + printf("\tReserved scale %d\n", rsv_scale); + } + } + + if (ftrs & TPCE_FS_IO) { + int io_addrs[16],io_lens[16]; + int iptr,ilen,ranges; + iop = 1; + io_16 = tbuf[i] & TPCE_FS_IO_BUS16; + if (print_tuples) + printf("\tIO lines %x, bus8 %d, bus16 %d, range %d\n", + (tbuf[i] & TPCE_FS_IO_LINES), + !!(tbuf[i] & TPCE_FS_IO_BUS8), + !!io_16, + ranges=!!(tbuf[i] & TPCE_FS_IO_RANGE)); + i++; + if(ranges) { + io_block_len = (tbuf[i] & TPCE_FS_IO_LEN) >> + TPCE_FS_IO_LEN_SHIFT; + io_block_size = (tbuf[i] & TPCE_FS_IO_SIZE) >> + TPCE_FS_IO_SIZE_SHIFT; + ios = (tbuf[i] & TPCE_FS_IO_NUM) + 1; + elen=io_block_len+(io_block_len==3?1:0)+ + io_block_size+(io_block_size==3?1:0); + i++; + if((ftrs & TPCE_FS_IRQ)!=0) { + iptr=(ios*elen)+i; + if((tbuf[iptr]&(TPCE_FS_IRQ_PULSE|TPCE_FS_IRQ_LEVEL))==0) { + if(((tbuf[iptr-elen]) &(TPCE_FS_IRQ_PULSE|TPCE_FS_IRQ_LEVEL))!=0) { + iptr-=elen; + } + } + if((tbuf[iptr]&TPCE_FS_IRQ_MASK)!=0) { + ilen=2; + } else { + ilen=1; + } + } else { + ilen=0; + } + if((i+(ios*elen)+ilen)>len) { + if (print_tuples) + printf("Warning: CIS range info doesn't fit in entry!" + " Reducing # of ranges by 1\n"); + printf("%d %d %d %d %d\n",i,ios,ilen,ios*elen,len); + ios--; + } + if (print_tuples) + printf("\t# ranges %d, length size %d, " + "addr size %d\n", ios, + io_block_len, io_block_size); + for (j = 0; j < ios; j++) { + io_addrs[j] = io_lens[j] = 0; + switch (io_block_size) { + case 3: + io_addrs[j] |= tbuf[i+3] << 24; + io_addrs[j] |= tbuf[i+2] << 16; + case 2: + io_addrs[j] |= tbuf[i+1] << 8; + case 1: + io_addrs[j] |= tbuf[i]; + break; + } + i += io_block_size + (io_block_size == 3 ? 1 + : 0); + switch (io_block_len) { + case 3: + io_lens[j] |= tbuf[i+3] << 24; + io_lens[j] |= tbuf[i+2] << 16; + case 2: + io_lens[j] |= tbuf[i+1] << 8; + case 1: + io_lens[j] |= tbuf[i]; + break; + } + io_lens[j]++; + i += io_block_len + (io_block_len == 3 ? 1 + : 0); + + if (print_tuples) + if(io_lens[j]&1) + printf("\taddr %08x, len %d (Assuming incorect CIS entry" + " CIS value == %d)\n", + io_addrs[j], + io_lens[j]-1, + io_lens[j]); + else + printf("\taddr %08x, len %d\n", + io_addrs[j], + io_lens[j]); + } + } + } + + if (ftrs & TPCE_FS_IRQ) { + int irq_mask,irqp,irq; + irqp = 1; + if (print_tuples) + printf("\tIRQ: share %d, pulse %d, level %d, ", + !!(tbuf[i] & TPCE_FS_IRQ_SHARE), + !!(tbuf[i] & TPCE_FS_IRQ_PULSE), + !!(tbuf[i] & TPCE_FS_IRQ_LEVEL)); + if (tbuf[i] & TPCE_FS_IRQ_MASK) { + irq_mask = (tbuf[i+2] << 8) + tbuf[i+1]; + if (print_tuples) + printf("VEND %d, BERR %d, IOCK %d, NMI %d\n" + "\t mask 0x%04x\n", + !!(tbuf[i] & TPCE_FS_IRQ_VEND), + !!(tbuf[i] & TPCE_FS_IRQ_BERR), + !!(tbuf[i] & TPCE_FS_IRQ_IOCK), + !!(tbuf[i] & TPCE_FS_IRQ_NMI), + irq_mask); + i += 2; + } else { + irq = tbuf[i] & TPCE_FS_IRQ_IRQN; + if (print_tuples) + printf("IRQ %d\n", irq); + } + + i++; + } + + if (ftrs & TPCE_FS_MEM) { + int memp,mems,mem_lens[16],mem_caddrs[16],mem_haddrs[16]; + memp = 1; + switch ((ftrs & TPCE_FS_MEM) >> TPCE_FS_MEM_SHIFT) { + case 1: + mems = 1; + mem_lens[0] = (tbuf[i+1] << 8) + tbuf[i]; + mem_lens[0] <<= 8; + printf("\tmem: len %d\n", mem_lens[0]); + + break; + case 2: + mems = 1; + mem_lens[0] = (tbuf[i+1] << 8) + tbuf[i]; + mem_caddrs[0] = mem_haddrs[0] = + (tbuf[i+3] << 8) + tbuf[i+2]; + + mem_lens[0] <<= 8; + mem_caddrs[0] <<= 8; + + if (print_tuples) + printf("\tmem: len %d, addr %d\n", + mem_lens[0], + mem_caddrs[0]); + break; + case 3: + host_addr_p = tbuf[i] & TPCE_FS_MEM_HOST; + addr_size = (tbuf[i] & TPCE_FS_MEM_ADDR) >> + TPCE_FS_MEM_ADDR_SHIFT; + len_size = (tbuf[i] & TPCE_FS_MEM_LEN) >> + TPCE_FS_MEM_LEN_SHIFT; + mems = (tbuf[i] & TPCE_FS_MEM_WINS) + 1; + if (print_tuples) + printf("\tmem (%x): host %d, addr size %d, len " + "size %d, # wins %d\n", tbuf[i], + !!host_addr_p, addr_size, + len_size, mems); + i++; + for (j = 0; j < mems; j++) { + mem_lens[j] = 0; + mem_caddrs[j] = 0; + mem_haddrs[j] = 0; + switch (len_size) { + case 3: + mem_lens[j] |= (tbuf[i+2] << 16); + case 2: + mem_lens[j] |= (tbuf[i+1] << 8); + case 1: + mem_lens[j] |= tbuf[i]; + } + i += len_size; + switch (addr_size) { + case 3: + mem_caddrs[j] |= (tbuf[i+2] << 16); + case 2: + mem_caddrs[j] |= (tbuf[i+1] << 8); + case 1: + mem_caddrs[j] |= tbuf[i]; + } + i += addr_size; + if (host_addr_p) { + switch (addr_size) { + case 3: + mem_haddrs[j] |= + (tbuf[i+2] << 16); + case 2: + mem_haddrs[j] |= + (tbuf[i+1] << 8); + case 1: + mem_haddrs[j] |= + tbuf[i]; + } + i += addr_size; + } + + mem_lens[j] <<= 8; + mem_caddrs[j] <<= 8; + mem_haddrs[j] <<= 8; + + if (print_tuples) + printf("\t\twin %d: len %d, card addr " + "%x, host addr %x\n", j, + mem_lens[j], + mem_caddrs[j], + mem_haddrs[j]); + } + } + } +} + +void read_extended_speed(u_char *tbuf, int *i) +{ + *i += 1; + /* fprintf(stderr, "\tXXX read_extended_speed not implemented!\n"); */ +} + +const char *tuple_name(int code) +{ +#define MAX_TUPLE_NAME (sizeof(tuple_names) / sizeof(char *)) + static const char *tuple_names[] = { + "NULL", "DEVICE", + "reserved", "reserved", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved", + "reserved", "reserved", + "CHECKSUM", "LONGLINK_A", "LONGLINK_C", "LINKTARGET", + "NO_LINK", "VERS_1", "ALTSTR", "DEVICE_A", + "JEDEC_C", "JEDEC_A", "CONFIG", "CFTABLE_ENTRY", + "DEVICE_OC", "DEVICE_OA", + }; + if(code==CIS_END) + return "END"; + + return (code < MAX_TUPLE_NAME) ? tuple_names[code] : "UNKNOWN"; +} + +const char *dtype_name(int idx) +{ +#define MAX_DTYPE_NAME (sizeof(dtype_names) / sizeof(char *)) + static const char *dtype_names[] = { + "NULL", "ROM", "OTPROM", "EPROM", + "EEPROM", "FLASH", "SRAM", "DRAM", + }; + + return (idx < MAX_DTYPE_NAME) ? dtype_names[idx] : "INVALID"; +} + +const char *dspeed_name(int idx) +{ +#define MAX_DSPEED_NAME (sizeof(dspeed_names) / sizeof(char *)) + static const char *dspeed_names[] = { + "NULL", "250NS", "200NS", "150NS", + "100NS", "reserved", "reserved", "extended", + }; + + return (idx < MAX_DSPEED_NAME) ? dspeed_names[idx] : "INVALID"; +} + +const char *dsize_name(int idx) +{ +#define MAX_DSIZE_NAME (sizeof(dsize_names) / sizeof(char *)) + static const char *dsize_names[] = { + "512b", "2k", "8k", "32k", "128k", "512k", "2M", "reserved", + }; + return (idx < MAX_DSIZE_NAME) ? dsize_names[idx] : "INVALID"; +} diff --git a/usr.sbin/pcmciad/dumpreg/Makefile b/usr.sbin/pcmciad/dumpreg/Makefile new file mode 100644 index 00000000000..e57d843e9ab --- /dev/null +++ b/usr.sbin/pcmciad/dumpreg/Makefile @@ -0,0 +1,10 @@ +# $Id: Makefile,v 1.1 1996/04/29 13:09:09 hvozda Exp $ + +SRCS = dumpreg.c + +CFLAGS += -g +PROG=dumpreg +NOMAN= + +.include <bsd.prog.mk> +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/usr.sbin/pcmciad/dumpreg/dumpreg.c b/usr.sbin/pcmciad/dumpreg/dumpreg.c new file mode 100644 index 00000000000..de1a0a7ebbe --- /dev/null +++ b/usr.sbin/pcmciad/dumpreg/dumpreg.c @@ -0,0 +1,143 @@ +#include <stdio.h> +#include <sys/types.h> +#include <sys/device.h> +#include <sys/file.h> +#include <sys/ioctl.h> + +#include <dev/ic/i82365reg.h> +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmcia_ioctl.h> + + +struct reg_t { + char addr; + char *name; + int width; +}; + +struct reg_t pcic_regs[] = { + PCIC_ID_REV, "Identification and Revision", 1, + PCIC_STATUS, "Interface Status", 1, + PCIC_POWER, "Power and RESETDRV control", 1, + PCIC_INT_GEN, "Interrupt and General Control", 1, + PCIC_STAT_CHG, "Card Status Change", 1, + PCIC_STAT_INT, "Card Status Change Interrupt Config", 1, + PCIC_ADDRWINE, "Address Window Enable", 1, + PCIC_IOCTL, "I/O Control", 1, + PCIC_IO0_STL, "I/O Address 0 Start", 2, + PCIC_IO0_SPL, "I/O Address 0 Stop", 2, + PCIC_IO1_STL, "I/O Address 1 Start", 2, + PCIC_IO1_SPL, "I/O Address 1 Stop", 2, + PCIC_SM0_STL, "System Memory Address 0 Mapping Start", 2, + PCIC_SM0_SPL, "System Memory Address 0 Mapping Stop", 2, + PCIC_CM0_L, "Card Memory Offset Address 0", 2, + PCIC_SM1_STL, "System Memory Address 1 Mapping Start", 2, + PCIC_SM1_SPL, "System Memory Address 1 Mapping Stop", 2, + PCIC_CM1_L, "Card Memory Offset Address 1", 2, + PCIC_SM2_STL, "System Memory Address 2 Mapping Start", 2, + PCIC_SM2_SPL, "System Memory Address 2 Mapping Stop", 2, + PCIC_CM2_L, "Card Memory Offset Address 2", 2, + PCIC_SM3_STL, "System Memory Address 3 Mapping Start", 2, + PCIC_SM3_SPL, "System Memory Address 3 Mapping Stop", 2, + PCIC_CM3_L, "Card Memory Offset Address 3", 2, + PCIC_SM4_STL, "System Memory Address 4 Mapping Start", 2, + PCIC_SM4_SPL, "System Memory Address 4 Mapping Stop", 2, + PCIC_CM4_L, "Card Memory Offset Address 4", 2, + 0, NULL, 0, +}; + +#if 0 +struct reg_t pcmcia_regs[] = { + PCMCIA_COR, "Configuration Option Register", 1, + PCMCIA_CCSR, "Card Configuration Status Register", 1, + PCMCIA_PIR, "Pin Replacement Register", 1, + PCMCIA_SCR, "Socket and Copy Register", 1, + 0, NULL, 0, +}; +#endif + +struct pcmcia_regs data; +struct pcic_regs *pcic = (struct pcic_regs *)&data.chip_data[0]; + +main(int argc, char **argv) +{ + int i, j, idx; + int fd; + char nmbuf[80]; + + if (argc < 2) + exit(1); + + idx=atoi(argv[1]); + + for(i=0;i<128;i++) { + pcic->reg[i].addr=i; + } + pcic->cnt=128; + + sprintf(nmbuf,"/dev/pcmcia/chip%d",idx/2); + + if((fd=open(nmbuf,O_RDWR))<0) { + perror("open"); + exit(1); + } + + if(ioctl(fd,PCMCIAIO_READ_REGS,&data)<0) { + perror("ioctl"); + exit(1); + } + + + + dump_pcic_regs((idx&1)?0x40:0); + printf("\n"); + /*if (argc == 2) + dump_pcmcia_regs(&pcic_socks[i]);/**/ + + return 0; +} + +dump_pcic_regs(int off) +{ + int i; + + for (i = 0; pcic_regs[i].name; i++) { + printf("%s: ", pcic_regs[i].name); + switch (pcic_regs[i].width) { + case 1: + printf("%#x", pcic->reg[pcic_regs[i].addr+off].val); + break; + case 2: + printf("%#x", (pcic->reg[pcic_regs[i].addr+off+1].val<<8)|pcic->reg[pcic_regs[i].addr+off].val); + break; + } + printf("\n"); + } +} +#if 0 +dump_pcmcia_regs(struct pcic_sock *sock) +{ + int i; + u_char v; + + pcic_map_attr(sock, PHYS_ADDR, 1); + for (i = 0; pcmcia_regs[i].name; i++) { + printf("%s: ", pcmcia_regs[i].name); + + if (lseek(mem_fd, PHYS_ADDR + sock->base_addr + + pcmcia_regs[i].addr, SEEK_SET) < 0) { + perror("seeking to tuple memory"); + exit(1); + } + if (read(mem_fd, &v, 1) < 0) { + perror("reading tuple memory"); + exit(1); + } + + printf("%#x\n", v); + } + + pcic_map_attr(sock, PHYS_ADDR, 0); +} +#endif diff --git a/usr.sbin/pcmciad/pathnames.h b/usr.sbin/pcmciad/pathnames.h new file mode 100644 index 00000000000..f28474271e9 --- /dev/null +++ b/usr.sbin/pcmciad/pathnames.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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. + * + */ + +#define _PATH_DEV_SPEAKER "/dev/speaker" +#define _PATH_PCMCIA_CONF "/etc/pcmciad.conf" + diff --git a/usr.sbin/pcmciad/pcmciad.8 b/usr.sbin/pcmciad/pcmciad.8 new file mode 100644 index 00000000000..439e01459af --- /dev/null +++ b/usr.sbin/pcmciad/pcmciad.8 @@ -0,0 +1,76 @@ +.\" 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. +.\" +.\" $Id: pcmciad.8,v 1.1 1996/04/29 13:08:56 hvozda Exp $ +.\" +.Dd October 29, 1995 +.Dt PCMCIAD 8 +.Os OpenBSD +.Sh NAME +.Nm pcmciad +.Nd PC-CARD slot monitor daemon +.Sh SYNOPSIS +.Nm +.Op Fl d +.Op Fl q +.Op Fl c Ar conf-file +.Sh DESCRIPTION +.Nm +monitors a set of PCMCIA slots for card change events, and acts on those +events. +It reads the configuration file specified with the +.Fl c +flag, or, if no file is specified, the default configuration file +.Pa /etc/pcmciad.conf . +.Pp +Each line of the configuration file contains a list of PCMCIA slot +device files to monitor and a command name for that slot. +Whenever a card event occurs on a monitored slot, pcmciad attempts to +configure (upon insertion) or unconfigure (upon removal) the card. If +the action succeeds, the slot's command is run, passed the slot number, +event type (insert or delete), and device type name. +.Pp +.Nm +announces card insertion/configuration/removal events on the speaker +(using the +.Pa /dev/speaker +device). A short high note announces a card insertion. A low note +followed by a high note indicates successful card configuration; a +single low note indicates an unknown card or configuration failure. A +high note followed by a low note indicates a card removal. +.Pp +When the +.Fl q +flag is specified, the card insertion/removal events are not announced +on the speaker. +.Sh SEE ALSO +.Xr pcmcia_cntrl 8 , +.Xr config_slot 8 , +.Xr speaker 4 . +.Sh HISTORY +The +.Nm pcmciad +command appeared in OpenBSD 1.1B. diff --git a/usr.sbin/pcmciad/pcmciad.c b/usr.sbin/pcmciad/pcmciad.c new file mode 100644 index 00000000000..b744928ca5b --- /dev/null +++ b/usr.sbin/pcmciad/pcmciad.c @@ -0,0 +1,459 @@ +/* $NetBSD$ */ +/* + * Copyright (c) 1995 John T. Kohl. All rights reserved. + * Copyright (c) 1993, 1994 Stefan Grefen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following dipclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by 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. + * + */ + +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/wait.h> +#include <syslog.h> +#include <signal.h> +#include <unistd.h> +#include <string.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <errno.h> +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmcia_ioctl.h> +#include "pathnames.h" + +#define PCMCIABUS_UNIT(a) (minor(a)) +#define PCMCIABUS_SLOT(a) (a&0x7) + +#define HAS_POWER(a) ISSET(a,PCMCIA_POWER) + +/* Macros to clear/set/test flags. */ +#define SET(t, f) (t) |= (f) +#define CLR(t, f) (t) &= ~(f) +#define ISSET(t, f) ((t) & (f)) + +extern const char *__progname; + +extern char *optarg; +extern int optind; +extern int optopt; +extern int opterr; +extern int optreset; + +const char conffile[] = _PATH_PCMCIA_CONF; + +enum speaker_tones { + SINGLE_HIGH, + SHORT_HIGH, + LOW_HIGH, + HIGH_LOW, + SINGLE_LOW +}; + + +void make_noise __P((enum speaker_tones)); +void child_death __P((int)); +void usage __P((void)); +void handle_fd __P((int fd)); + +extern int read_conf(u_char *buf, + int blen, + int cfidx, + struct pcmcia_conf *pc_cf); + +void +usage(void) +{ + fprintf(stderr,"usage: %s [-d] [-c configfile]\n", __progname); + exit(1); +} + +dev_t devices_opened[64]; /* XXX fixed size */ +int slot_status[64]; /* XXX fixed size */ + +int speaker_ok = 1; + +void /* XXX */ +main(int argc, + char *argv[]) +{ + int fd, ch, maxfd = 0, ready; + int debug = 0; + FILE *infile = NULL; + const char *fname = conffile; + char confline[128]; + fd_set sockets; + fd_set selcopy; + struct stat statb; + + while ((ch = getopt(argc, argv, "qdc:")) != -1) + switch(ch) { + case 'q': + speaker_ok = 0; + break; + case 'd': + debug = 1; + break; + case 'c': + fname = optarg; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if ((infile = fopen(fname, "r")) == NULL) { + (void)err(1, "cannot open config file `%s'", fname); + } + if (debug) { + openlog(__progname, LOG_CONS, LOG_LOCAL1); + } else { + openlog(__progname, LOG_CONS, LOG_DAEMON); + setlogmask(LOG_UPTO(LOG_NOTICE)); + daemon(0, 0); + } + syslog(LOG_DEBUG, "opened config file %s", fname); + FD_ZERO(&sockets); + while (fgets(confline, sizeof(confline), infile) != NULL) { + if (confline[strlen(confline)-1] == '\n') + confline[strlen(confline)-1] = '\0'; + fd = open(confline, O_RDWR); + if (fd != -1) { + struct pcmcia_status stbuf; + if (ioctl(fd, PCMCIAIO_GET_STATUS, &stbuf) < 0) { + syslog(LOG_ERR,"ioctl PCMCIAIO_GET_STATUS %s: %m", + confline); + close(fd); + } else { + FD_SET(fd, &sockets); + syslog(LOG_DEBUG, "%s is fd %d\n", confline, fd); + if (fstat(fd, &statb) == -1) { + syslog(LOG_ERR, "cannot fstat %s: %m", + confline); + (void) close(fd); + } else { + maxfd = MAX(fd, maxfd); + devices_opened[fd] = statb.st_rdev; + } + slot_status[fd] = ISSET(stbuf.status, + PCMCIA_CARD_PRESENT); + if (ISSET(stbuf.status, PCMCIA_CARD_INUSE)) + make_noise(LOW_HIGH); + else if (ISSET(stbuf.status, + PCMCIA_CARD_IS_MAPPED)) + make_noise(SINGLE_LOW); + else if (ISSET(stbuf.status, + PCMCIA_CARD_PRESENT)) + handle_fd(fd); + + } + } else + syslog(LOG_DEBUG, "%s: %m", confline); + } + fclose(infile); + + if (maxfd == 0) { + syslog(LOG_ERR, "no files to monitor"); + exit(1); + } + syslog(LOG_DEBUG, "maxfd = %d\n", maxfd); + + signal(SIGCHLD, child_death); + while (1) { + for (selcopy = sockets; + (ready = select(maxfd+1, 0, 0, &selcopy, 0)) > 0; + selcopy = sockets) { + register int i; + syslog(LOG_DEBUG, "%d ready descriptors\n", ready); + for (i = 0; ready && i <= maxfd; i++) { + if (FD_ISSET(i, &selcopy)) { + syslog(LOG_DEBUG, "fd %d is exceptionally ready\n", i); + /* sleep to let it settle */ + sleep(2); + ready--; + handle_fd(i); + } + } + } + if (ready == -1) { + if (errno != EINTR) + syslog(LOG_ERR, "select failed: %m"); + continue; + } else { + syslog(LOG_ERR, "leaving with ready == 0?"); + break; + } + } +} + +void +handle_fd(int fd) +{ + struct pcmcia_status stbuf; + struct pcmcia_info inbuf; + struct pcmcia_conf pc_cf; + int status; + int pw; + int first=1; + char manu[MAX_CIS_NAMELEN]; + char model[MAX_CIS_NAMELEN]; + char addinf1[MAX_CIS_NAMELEN]; + char addinf2[MAX_CIS_NAMELEN]; + char cmd[64]; + + if (ioctl(fd, PCMCIAIO_GET_STATUS, &stbuf) < 0) { + syslog(LOG_ERR,"ioctl PCMCIAIO_GET_STATUS: %m"); + return; + } + status = ISSET(stbuf.status, PCMCIA_CARD_PRESENT); + if (!status) { + syslog(LOG_INFO,"No card in slot %d\n",stbuf.slot); + if (ISSET(stbuf.status, PCMCIA_CARD_INUSE) || + ISSET(stbuf.status, PCMCIA_CARD_IS_MAPPED)) { + if (ioctl(fd, + ISSET(stbuf.status, PCMCIA_CARD_INUSE) ? + PCMCIAIO_UNCONFIGURE : PCMCIAIO_UNMAP, 0) < 0) + syslog(LOG_ERR, + "ioctl PCMCIAIO_UNCONFIGURE slot %d: %m", + stbuf.slot); + else { + if (status != slot_status[fd]) { + make_noise(HIGH_LOW); + } + } + slot_status[fd] = status; + if (ioctl(fd, PCMCIAIO_GET_STATUS, &stbuf) < 0) { + syslog(LOG_ERR, "ioctl PCMCIAIO_GET_STATUS: %m"); + make_noise(SINGLE_LOW); + return; + } + } else { + syslog(LOG_DEBUG,"Card in slot %d is not mapped\n", + stbuf.slot); + if (status != slot_status[fd]) { + make_noise(HIGH_LOW); + } + slot_status[fd] = status; + return; + } + if (ISSET(stbuf.status, PCMCIA_POWER)) { + pw = PCMCIASIO_POWER_OFF; + if (ioctl(fd, PCMCIAIO_SET_POWER, &pw) < 0) + syslog(LOG_ERR,"ioctl PCMCIAIO_SET_POWER slot %d: %m", + stbuf.slot); + } +#if 0 + sprintf(cmd, "/sbin/pcmcia_cntrl -f %d %d unmapforce", fd, + PCMCIABUS_SLOT(PCMCIABUS_UNIT(devices_opened[fd]))); +#endif + return; + } else { + if (status != slot_status[fd]) + make_noise(SHORT_HIGH); + if (ISSET(stbuf.status, PCMCIA_CARD_INUSE)) { + syslog(LOG_INFO, + "Card in slot %d is attached, can't probe it", + stbuf.slot); + /* make_noise(SINGLE_LOW); */ + return; + } + /* unmap the card to clean up. */ + if (ISSET(stbuf.status, PCMCIA_CARD_IS_MAPPED) && + ioctl(fd, PCMCIAIO_UNMAP, 0) == -1) { + syslog(LOG_NOTICE, + "cannot unmap card in slot %d: %m", stbuf.slot); + make_noise(SINGLE_LOW); + return; + } + +tryagain: + pw = PCMCIASIO_POWER_OFF; + if (ioctl(fd, PCMCIAIO_SET_POWER, &pw) == -1) { + syslog(LOG_ERR,"ioctl PCMCIAIO_SET_POWER slot %d: %m", + stbuf.slot); + make_noise(SINGLE_LOW); + return; + } + pw = PCMCIASIO_POWER_AUTO; + if (ioctl(fd, PCMCIAIO_SET_POWER, &pw) == -1) { + syslog(LOG_ERR,"ioctl PCMCIAIO_SET_POWER slot %d: %m", + stbuf.slot); + make_noise(SINGLE_LOW); + return; + } + if (ioctl(fd, PCMCIAIO_GET_INFO, &inbuf) < 0) + syslog(LOG_ERR, "ioctl PCMCIAIO_GETINFO: %m"); + else { + syslog(LOG_DEBUG, "config: %s", inbuf.cis_data); + } + memset(&pc_cf, 0, sizeof(pc_cf)); + if (pcmcia_get_cf(0, inbuf.cis_data, 512, CFGENTRYMASK, + &pc_cf)) { + syslog(LOG_ERR, "can't interpret config info"); + } else { + if (pcmcia_get_cisver1(0, (u_char *)&inbuf.cis_data, + 512, manu, model, addinf1, + addinf2) == 0) { + syslog(LOG_INFO,"<%s, %s, %s, %s>", + manu, model, addinf1, addinf2); + } else { + syslog(LOG_ERR, "can't get CIS info\n"); + if (first) { + first = 0; + goto tryagain; + } + } + } +#if 0 + sprintf(cmd, "/sbin/pcmcia_cntrl -f %d %d probe", fd, + PCMCIABUS_SLOT(PCMCIABUS_UNIT(devices_opened[fd]))); +#endif +#if 0 || 0 + if (ioctl(fd, PCMCIAIO_CONFIGURE, &pc_cf) == -1) { + syslog(LOG_ERR, "ioctl PCMCIAIO_CONFIGURE: %m"); + return; + } +#endif + memset(&pc_cf, 0, sizeof(pc_cf)); + if (ioctl(fd, PCMCIAIO_CONFIGURE, &pc_cf) == -1) { + syslog(LOG_ERR, "ioctl PCMCIAIO_CONFIGURE: %m"); + make_noise(SINGLE_LOW); + } else + if (status != slot_status[fd]) + make_noise(LOW_HIGH); + slot_status[fd] = status; + return; + } +#if 0 + syslog(LOG_DEBUG, "execing `%s'", cmd); + status = system(cmd); + if (status == -1) + syslog(LOG_ERR, "cannot run %s", cmd); + else if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) + syslog(LOG_ERR, + "%s returned %d\n", cmd, WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + syslog(LOG_ERR, + "%s died from signal %d", cmd, WTERMSIG(status)); + } + return; +#endif +} + +/* + * Insert/remove tones. We do the same tones as Wildboar (BSD/OS kit): + * + * single high note: suspend/resume (look at apmd instead) + * short high note: card insertion noticed + * low then high note: successful attach + * high then low note: card eject noticed + * single low note: unknown card or attach failure + * + * we do the sound via /dev/speaker. + */ + +const char *tone_string[] = { +/* SINGLE_HIGH*/"o4c", +/* SHORT_HIGH,*/"t240o4c", +/* LOW_HIGH,*/ "t180o2co4c", +/* HIGH_LOW,*/ "t180o4co2c", +/* SINGLE_LOW*/ "t180o2c" +}; + +void +make_noise(tones) + enum speaker_tones tones; +{ + pid_t pid; + int spkrfd; + int trycnt; + + if (!speaker_ok) /* don't bother after sticky errors */ + return; + + pid = fork(); + switch (pid) { + case -1: + syslog(LOG_ERR, "cannot fork for speaker tones: %m"); + return; + case 0: + /* child */ + for (trycnt = 0; trycnt < 3; trycnt++) { + spkrfd = open(_PATH_DEV_SPEAKER, O_WRONLY); + if (spkrfd == -1) { + switch (errno) { + case EBUSY: + usleep(1000000); + errno = EBUSY; + continue; + case ENOENT: + case ENODEV: + case ENXIO: + case EPERM: + case EACCES: + syslog(LOG_INFO, + "speaker device " _PATH_DEV_SPEAKER " unavailable: %m"); + exit(2); + break; + } + } else + break; + } + if (spkrfd == -1) { + syslog(LOG_WARNING, + "cannot open " _PATH_DEV_SPEAKER ": %m"); + exit(1); + } + syslog(LOG_DEBUG, + "sending %s to speaker\n", tone_string[tones]); + write (spkrfd, tone_string[tones], strlen(tone_string[tones])); + exit(0); + default: + /* parent */ + return; + } +} + +void +child_death(sig) + int sig; +{ + int status; + if (wait(&status) == -1) { + syslog(LOG_ERR, "wait error for signaled child: %m"); + return; + } + if (WEXITSTATUS(status) == 2) + speaker_ok = 0; +} diff --git a/usr.sbin/pcmciad/test.config b/usr.sbin/pcmciad/test.config new file mode 100644 index 00000000000..4d78866480e --- /dev/null +++ b/usr.sbin/pcmciad/test.config @@ -0,0 +1,2 @@ +/dev/pcmcia/slot0 +/dev/pcmcia/slot1 |