1 /* $OpenBSD: pcex.c,v 1.5 2024/06/01 00:48:16 aoyama Exp $ */ 2 3 /* 4 * Copyright (c) 2014 Kenji Aoyama. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * PC-9801 extension board slot direct access driver for LUNA-88K2. 21 */ 22 23 #include <sys/param.h> 24 #include <sys/systm.h> /* tsleep()/wakeup() */ 25 #include <sys/device.h> 26 #include <sys/ioctl.h> 27 28 #include <machine/autoconf.h> 29 #include <machine/board.h> /* PC_BASE */ 30 #include <machine/conf.h> 31 #include <machine/pcex.h> 32 33 #include <luna88k/cbus/cbusvar.h> 34 35 extern int hz; 36 37 #if 0 38 #define PCEX_DEBUG 39 #endif 40 41 /* autoconf stuff */ 42 int pcex_match(struct device *, void *, void *); 43 void pcex_attach(struct device *, struct device *, void *); 44 45 struct pcex_softc { 46 struct device sc_dev; 47 int intr_use[NCBUSISR]; 48 }; 49 50 const struct cfattach pcex_ca = { 51 sizeof(struct pcex_softc), pcex_match, pcex_attach 52 }; 53 54 struct cfdriver pcex_cd = { 55 NULL, "pcex", DV_DULL 56 }; 57 58 /* prototypes */ 59 int pcex_intr(void *); 60 int pcex_set_int(struct pcex_softc *, u_int); 61 int pcex_reset_int(struct pcex_softc *, u_int); 62 int pcex_wait_int(struct pcex_softc *, u_int); 63 64 int 65 pcex_match(struct device *parent, void *cf, void *aux) 66 { 67 struct cbus_attach_args *caa = aux; 68 69 if (strcmp(caa->ca_name, pcex_cd.cd_name)) 70 return 0; 71 72 return 1; 73 } 74 75 void 76 pcex_attach(struct device *parent, struct device *self, void *args) 77 { 78 struct pcex_softc *sc = (struct pcex_softc *)self; 79 int i; 80 81 for (i = 0; i < NCBUSISR; i++) 82 sc->intr_use[i] = 0; 83 84 printf("\n"); 85 return; 86 } 87 88 int 89 pcexopen(dev_t dev, int flag, int mode, struct proc *p) 90 { 91 switch (minor(dev)) { 92 case 0: /* memory area */ 93 case 1: /* I/O port area */ 94 return 0; 95 default: 96 return ENXIO; 97 } 98 } 99 100 int 101 pcexclose(dev_t dev, int flag, int mode, struct proc *p) 102 { 103 return (0); 104 } 105 106 paddr_t 107 pcexmmap(dev_t dev, off_t offset, int prot) 108 { 109 paddr_t cookie = -1; 110 111 switch (minor(dev)) { 112 case 0: /* memory area */ 113 if (offset >= 0 && offset < 0x1000000) 114 cookie = (paddr_t)(PCEXMEM_BASE + offset); 115 break; 116 case 1: /* I/O port area */ 117 if (offset >= 0 && offset < 0x10000) 118 cookie = (paddr_t)(PCEXIO_BASE + offset); 119 break; 120 default: 121 break; 122 } 123 124 return cookie; 125 } 126 127 int 128 pcexioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 129 { 130 struct pcex_softc *sc = NULL; 131 u_int level; 132 133 if (pcex_cd.cd_ndevs != 0) 134 sc = pcex_cd.cd_devs[0]; 135 if (sc == NULL) 136 return ENXIO; 137 138 level = *(u_int *)data; 139 140 switch(cmd) { 141 case PCEXSETLEVEL: 142 return pcex_set_int(sc, level); 143 144 case PCEXRESETLEVEL: 145 return pcex_reset_int(sc, level); 146 147 case PCEXWAITINT: 148 return pcex_wait_int(sc, level); 149 150 default: 151 return ENOTTY; 152 } 153 } 154 155 int 156 pcex_set_int(struct pcex_softc *sc, u_int level) 157 { 158 if (level > 6) 159 return EINVAL; 160 if (sc->intr_use[level] != 0) 161 return EINVAL; /* Duplicate */ 162 163 sc->intr_use[level] = 1; 164 cbus_isrlink(pcex_intr, &(sc->intr_use[level]), level, IPL_NET, 165 sc->sc_dev.dv_xname); 166 167 return 0; 168 } 169 170 int 171 pcex_reset_int(struct pcex_softc *sc, u_int level) 172 { 173 if (level > 6) 174 return EINVAL; 175 if (sc->intr_use[level] == 0) 176 return EINVAL; /* Not registered */ 177 178 sc->intr_use[level] = 0; 179 cbus_isrunlink(pcex_intr, level); 180 181 return 0; 182 } 183 184 int 185 pcex_wait_int(struct pcex_softc *sc, u_int level) 186 { 187 int ret; 188 189 if (level > 6) 190 return EINVAL; 191 if (sc->intr_use[level] == 0) 192 return EINVAL; /* Not registered */ 193 194 ret = tsleep_nsec(&(sc->intr_use[level]), PWAIT | PCATCH, "pcex", 195 SEC_TO_NSEC(1)); /* XXX 1 sec. */ 196 197 #ifdef PCEX_DEBUG 198 if (ret == EWOULDBLOCK) 199 printf("pcex_wait_int: timeout in tsleep_nsec\n"); 200 #endif 201 return ret; 202 } 203 204 int 205 pcex_intr(void *arg) 206 { 207 #ifdef PCEX_DEBUG 208 printf("pcex_intr: called, arg=%p\n", arg); 209 #endif 210 /* Just wakeup(9) for now */ 211 wakeup(arg); 212 213 return 1; 214 } 215