1 /* $OpenBSD: pcex.c,v 1.4 2019/10/08 13:14:49 cheloha 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 #define PCEXMEM_BASE PC_BASE 42 #define PCEXIO_BASE (PC_BASE + 0x1000000) 43 44 /* autoconf stuff */ 45 int pcex_match(struct device *, void *, void *); 46 void pcex_attach(struct device *, struct device *, void *); 47 48 struct pcex_softc { 49 struct device sc_dev; 50 int intr_use[NCBUSISR]; 51 }; 52 53 const struct cfattach pcex_ca = { 54 sizeof(struct pcex_softc), pcex_match, pcex_attach 55 }; 56 57 struct cfdriver pcex_cd = { 58 NULL, "pcex", DV_DULL 59 }; 60 61 /* prototypes */ 62 int pcex_intr(void *); 63 int pcex_set_int(struct pcex_softc *, u_int); 64 int pcex_reset_int(struct pcex_softc *, u_int); 65 int pcex_wait_int(struct pcex_softc *, u_int); 66 67 int 68 pcex_match(struct device *parent, void *cf, void *aux) 69 { 70 struct cbus_attach_args *caa = aux; 71 72 if (strcmp(caa->ca_name, pcex_cd.cd_name)) 73 return 0; 74 75 return 1; 76 } 77 78 void 79 pcex_attach(struct device *parent, struct device *self, void *args) 80 { 81 struct pcex_softc *sc = (struct pcex_softc *)self; 82 int i; 83 84 for (i = 0; i < NCBUSISR; i++) 85 sc->intr_use[i] = 0; 86 87 printf("\n"); 88 return; 89 } 90 91 int 92 pcexopen(dev_t dev, int flag, int mode, struct proc *p) 93 { 94 switch (minor(dev)) { 95 case 0: /* memory area */ 96 case 1: /* I/O port area */ 97 return 0; 98 default: 99 return ENXIO; 100 } 101 } 102 103 int 104 pcexclose(dev_t dev, int flag, int mode, struct proc *p) 105 { 106 return (0); 107 } 108 109 paddr_t 110 pcexmmap(dev_t dev, off_t offset, int prot) 111 { 112 paddr_t cookie = -1; 113 114 switch (minor(dev)) { 115 case 0: /* memory area */ 116 if (offset >= 0 && offset < 0x1000000) 117 cookie = (paddr_t)(PCEXMEM_BASE + offset); 118 break; 119 case 1: /* I/O port area */ 120 if (offset >= 0 && offset < 0x10000) 121 cookie = (paddr_t)(PCEXIO_BASE + offset); 122 break; 123 default: 124 break; 125 } 126 127 return cookie; 128 } 129 130 int 131 pcexioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 132 { 133 struct pcex_softc *sc = NULL; 134 u_int level; 135 136 if (pcex_cd.cd_ndevs != 0) 137 sc = pcex_cd.cd_devs[0]; 138 if (sc == NULL) 139 return ENXIO; 140 141 level = *(u_int *)data; 142 143 switch(cmd) { 144 case PCEXSETLEVEL: 145 return pcex_set_int(sc, level); 146 147 case PCEXRESETLEVEL: 148 return pcex_reset_int(sc, level); 149 150 case PCEXWAITINT: 151 return pcex_wait_int(sc, level); 152 153 default: 154 return ENOTTY; 155 } 156 } 157 158 int 159 pcex_set_int(struct pcex_softc *sc, u_int level) 160 { 161 if (level > 6) 162 return EINVAL; 163 if (sc->intr_use[level] != 0) 164 return EINVAL; /* Duplicate */ 165 166 sc->intr_use[level] = 1; 167 cbus_isrlink(pcex_intr, &(sc->intr_use[level]), level, IPL_NET, 168 sc->sc_dev.dv_xname); 169 170 return 0; 171 } 172 173 int 174 pcex_reset_int(struct pcex_softc *sc, u_int level) 175 { 176 if (level > 6) 177 return EINVAL; 178 if (sc->intr_use[level] == 0) 179 return EINVAL; /* Not registered */ 180 181 sc->intr_use[level] = 0; 182 cbus_isrunlink(pcex_intr, level); 183 184 return 0; 185 } 186 187 int 188 pcex_wait_int(struct pcex_softc *sc, u_int level) 189 { 190 int ret; 191 192 if (level > 6) 193 return EINVAL; 194 if (sc->intr_use[level] == 0) 195 return EINVAL; /* Not registered */ 196 197 ret = tsleep_nsec(&(sc->intr_use[level]), PWAIT | PCATCH, "pcex", 198 SEC_TO_NSEC(1)); /* XXX 1 sec. */ 199 200 #ifdef PCEX_DEBUG 201 if (ret == EWOULDBLOCK) 202 printf("pcex_wait_int: timeout in tsleep_nsec\n"); 203 #endif 204 return ret; 205 } 206 207 int 208 pcex_intr(void *arg) 209 { 210 #ifdef PCEX_DEBUG 211 printf("pcex_intr: called, arg=%p\n", arg); 212 #endif 213 /* Just wakeup(9) for now */ 214 wakeup(arg); 215 216 return 1; 217 } 218