From: hvozda Date: Mon, 29 Apr 1996 13:05:58 +0000 (+0000) Subject: Pull in John Kohl's most recent (15Apr96) APM and PCMCIA work X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=054c7b81f2087f56abf9a6bf444e741b73878339;p=openbsd Pull in John Kohl's most recent (15Apr96) APM and PCMCIA work (original PCMCIA framework by Stefan Grefen). --- diff --git a/etc/etc.i386/MAKEDEV b/etc/etc.i386/MAKEDEV index cafbfe5823e..af017912829 100644 --- a/etc/etc.i386/MAKEDEV +++ b/etc/etc.i386/MAKEDEV @@ -73,6 +73,7 @@ # speaker pc speaker (XXX - installed) # lkm loadable kernel modules interface # audio audio device +# apm power management device # tun* network tunnel driver # joy* joystick driver # pcmcia* PCMCIA card drivers @@ -89,7 +90,7 @@ all) sh MAKEDEV st0 st1 ch0 cd0 cd1 mcd0 vnd0 vnd1 lpa0 lpa1 sh MAKEDEV ccd0 ccd1 ccd2 ccd3 sh MAKEDEV lpt0 lpt1 lpt2 ttyv0 bpf0 bpf1 bpf2 bpf3 ipl tun0 tun1 tun2 - sh MAKEDEV speaker lkm mms0 lms0 pms0 audio joy0 joy1 local + sh MAKEDEV speaker lkm mms0 lms0 pms0 audio joy0 joy1 apm pcmcia local # MISSING: # sh MAKEDEV mouse-? ;; @@ -374,7 +375,7 @@ pcmcia*) chmod 700 pcmcia chmod 600 pcmcia/* ;; - + joy*) unit=`expr $i : 'joy\(.*\)'` rm -f joy$unit @@ -382,6 +383,46 @@ joy*) chown root.wheel joy$unit chmod 666 joy$unit ;; + +apm*) + rm -f apm apmctl + mknod apm c 21 0 + mknod apmctl c 21 8 + chown root.wheel apm apmctl + chmod 644 apm apmctl + ;; + +pcmcia*) + rm -f pcmcia/bus? pcmcia/chip? pcmcia/slot* + mkdir -p pcmcia + mknod pcmcia/bus0 c 26 128 + mknod pcmcia/bus1 c 26 129 + mknod pcmcia/bus2 c 26 130 + mknod pcmcia/bus3 c 26 131 + mknod pcmcia/chip0 c 26 64 + mknod pcmcia/chip1 c 26 65 + mknod pcmcia/chip2 c 26 66 + mknod pcmcia/chip3 c 26 67 + mknod pcmcia/slot0 c 26 0 + mknod pcmcia/slot1 c 26 1 + mknod pcmcia/slot2 c 26 2 + mknod pcmcia/slot3 c 26 3 + mknod pcmcia/slot4 c 26 4 + mknod pcmcia/slot5 c 26 5 + mknod pcmcia/slot6 c 26 6 + mknod pcmcia/slot7 c 26 7 + mknod pcmcia/slot8 c 26 8 + mknod pcmcia/slot9 c 26 9 + mknod pcmcia/slot10 c 26 10 + mknod pcmcia/slot11 c 26 11 + mknod pcmcia/slot12 c 26 12 + mknod pcmcia/slot13 c 26 13 + mknod pcmcia/slot14 c 26 14 + mknod pcmcia/slot15 c 26 15 + chown -R root.wheel pcmcia + chmod 700 pcmcia + chmod 600 pcmcia/* + ;; local) umask 0 diff --git a/sbin/Makefile b/sbin/Makefile index 3c87a070c83..1b8b46a7875 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.5 1996/04/22 20:21:52 hannken Exp $ +# $OpenBSD: Makefile,v 1.6 1996/04/29 13:07:00 hvozda Exp $ # $NetBSD: Makefile,v 1.28 1996/04/05 01:44:24 cgd Exp $ # @(#)Makefile 8.5 (Berkeley) 3/31/94 @@ -27,9 +27,11 @@ SUBDIR+= mount_umap SUBDIR+= mount_union .if make(clean) || make(cleandir) -SUBDIR+= bim edlabel fdisk +SUBDIR+= bim config_slot edlabel fdisk pcmcia_cntrl .elif ${MACHINE} == "i386" +SUBDIR+= config_slot SUBDIR+= fdisk +SUBDIR+= pcmcia_cntrl .elif ${MACHINE} == "pc532" SUBDIR+= bim .elif ${MACHINE} == "sun3" diff --git a/sbin/config_slot/Makefile b/sbin/config_slot/Makefile new file mode 100644 index 00000000000..74e14e35e1f --- /dev/null +++ b/sbin/config_slot/Makefile @@ -0,0 +1,15 @@ +# $Id: Makefile,v 1.1 1996/04/29 13:07:01 hvozda Exp $ + +SRCS = config_slot.c pcmcia_conf.c +VPATH = ${.CURDIR}/../../sys/dev/pcmcia +#dumpreg.c + +CFLAGS+= -g -O2 -Wmissing-prototypes -I${.CURDIR}/../../sys +PROG=config_slot +NOMAN= + +pcmcia_conf.o: pcmcia_conf.c + $(CC) $(CFLAGS) -D_KERNEL -c $< + +.include +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/sbin/config_slot/config_slot.c b/sbin/config_slot/config_slot.c new file mode 100644 index 00000000000..a24c387eff9 --- /dev/null +++ b/sbin/config_slot/config_slot.c @@ -0,0 +1,233 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +void parse_device(u_char *, int, int); +void parse_ver1(u_char *, int, int); +void parse_config(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); +int dumpcf(struct pcmcia_conf *pc_cf); +void usage(void); +int readiowin(char **argv,struct iowin *io); +void dcp(char **argv,char *target); +void parse_cmdline(int argc,char **argv,struct pcmcia_conf *pc_cf); + +int iowins=0; + +dumpcf(struct pcmcia_conf *pc_cf) { + int i; + static char *ios[]= { + "auto","8bit","16bit","illegal" + }; + printf("Driver name '%s'\n",pc_cf->driver_name); + printf("CFG offset %x\n",pc_cf->cfg_off ); + printf("IRQ type %s\n",pc_cf->irq_level?"Level":pc_cf->irq_pulse?"Pulse":"None"); + printf("CFG Entry %x %s\n",pc_cf->cfgtype,pc_cf->cfgtype&DOSRESET?"dosreset":""); + printf("IRQ num %x\n",pc_cf->irq_num&0xf); + printf("Cardtype %s\n",pc_cf->iocard?"IO":"MEM"); + for (i=0;iiowin;i++) { + printf("iowin %x-%x %s\n",pc_cf->io[i].start, + pc_cf->io[i].start+pc_cf->io[i].len-1, + ios[(pc_cf->io[i].flags&(PCMCIA_MAP_8|PCMCIA_MAP_16))>>8]); + } + for (i=0;imemwin;i++) { + printf("memwin (%x)%x-%x %x\n", + pc_cf->mem[i].caddr, + pc_cf->mem[i].start, + pc_cf->mem[i].start+pc_cf->mem[i].len-1, + pc_cf->mem[i].flags); + } +} + +void +usage(void) { + fprintf(stderr,"usage: config_slot [driver name][iocard]\\\n"); + fprintf(stderr," [irq num][lirq][iowin start len width]\n"); + fprintf(stderr," [** not yet memwin start offs len width]\n"); +} + + +main(int argc,char **argv) { + char namebuf[64]; + struct pcmcia_status stbuf; + struct pcmcia_info inbuf; + struct pcmcia_conf pc_cf; + char manu[MAX_CIS_NAMELEN]; + char model[MAX_CIS_NAMELEN]; + char addinf1[MAX_CIS_NAMELEN]; + char addinf2[MAX_CIS_NAMELEN]; + int sockid; + int fd,cfg; + + if(argc<2 || !isdigit(argv[1][0])) { + usage(); + exit(1); + } + + sockid=atoi(argv[1]); + + bzero(pc_cf,sizeof(pc_cf)); + + argc-=2;argv+=2; + sprintf(namebuf,"/dev/pcmcia/slot%d",sockid); + + if((fd=open(namebuf,O_RDWR))<0) { + printf("errno %d\n",errno); + perror("open"); + exit(1); + } + if(ioctl(fd,PCMCIAIO_GET_STATUS,&stbuf)<0) { + printf("errno %d\n",errno); + perror("ioctl PCMCIAIO_GET_STATUS"); + exit(1); + } + 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(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_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); + } + /*dbuf(inbuf.cis_data,512);/**/ + bzero(&pc_cf,sizeof(pc_cf)); + /*parse_cmdline(argc,argv,&pc_cf);/**/ + printf("* %x\n",pc_cf.cfgtype); + cfg=pc_cf.cfgtype&CFGENTRYMASK; + if(pcmcia_get_cf(0, inbuf.cis_data,512,CFGENTRYMASK,&pc_cf)) { + fprintf(stderr,"read_conf failed\n"); + exit(1); + } + if(pc_cf.cfgtype&CFGENTRYID) { + if(pcmcia_get_cf(0, inbuf.cis_data,512,cfg,&pc_cf)) { + fprintf(stderr,"read_conf failed\n"); + exit(1); + } + } + parse_cmdline(argc,argv,&pc_cf); + if(iowins && pc_cf.iowin!=iowins) { + pc_cf.iowin=iowins; + } + dumpcf(&pc_cf); + if (pcmcia_get_cisver1(0, (u_char *)&inbuf.cis_data, 512, + manu, model, addinf1, addinf2) == 0) { + printf(" <%s, %s", manu, model); + if (addinf1[0]) + printf(", %s", addinf1); + if (addinf2[0]) + printf(", %s", addinf2); + printf(">\n"); + } + printf("PCMCIAIO_CONFIGURE==%x\n",PCMCIAIO_CONFIGURE); + if(ioctl(fd,PCMCIAIO_CONFIGURE,&pc_cf)<0) { + printf("errno %d\n",errno); + perror("ioctl PCMCIAIO_CONFIGURE"); + exit(1); + } + + exit(0); + +} +#define OPT_ARG(opt,arg,func) if(argc>1 && !strcmp(argv[0],opt)) { \ + arg=func(argv[1]); argv+=2;argc-=2 ;continue;} +#define OPT(opt,arg) if(!strcmp(argv[0],opt)) { \ + arg=1; argv++;argc-- ;continue;} +#define OPTOV_ARG(opt,op,func,arg) if(!strcmp(argv[0],opt)) { \ + arg op func(argv[1]); argv+=2;argc-=2 ;continue;} +#define OPTOV(opt,op,val,arg) if(!strcmp(argv[0],opt)) { \ + arg op val; argv++;argc-- ;continue;} +#define OPT_ARGN(opt,n,arg,func) if(argc>n && !strcmp(argv[0],opt)) { \ + func(&argv[1],&(arg)); argv+=n+1;argc-=n+1 ;continue;} +readiowin(char **argv,struct iowin *io) { + io->start=strtol(argv[0],NULL,0); + io->len=strtol(argv[1],NULL,0); + if(!strcmp(argv[2],"auto")) { + io->flags=0; + } else if(!strcmp(argv[2],"8bit")) { + io->flags=PCMCIA_MAP_8; + } else if(!strcmp(argv[2],"16bit")) { + io->flags=PCMCIA_MAP_16; + } +} + +void +dcp(char **argv,char *target) { + strcpy(target,argv[0]); +} + +void +parse_cmdline(int argc,char **argv,struct pcmcia_conf *pc_cf) { + int memwin=0; + while(argc>0) { + OPT_ARG("irq", pc_cf->irq_num,atoi); + OPT_ARGN("iowin",3,pc_cf->io[iowins++],readiowin); + /*OPT_ARGN("-memwin",4,pc_cf->mem,readmem,win);/**/ + OPT("pirq", pc_cf->irq_pulse); + OPT("lirq", pc_cf->irq_level); + OPT("iocard", pc_cf->iocard); + OPTOV("dosreset", |= ,DOSRESET,pc_cf->cfgtype); + OPTOV_ARG("configid",|= CFGENTRYID |,atoi,pc_cf->cfgtype); + OPT_ARGN("driver",1, pc_cf->driver_name[0][0],dcp); + printf("illegal option '%s'\n",argv[0]); + argc--;argv++; + } +} diff --git a/sbin/config_slot/read_conf.c b/sbin/config_slot/read_conf.c new file mode 100644 index 00000000000..9e4a60cb569 --- /dev/null +++ b/sbin/config_slot/read_conf.c @@ -0,0 +1,288 @@ +/* + * 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. + */ +/* With 'help' of Barry Jaspan's code */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +read_conf(u_char *buf, int blen,int cfidx,struct pcmcia_conf *pc_cf) +{ + u_char code, len,*tbuf,*endp=buf+blen; + int done; + + done = 0; + while (!done && buf> TPCC_RASZ_SHIFT; + rmsz = (tbuf[i] & TPCC_RMSZ) >> TPCC_RMSZ_SHIFT; + + i+=2; + pc_cf->cfg_off = 0; + switch (rasz) { + case 3: + pc_cf->cfg_off |= (tbuf[i+3] << 24); + case 2: + pc_cf->cfg_off |= (tbuf[i+2] << 16); + case 1: + pc_cf->cfg_off |= (tbuf[i+1] << 8); + case 0: + pc_cf->cfg_off |= tbuf[i]; + } + i+=rasz; + pc_cf->cfg_regmask = 0; + switch (rmsz) { + default: + case 3: + pc_cf->cfg_regmask |= (tbuf[i+3] << 24); + case 2: + pc_cf->cfg_regmask |= (tbuf[i+2] << 16); + case 1: + pc_cf->cfg_regmask |= (tbuf[i+1] << 8); + case 0: + pc_cf->cfg_regmask |= tbuf[i]; + } + +} + +parse_cfent(u_char *tbuf, int len,int slotid, struct pcmcia_conf *pc_cf) +{ + int i, idx,defp,iop,io_16,ios,ftrs,intface,k; + int host_addr_p, addr_size, len_size; + + i = 0; + intface = (tbuf[i] & TPCE_INDX_INT); + idx = (tbuf[i] & TPCE_INDX_ENTRY); + defp = (tbuf[i] & TPCE_INDX_DEF); + printf("%x %x\n",idx,slotid); + if((idx==slotid) ||(defp && slotid==-1)) { + int j; + printf("** %x %x\n",idx,slotid); + if (intface) { + i++; + pc_cf->iocard=(tbuf[i] & TPCE_IF_TYPE)==1; + } + + i++; + ftrs = tbuf[i++]; + for (j = 0; j < (ftrs & TPCE_FS_PWR); j++) { + int pwr_desc = tbuf[i++]; + /* for each struct, skip all parameter defns */ + for (k = 0; k < 8; pwr_desc >>= 1, k++) { + if (pwr_desc & 0x01) { + /* skip bytes until non-ext found */ + while (tbuf[i++] & 0x80) + ; + } + } + } + + if (ftrs & TPCE_FS_TD) { + i++; + } + + if (ftrs & TPCE_FS_IO) { + int io_addrs[16],io_lens[16]; + int io_16,io_block_len, io_block_size; + iop = 1; + io_16 = tbuf[i] & TPCE_FS_IO_BUS16; + i++; + ios--; /*TMPFIX*/; + 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; + i++; + 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; + } + pc_cf->io[j].start=io_addrs[j]; + 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]++; /*TMPFIX*/; + pc_cf->io[j].len=io_lens[j]; + pc_cf->io[j].flags=io_16?PCMCIA_MAP_16:PCMCIA_MAP_8; + i += io_block_len + (io_block_len == 3 ? 1 + : 0); + + } + pc_cf->iowin=ios; + } + + if (ftrs & TPCE_FS_IRQ) { + int irq_mask,irqp,irq; + pc_cf->irq_level=!!(tbuf[i] & TPCE_FS_IRQ_LEVEL); + pc_cf->irq_pulse=!!(tbuf[i] & TPCE_FS_IRQ_PULSE); + pc_cf->irq_share=!!(tbuf[i] & TPCE_FS_IRQ_SHARE); + if (tbuf[i] & TPCE_FS_IRQ_MASK) { + irq_mask = (tbuf[i+2] << 8) + tbuf[i+1]; + i += 2; + } else { + pc_cf->irq_num = tbuf[i] & TPCE_FS_IRQ_IRQN; + } + + 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; + + 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; + 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; + + } + } + } + } +} + + + + diff --git a/sbin/pcmcia_cntrl/Makefile b/sbin/pcmcia_cntrl/Makefile new file mode 100644 index 00000000000..a231297e9ae --- /dev/null +++ b/sbin/pcmcia_cntrl/Makefile @@ -0,0 +1,9 @@ +# $Id: Makefile,v 1.1 1996/04/29 13:07:04 hvozda Exp $ + +SRCS = pcmcia_cntrl.c + +CFLAGS += -g +PROG=pcmcia_cntrl + +.include +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/sbin/pcmcia_cntrl/pcmcia_cntrl.1 b/sbin/pcmcia_cntrl/pcmcia_cntrl.1 new file mode 100644 index 00000000000..0ad4cadae2d --- /dev/null +++ b/sbin/pcmcia_cntrl/pcmcia_cntrl.1 @@ -0,0 +1,77 @@ +.\" Copyright (c) 1994 Stefan Grefen +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" 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. +.\" +.\" from: @(#)pwd.1 6.5 (Berkeley) 6/27/91 +.\" $Id: pcmcia_cntrl.1,v 1.1 1996/04/29 13:07:04 hvozda Exp $ +.\" +.Dd May 31, 1994 +.Dt PWD 1 +.Os BSD 4 +.Sh NAME +.Nm pcmcia_cntrl +.Nd Change the status of a pcmcia slot +.Sh SYNOPSIS +.Nm pcmcia_cntrl +.Ar slotid +.Op on | off | unmap | probe +.Sh DESCRIPTION +.Nm Pcmcia_cntrl +controls the operation of a PCMCIA card. It operates on the card in slot +.Ar slotid . +\. +.Pp +The options are as follows: +.Bl -tag -width flag +.It Fl on +Turns power on +.It Fl off +Turns power off +.It Fl unmap +Unmaps and unconfigures a active card (not all drivers may support this). +.It Fl probe +Probes and attaches the card found in the slot. Works only for devices that +have kernel support for mapping. +Use config_slot for other devices. +.El +.Pp +If an error occurs, +.Nm pcmcia_cntrl +exits with a value >0. +.Sh SEE ALSO +.Xr config_slot 1 , +.Xr pcmcia 4 +.Sh BUGS +To numerous to mention. + + diff --git a/sbin/pcmcia_cntrl/pcmcia_cntrl.c b/sbin/pcmcia_cntrl/pcmcia_cntrl.c new file mode 100644 index 00000000000..e01e754177b --- /dev/null +++ b/sbin/pcmcia_cntrl/pcmcia_cntrl.c @@ -0,0 +1,165 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#define HAS_POWER(a) (!!(a&(PCMCIA_POWER))) + +void +usage(void) { + fprintf(stderr,"usage: pcmcia_cntrl [-f fd] on|off|unmap|unconf|probe\n"); +} + +main(int argc,char **argv) { + int fd = -1; + char namebuf[64]; + int sockid; + struct pcmcia_status stbuf; + struct pcmcia_info inbuf; + int onoff=-1; + int unmap=-1; + int unconf=-1; + int probe=-1; + int force=-1; + + if (argv[1] && strcmp(argv[1], "-f") == 0 && + argv[2]) { + fd = atoi(argv[2]); + argv += 2; + argc -= 2; + } + + if(argc!=3 || !isdigit(argv[1][0])) { + usage(); + exit(1); + } + sockid=atoi(argv[1]); + + + if(!strcmp(argv[2],"on")) { + onoff=1; + } else if(!strcmp(argv[2],"off")) { + onoff=0; + } else if(!strcmp(argv[2],"unconf")) { + unmap=1; + unconf=1; + } else if(!strcmp(argv[2],"unconfforce")) { + unmap=1; + unconf=1; + force=1; + } else if(!strcmp(argv[2],"unmap")) { + unmap=1; + } else if(!strcmp(argv[2],"probe")) { + probe=1; + } else { + usage(); + exit(1); + } + + sprintf(namebuf,"/dev/pcmcia/slot%d",sockid); + + if (fd == -1 && (fd=open(namebuf,O_RDWR))<0) { + perror("open"); + exit(1); + } + if(ioctl(fd,PCMCIAIO_GET_STATUS,&stbuf)<0) { + perror("ioctl PCMCIAIO_GET_STATUS"); + exit(1); + } + if(!(stbuf.status&PCMCIA_CARD_PRESENT) && force < 0) { + fprintf(stderr,"No card in slot %d\n",stbuf.slot); + exit(1); + } + if(onoff>=0) { + if(stbuf.status&PCMCIA_CARD_IS_MAPPED) { + fprintf(stderr,"Card in slot %d is mapped, can't turn it %s\n",stbuf.slot,onoff?"on":"off"); + exit(1); + } + if((HAS_POWER(stbuf.status&PCMCIA_POWER))^(!!onoff)) { + int pw=onoff?PCMCIASIO_POWER_5V:PCMCIASIO_POWER_OFF; + printf("Card in slot %d power %s\n",stbuf.slot,onoff?"on":"off" ); + if(ioctl(fd,PCMCIAIO_SET_POWER,&pw)<0) { + printf("errno %d\n",errno); + perror("ioctl PCMCIAIO_SET_POWER"); + exit(1); + } + /*exit(1);/**/ + } + } + if (unconf >= 0) { + int o; + if(!(stbuf.status&PCMCIA_CARD_IS_MAPPED)) { + fprintf(stderr,"Card in slot %d is not mapped\n",stbuf.slot); + exit(1); + } + if(ioctl(fd,PCMCIAIO_UNCONFIGURE,0)<0) { + perror("ioctl PCMCIAIO_UNCONFIGURE"); + exit(1); + } + } + if (unmap >= 0) { + if (!unconf && (stbuf.status&PCMCIA_CARD_INUSE)) { + fprintf(stderr, "Card in slot %d is configured--unconfigure before unmapping.\n", stbuf.slot); + exit(1); + } + if(!(stbuf.status&PCMCIA_CARD_IS_MAPPED)) { + fprintf(stderr,"Card in slot %d is not mapped\n",stbuf.slot); + exit(1); + } + if(ioctl(fd,PCMCIAIO_UNMAP,0)<0) { + perror("ioctl PCMCIAIO_UNMAP"); + exit(1); + } + } + if(probe>=0) { + struct pcmcia_conf pc_cf; + if(stbuf.status&PCMCIA_CARD_IS_MAPPED) { + fprintf(stderr,"Card in slot %d is mapped, can't probe it\n", + stbuf.slot); + exit(1); + } + bzero(pc_cf,sizeof(pc_cf)); + if(ioctl(fd,PCMCIAIO_CONFIGURE,&pc_cf)<0) { + perror("ioctl PCMCIAIO_CONFIGURE"); + exit(1); + } + } + exit(0); +} + 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 +# 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +# 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +.include +# 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 +# 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 +#include +#include +#include +#include + +#include +#include +#include +#include + + +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 +# 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +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;i126?'.':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 +# 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 +#include +#include +#include +#include + +#include +#include +#include +#include + + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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