xref: /openbsd/sys/arch/luna88k/cbus/pcex.c (revision 4fb9ab68)
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