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
pcex_match(struct device * parent,void * cf,void * aux)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
pcex_attach(struct device * parent,struct device * self,void * args)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
pcexopen(dev_t dev,int flag,int mode,struct proc * p)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
pcexclose(dev_t dev,int flag,int mode,struct proc * p)101 pcexclose(dev_t dev, int flag, int mode, struct proc *p)
102 {
103 return (0);
104 }
105
106 paddr_t
pcexmmap(dev_t dev,off_t offset,int prot)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
pcexioctl(dev_t dev,u_long cmd,caddr_t data,int flags,struct proc * p)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
pcex_set_int(struct pcex_softc * sc,u_int level)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
pcex_reset_int(struct pcex_softc * sc,u_int level)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
pcex_wait_int(struct pcex_softc * sc,u_int level)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
pcex_intr(void * arg)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