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