xref: /netbsd-src/sys/dev/qbus/dl.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: dl.c,v 1.39 2007/11/19 18:51:49 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1997  Ben Harris.  All rights reserved.
41  * Copyright (c) 1982, 1986, 1990, 1992, 1993
42  *	The Regents of the University of California.  All rights reserved.
43  *
44  * This code is derived from software contributed to Berkeley by
45  * Ralph Campbell and Rick Macklem.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions
49  * are met:
50  * 1. Redistributions of source code must retain the above copyright
51  *    notice, this list of conditions and the following disclaimer.
52  * 2. Redistributions in binary form must reproduce the above copyright
53  *    notice, this list of conditions and the following disclaimer in the
54  *    documentation and/or other materials provided with the distribution.
55  * 3. Neither the name of the University nor the names of its contributors
56  *    may be used to endorse or promote products derived from this software
57  *    without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69  * SUCH DAMAGE.
70  */
71 
72 /*
73  * Copyright (c) 1996  Ken C. Wellsch.  All rights reserved.
74  *
75  * This code is derived from software contributed to Berkeley by
76  * Ralph Campbell and Rick Macklem.
77  *
78  * Redistribution and use in source and binary forms, with or without
79  * modification, are permitted provided that the following conditions
80  * are met:
81  * 1. Redistributions of source code must retain the above copyright
82  *    notice, this list of conditions and the following disclaimer.
83  * 2. Redistributions in binary form must reproduce the above copyright
84  *    notice, this list of conditions and the following disclaimer in the
85  *    documentation and/or other materials provided with the distribution.
86  * 3. All advertising materials mentioning features or use of this software
87  *    must display the following acknowledgement:
88  *	This product includes software developed by the University of
89  *	California, Berkeley and its contributors.
90  * 4. Neither the name of the University nor the names of its contributors
91  *    may be used to endorse or promote products derived from this software
92  *    without specific prior written permission.
93  *
94  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
95  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
96  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
97  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
98  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
99  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
100  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
101  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
102  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
103  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
104  * SUCH DAMAGE.
105  */
106 
107 /*
108  * dl.c -- Device driver for the DL11 and DLV11 serial cards.
109  *
110  * OS-interface code derived from the dz and dca (hp300) drivers.
111  */
112 
113 #include <sys/cdefs.h>
114 __KERNEL_RCSID(0, "$NetBSD: dl.c,v 1.39 2007/11/19 18:51:49 ad Exp $");
115 
116 #include <sys/param.h>
117 #include <sys/systm.h>
118 #include <sys/ioctl.h>
119 #include <sys/tty.h>
120 #include <sys/proc.h>
121 #include <sys/buf.h>
122 #include <sys/conf.h>
123 #include <sys/file.h>
124 #include <sys/uio.h>
125 #include <sys/kernel.h>
126 #include <sys/syslog.h>
127 #include <sys/device.h>
128 #include <sys/kauth.h>
129 
130 #include <sys/bus.h>
131 
132 #include <dev/qbus/ubavar.h>
133 
134 #include <dev/qbus/dlreg.h>
135 
136 #include "ioconf.h"
137 
138 struct dl_softc {
139 	struct device	sc_dev;
140 	struct evcnt	sc_rintrcnt;
141 	struct evcnt	sc_tintrcnt;
142 	bus_space_tag_t	sc_iot;
143 	bus_space_handle_t sc_ioh;
144 	struct tty	*sc_tty;
145 };
146 
147 static	int	dl_match (struct device *, struct cfdata *, void *);
148 static	void	dl_attach (struct device *, struct device *, void *);
149 static	void	dlrint (void *);
150 static	void	dlxint (void *);
151 static	void	dlstart (struct tty *);
152 static	int	dlparam (struct tty *, struct termios *);
153 static	void	dlbrk (struct dl_softc *, int);
154 
155 CFATTACH_DECL(dl, sizeof(struct dl_softc),
156     dl_match, dl_attach, NULL, NULL);
157 
158 dev_type_open(dlopen);
159 dev_type_close(dlclose);
160 dev_type_read(dlread);
161 dev_type_write(dlwrite);
162 dev_type_ioctl(dlioctl);
163 dev_type_stop(dlstop);
164 dev_type_tty(dltty);
165 dev_type_poll(dlpoll);
166 
167 const struct cdevsw dl_cdevsw = {
168 	dlopen, dlclose, dlread, dlwrite, dlioctl,
169 	dlstop, dltty, dlpoll, nommap, ttykqfilter, D_TTY
170 };
171 
172 #define	DL_READ_WORD(reg) \
173 	bus_space_read_2(sc->sc_iot, sc->sc_ioh, reg)
174 #define	DL_WRITE_WORD(reg, val) \
175 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, reg, val)
176 #define	DL_WRITE_BYTE(reg, val) \
177 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val)
178 
179 /* Autoconfig handles: setup the controller to interrupt, */
180 /* then complete the housecleaning for full operation */
181 
182 static int
183 dl_match (struct device *parent, struct cfdata *cf, void *aux)
184 {
185 	struct uba_attach_args *ua = aux;
186 
187 #ifdef DL_DEBUG
188 	printf("Probing for dl at %lo ... ", (long)ua->ua_iaddr);
189 #endif
190 
191 	bus_space_write_2(ua->ua_iot, ua->ua_ioh, DL_UBA_XCSR, DL_XCSR_TXIE);
192 	if (bus_space_read_2(ua->ua_iot, ua->ua_ioh, DL_UBA_XCSR) !=
193 	    (DL_XCSR_TXIE | DL_XCSR_TX_READY)) {
194 #ifdef DL_DEBUG
195 		printf("failed (step 1; XCSR = %.4b)\n",
196 		    bus_space_read_2(ua->ua_iot, ua->ua_ioh, DL_UBA_XCSR),
197 		    DL_XCSR_BITS);
198 #endif
199 		return 0;
200 	}
201 
202 	/*
203 	 * We have to force an interrupt so the uba driver can work
204 	 * out where we are.  Unfortunately, the only way to make a
205 	 * DL11 interrupt is to get it to send or receive a
206 	 * character.  We'll send a NUL and hope it doesn't hurt
207 	 * anything.
208 	 */
209 
210 	bus_space_write_1(ua->ua_iot, ua->ua_ioh, DL_UBA_XBUFL, '\0');
211 #if 0 /* This test seems to fail 2/3 of the time :-( */
212 	if (dladdr->dl_xcsr != (DL_XCSR_TXIE)) {
213 #ifdef DL_DEBUG
214 		printf("failed (step 2; XCSR = %.4b)\n", dladdr->dl_xcsr,
215 		    DL_XCSR_BITS);
216 #endif
217 		return 0;
218 	}
219 #endif
220 	DELAY(100000); /* delay 1/10 s for character to transmit */
221 	if (bus_space_read_2(ua->ua_iot, ua->ua_ioh, DL_UBA_XCSR) !=
222 	    (DL_XCSR_TXIE | DL_XCSR_TX_READY)) {
223 #ifdef DL_DEBUG
224 		printf("failed (step 3; XCSR = %.4b)\n",
225 		    bus_space_read_2(ua->ua_iot, ua->ua_ioh, DL_UBA_XCSR),
226 		    DL_XCSR_BITS);
227 #endif
228 		return 0;
229 	}
230 
231 
232 	/* What else do I need to do? */
233 
234 	return 1;
235 
236 }
237 
238 static void
239 dl_attach (struct device *parent, struct device *self, void *aux)
240 {
241 	struct dl_softc *sc = device_private(self);
242 	struct uba_attach_args *ua = aux;
243 
244 	sc->sc_iot = ua->ua_iot;
245 	sc->sc_ioh = ua->ua_ioh;
246 
247 	/* Tidy up the device */
248 
249 	DL_WRITE_WORD(DL_UBA_RCSR, DL_RCSR_RXIE);
250 	DL_WRITE_WORD(DL_UBA_XCSR, DL_XCSR_TXIE);
251 
252 	/* Initialize our softc structure. Should be done in open? */
253 
254 	sc->sc_tty = ttymalloc();
255 	tty_attach(sc->sc_tty);
256 
257 	/* Now register the TX & RX interrupt handlers */
258 	uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
259 		dlxint, sc, &sc->sc_tintrcnt);
260 	uba_intr_establish(ua->ua_icookie, ua->ua_cvec - 4,
261 		dlrint, sc, &sc->sc_rintrcnt);
262 	evcnt_attach_dynamic(&sc->sc_rintrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
263 		sc->sc_dev.dv_xname, "rintr");
264 	evcnt_attach_dynamic(&sc->sc_tintrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
265 		sc->sc_dev.dv_xname, "tintr");
266 
267 	printf("\n");
268 }
269 
270 /* Receiver Interrupt Handler */
271 
272 static void
273 dlrint(void *arg)
274 {
275 	struct dl_softc *sc = arg;
276 
277 	if (DL_READ_WORD(DL_UBA_RCSR) & DL_RCSR_RX_DONE) {
278 		struct tty *tp = sc->sc_tty;
279 		unsigned c;
280 		int cc;
281 
282 		c = DL_READ_WORD(DL_UBA_RBUF);
283 		cc = c & 0xFF;
284 
285 		if (!(tp->t_state & TS_ISOPEN)) {
286 			clwakeup(&tp->t_rawq);
287 			return;
288 		}
289 
290 		if (c & DL_RBUF_OVERRUN_ERR) {
291 			/*
292 			 * XXX: This should really be logged somwhere
293 			 * else where we can afford the time.
294 			 */
295 			log(LOG_WARNING, "%s: rx overrun\n",
296 			    sc->sc_dev.dv_xname);
297 		}
298 		if (c & DL_RBUF_FRAMING_ERR)
299 			cc |= TTY_FE;
300 		if (c & DL_RBUF_PARITY_ERR)
301 			cc |= TTY_PE;
302 
303 		(*tp->t_linesw->l_rint)(cc, tp);
304 #if defined(DIAGNOSTIC)
305 	} else {
306 		log(LOG_WARNING, "%s: stray rx interrupt\n",
307 		    sc->sc_dev.dv_xname);
308 #endif
309 	}
310 }
311 
312 /* Transmitter Interrupt Handler */
313 
314 static void
315 dlxint(void *arg)
316 {
317 	struct dl_softc *sc = arg;
318 	struct tty *tp = sc->sc_tty;
319 
320 	tp->t_state &= ~(TS_BUSY | TS_FLUSH);
321 	(*tp->t_linesw->l_start)(tp);
322 
323 	return;
324 }
325 
326 int
327 dlopen(dev_t dev, int flag, int mode, struct lwp *l)
328 {
329 	struct tty *tp;
330 	struct dl_softc *sc;
331 	int unit;
332 
333 	unit = minor(dev);
334 
335 	if (unit >= dl_cd.cd_ndevs || dl_cd.cd_devs[unit] == NULL)
336 		return ENXIO;
337 	sc = dl_cd.cd_devs[unit];
338 
339 	tp = sc->sc_tty;
340 	if (tp == NULL)
341 		return ENODEV;
342 	tp->t_oproc = dlstart;
343 	tp->t_param = dlparam;
344 	tp->t_dev = dev;
345 
346 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
347 		return (EBUSY);
348 
349 	if (!(tp->t_state & TS_ISOPEN)) {
350 		ttychars(tp);
351 		tp->t_iflag = TTYDEF_IFLAG;
352 		tp->t_oflag = TTYDEF_OFLAG;
353 		/* No modem control, so set CLOCAL. */
354 		tp->t_cflag = TTYDEF_CFLAG | CLOCAL;
355 		tp->t_lflag = TTYDEF_LFLAG;
356 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
357 
358 		dlparam(tp, &tp->t_termios);
359 		ttsetwater(tp);
360 
361 	}
362 
363 	return ((*tp->t_linesw->l_open)(dev, tp));
364 }
365 
366 /*ARGSUSED*/
367 int
368 dlclose(dev_t dev, int flag, int mode, struct lwp *l)
369 {
370 	struct dl_softc *sc = dl_cd.cd_devs[minor(dev)];
371 	struct tty *tp = sc->sc_tty;
372 
373 	(*tp->t_linesw->l_close)(tp, flag);
374 
375 	/* Make sure a BREAK state is not left enabled. */
376 	dlbrk(sc, 0);
377 
378 	return (ttyclose(tp));
379 }
380 
381 int
382 dlread(dev_t dev, struct uio *uio, int flag)
383 {
384 	struct dl_softc *sc = dl_cd.cd_devs[minor(dev)];
385 	struct tty *tp = sc->sc_tty;
386 
387 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
388 }
389 
390 int
391 dlwrite(dev_t dev, struct uio *uio, int flag)
392 {
393 	struct dl_softc *sc = dl_cd.cd_devs[minor(dev)];
394 	struct tty *tp = sc->sc_tty;
395 
396 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
397 }
398 
399 int
400 dlpoll(dev_t dev, int events, struct lwp *l)
401 {
402 	struct dl_softc *sc = dl_cd.cd_devs[minor(dev)];
403 	struct tty *tp = sc->sc_tty;
404 
405 	return ((*tp->t_linesw->l_poll)(tp, events, l));
406 }
407 
408 int
409 dlioctl(dev_t dev, unsigned long cmd, void *data, int flag, struct lwp *l)
410 {
411 	struct dl_softc *sc = dl_cd.cd_devs[minor(dev)];
412 	struct tty *tp = sc->sc_tty;
413 	int error;
414 
415 
416 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
417 	if (error != EPASSTHROUGH)
418 		return (error);
419 
420 	error = ttioctl(tp, cmd, data, flag, l);
421 	if (error != EPASSTHROUGH)
422 		return (error);
423 
424 	switch (cmd) {
425 
426 	case TIOCSBRK:
427 		dlbrk(sc, 1);
428 		break;
429 
430 	case TIOCCBRK:
431 		dlbrk(sc, 0);
432 		break;
433 
434 	case TIOCMGET:
435 		/* No modem control, assume they're all low. */
436 		*(int *)data = 0;
437 		break;
438 
439 	default:
440 		return (EPASSTHROUGH);
441 	}
442 	return (0);
443 }
444 
445 struct tty *
446 dltty(dev_t dev)
447 {
448 	struct dl_softc *sc = dl_cd.cd_devs[minor(dev)];
449 
450 	return sc->sc_tty;
451 }
452 
453 void
454 dlstop(struct tty *tp, int flag)
455 {
456 	int s = spltty();
457 
458 	if ((tp->t_state & (TS_BUSY|TS_TTSTOP)) == TS_BUSY)
459 		tp->t_state |= TS_FLUSH;
460 	splx(s);
461 }
462 
463 static void
464 dlstart(struct tty *tp)
465 {
466 	struct dl_softc *sc = dl_cd.cd_devs[minor(tp->t_dev)];
467 	int s = spltty();
468 
469 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
470 		goto out;
471 	if (!ttypull(tp))
472 		goto out;
473 	if (DL_READ_WORD(DL_UBA_XCSR) & DL_XCSR_TX_READY) {
474 		tp->t_state |= TS_BUSY;
475 		DL_WRITE_BYTE(DL_UBA_XBUFL, getc(&tp->t_outq));
476 	}
477 out:
478 	splx(s);
479 	return;
480 }
481 
482 /*ARGSUSED*/
483 static int
484 dlparam(struct tty *tp, struct termios *t)
485 {
486 	/*
487 	 * All this kind of stuff (speed, character format, whatever)
488 	 * is set by jumpers on the card.  Changing it is thus rather
489 	 * tricky for a mere device driver.
490 	 */
491 	return 0;
492 }
493 
494 static void
495 dlbrk(struct dl_softc *sc, int state)
496 {
497 	int s = spltty();
498 
499 	if (state) {
500 		DL_WRITE_WORD(DL_UBA_XCSR, DL_READ_WORD(DL_UBA_XCSR) |
501 		    DL_XCSR_TX_BREAK);
502 	} else {
503 		DL_WRITE_WORD(DL_UBA_XCSR, DL_READ_WORD(DL_UBA_XCSR) &
504 		    ~DL_XCSR_TX_BREAK);
505 	}
506 	splx(s);
507 }
508