xref: /openbsd/sys/arch/sparc64/dev/sbbc.c (revision 73471bf0)
1 /*	$OpenBSD: sbbc.c,v 1.14 2021/10/24 17:05:04 mpi Exp $	*/
2 /*
3  * Copyright (c) 2008 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/conf.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 #include <sys/proc.h>
23 #include <sys/timeout.h>
24 #include <sys/tty.h>
25 #include <sys/systm.h>
26 
27 #ifdef DDB
28 #include <ddb/db_var.h>
29 #endif
30 
31 #include <machine/autoconf.h>
32 #include <machine/conf.h>
33 #include <machine/openfirm.h>
34 #include <machine/sparc64.h>
35 
36 #include <dev/cons.h>
37 
38 #include <dev/pci/pcidevs.h>
39 #include <dev/pci/pcireg.h>
40 #include <dev/pci/pcivar.h>
41 
42 #include <dev/clock_subr.h>
43 
44 extern todr_chip_handle_t todr_handle;
45 
46 #define SBBC_PCI_BAR	PCI_MAPREG_START
47 
48 #define SBBC_REGS_OFFSET	0x800000
49 #define SBBC_REGS_SIZE		0x6230
50 #define SBBC_EPLD_OFFSET	0x8e0000
51 #define SBBC_EPLD_SIZE		0x20
52 #define SBBC_SRAM_OFFSET	0x900000
53 #define SBBC_SRAM_SIZE		0x20000	/* 128KB SRAM */
54 
55 #define SBBC_PCI_INT_STATUS	0x2320
56 #define SBBC_PCI_INT_ENABLE	0x2330
57 #define SBBC_PCI_ENABLE_INT_A	0x11
58 
59 #define SBBC_EPLD_INTERRUPT	0x13
60 #define SBBC_EPLD_INTERRUPT_ON	0x01
61 
62 #define SBBC_SRAM_CONS_IN		0x00000001
63 #define SBBC_SRAM_CONS_OUT		0x00000002
64 #define SBBC_SRAM_CONS_BRK		0x00000004
65 #define SBBC_SRAM_CONS_SPACE_IN		0x00000008
66 #define SBBC_SRAM_CONS_SPACE_OUT	0x00000010
67 
68 #define SBBC_MAX_TAGS	32
69 
70 struct sbbc_sram_tag {
71 	char		tag_key[8];
72 	uint32_t	tag_size;
73 	uint32_t	tag_offset;
74 };
75 
76 struct sbbc_sram_toc {
77 	char			toc_magic[8];
78 	uint8_t			toc_reserved;
79 	uint8_t			toc_type;
80 	uint16_t		toc_version;
81 	uint32_t		toc_ntags;
82 	struct sbbc_sram_tag 	toc_tag[SBBC_MAX_TAGS];
83 };
84 
85 /* Time of day service. */
86 struct sbbc_sram_tod {
87 	uint32_t	tod_magic;
88 	uint32_t	tod_version;
89 	uint64_t	tod_time;
90 	uint64_t	tod_skew;
91 	uint32_t	tod_reserved;
92 	uint32_t	tod_heartbeat;
93 	uint32_t	tod_timeout;
94 };
95 
96 #define SBBC_TOD_MAGIC		0x54443100 /* "TD1" */
97 #define SBBC_TOD_VERSION	1
98 
99 /* Console service. */
100 struct sbbc_sram_cons {
101 	uint32_t cons_magic;
102 	uint32_t cons_version;
103 	uint32_t cons_size;
104 
105 	uint32_t cons_in_begin;
106 	uint32_t cons_in_end;
107 	uint32_t cons_in_rdptr;
108 	uint32_t cons_in_wrptr;
109 
110 	uint32_t cons_out_begin;
111 	uint32_t cons_out_end;
112 	uint32_t cons_out_rdptr;
113 	uint32_t cons_out_wrptr;
114 };
115 
116 #define SBBC_CONS_MAGIC		0x434f4e00 /* "CON" */
117 #define SBBC_CONS_VERSION	1
118 
119 struct sbbc_softc {
120 	struct device		sc_dv;
121 	bus_space_tag_t		sc_iot;
122 	bus_space_handle_t	sc_regs_ioh;
123 	bus_space_handle_t	sc_epld_ioh;
124 	bus_space_handle_t	sc_sram_ioh;
125 	caddr_t			sc_sram;
126 	uint32_t		sc_sram_toc;
127 	void *			sc_ih;
128 
129 	struct sparc_bus_space_tag sc_bbt;
130 
131 	struct tty		*sc_tty;
132 	caddr_t			sc_sram_cons;
133 	uint32_t		*sc_sram_solscie;
134 	uint32_t		*sc_sram_solscir;
135 	uint32_t		*sc_sram_scsolie;
136 	uint32_t		*sc_sram_scsolir;
137 	void			*sc_cons_si;
138 };
139 
140 struct sbbc_softc *sbbc_cons_input;
141 struct sbbc_softc *sbbc_cons_output;
142 
143 int	sbbc_match(struct device *, void *, void *);
144 void	sbbc_attach(struct device *, struct device *, void *);
145 
146 const struct cfattach sbbc_ca = {
147 	sizeof(struct sbbc_softc), sbbc_match, sbbc_attach
148 };
149 
150 struct cfdriver sbbc_cd = {
151 	NULL, "sbbc", DV_DULL
152 };
153 
154 int	sbbc_intr(void *);
155 void	sbbc_send_intr(struct sbbc_softc *sc);
156 
157 void	sbbc_attach_tod(struct sbbc_softc *, uint32_t);
158 int	sbbc_tod_gettime(todr_chip_handle_t, struct timeval *);
159 int	sbbc_tod_settime(todr_chip_handle_t, struct timeval *);
160 
161 void	sbbc_attach_cons(struct sbbc_softc *, uint32_t);
162 void	sbbc_intr_cons(struct sbbc_softc *, uint32_t);
163 void	sbbc_softintr_cons(void *);
164 int	sbbc_cnlookc(dev_t, int *);
165 int	sbbc_cngetc(dev_t);
166 void	sbbc_cnputc(dev_t, int);
167 void	sbbcstart(struct tty *);
168 int	sbbcparam(struct tty *, struct termios *);
169 
170 int
171 sbbc_match(struct device *parent, void *match, void *aux)
172 {
173 	struct pci_attach_args *pa = aux;
174 
175 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
176 	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_SBBC))
177 		return (1);
178 
179 	return (0);
180 }
181 
182 void
183 sbbc_attach(struct device *parent, struct device *self, void *aux)
184 {
185 	struct sbbc_softc *sc = (void *)self;
186 	struct pci_attach_args *pa = aux;
187 	struct sbbc_sram_toc *toc;
188 	bus_addr_t base;
189 	bus_size_t size;
190 	pci_intr_handle_t ih;
191 	int chosen, iosram;
192 	int i;
193 
194 	/* XXX Don't byteswap. */
195 	sc->sc_bbt = *pa->pa_memt;
196 	sc->sc_bbt.sasi = ASI_PRIMARY;
197 	sc->sc_iot = &sc->sc_bbt;
198 
199 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, SBBC_PCI_BAR,
200 	    PCI_MAPREG_TYPE_MEM, &base, &size, NULL)) {
201 		printf(": can't find register space\n");
202 		return;
203 	}
204 
205 	if (bus_space_map(sc->sc_iot, base + SBBC_REGS_OFFSET,
206 	    SBBC_REGS_SIZE, 0, &sc->sc_regs_ioh)) {
207 		printf(": can't map register space\n");
208 		return;
209 	}
210 
211 	if (bus_space_map(sc->sc_iot, base + SBBC_EPLD_OFFSET,
212 	    SBBC_EPLD_SIZE, 0, &sc->sc_epld_ioh)) {
213 		printf(": can't map EPLD registers\n");
214 		goto unmap_regs;
215 	}
216 
217 	if (bus_space_map(sc->sc_iot, base + SBBC_SRAM_OFFSET,
218 	    SBBC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) {
219 		printf(": can't map SRAM\n");
220 		goto unmap_epld;
221 	}
222 
223 	if (pci_intr_map(pa, &ih)) {
224 		printf(": unable to map interrupt\n");
225 		goto unmap_sram;
226 	}
227 	printf(": %s\n", pci_intr_string(pa->pa_pc, ih));
228 
229 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY,
230 	    sbbc_intr, sc, sc->sc_dv.dv_xname);
231 	if (sc->sc_ih == NULL) {
232 		printf("%s: unable to establish interrupt\n", sc->sc_dv.dv_xname);
233 		goto unmap_sram;
234 	}
235 
236 	bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh,
237 	    SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A);
238 
239 	/* Check if we are the chosen one. */
240 	chosen = OF_finddevice("/chosen");
241 	if (OF_getprop(chosen, "iosram", &iosram, sizeof(iosram)) <= 0 ||
242 	    PCITAG_NODE(pa->pa_tag) != iosram)
243 		return;
244 
245 	/* SRAM TOC offset defaults to 0. */
246 	if (OF_getprop(chosen, "iosram-toc", &sc->sc_sram_toc,
247 	    sizeof(sc->sc_sram_toc)) <= 0)
248 		sc->sc_sram_toc = 0;
249 
250 	sc->sc_sram = bus_space_vaddr(sc->sc_iot, sc->sc_sram_ioh);
251 	toc = (struct sbbc_sram_toc *)(sc->sc_sram + sc->sc_sram_toc);
252 
253 	for (i = 0; i < toc->toc_ntags; i++) {
254 		if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIE") == 0)
255 			sc->sc_sram_solscie = (uint32_t *)
256 			    (sc->sc_sram + toc->toc_tag[i].tag_offset);
257 		if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIR") == 0)
258 			sc->sc_sram_solscir = (uint32_t *)
259 			    (sc->sc_sram + toc->toc_tag[i].tag_offset);
260 		if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIE") == 0)
261 			sc->sc_sram_scsolie = (uint32_t *)
262 			    (sc->sc_sram + toc->toc_tag[i].tag_offset);
263 		if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIR") == 0)
264 			sc->sc_sram_scsolir = (uint32_t *)
265 			    (sc->sc_sram + toc->toc_tag[i].tag_offset);
266 	}
267 
268 	for (i = 0; i < toc->toc_ntags; i++) {
269 		if (strcmp(toc->toc_tag[i].tag_key, "TODDATA") == 0)
270 			sbbc_attach_tod(sc, toc->toc_tag[i].tag_offset);
271 		if (strcmp(toc->toc_tag[i].tag_key, "SOLCONS") == 0)
272 			sbbc_attach_cons(sc, toc->toc_tag[i].tag_offset);
273 	}
274 
275 	return;
276 
277  unmap_sram:
278 	bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_SRAM_SIZE);
279  unmap_epld:
280 	bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_EPLD_SIZE);
281  unmap_regs:
282 	bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_REGS_SIZE);
283 }
284 
285 int
286 sbbc_intr(void *arg)
287 {
288 	struct sbbc_softc *sc = arg;
289 	uint32_t status, reason;
290 
291 	status = bus_space_read_4(sc->sc_iot, sc->sc_regs_ioh,
292 	    SBBC_PCI_INT_STATUS);
293 	if (status == 0)
294 		return (0);
295 
296 	/* Sigh, we cannot use compare and swap for non-cachable memory. */
297 	reason = *sc->sc_sram_scsolir;
298 	*sc->sc_sram_scsolir = 0;
299 
300 	sbbc_intr_cons(sc, reason);
301 
302 	/* Ack interrupt. */
303 	bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh,
304 	    SBBC_PCI_INT_STATUS, status);
305 	return (1);
306 }
307 
308 void
309 sbbc_send_intr(struct sbbc_softc *sc)
310 {
311 	bus_space_write_1(sc->sc_iot, sc->sc_epld_ioh,
312 	    SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON);
313 }
314 
315 void
316 sbbc_attach_tod(struct sbbc_softc *sc, uint32_t offset)
317 {
318 	struct sbbc_sram_tod *tod;
319 	todr_chip_handle_t handle;
320 
321 	tod = (struct sbbc_sram_tod *)(sc->sc_sram + offset);
322 	if (tod->tod_magic != SBBC_TOD_MAGIC ||
323 	    tod->tod_version < SBBC_TOD_VERSION)
324 		return;
325 
326 	handle = malloc(sizeof(struct todr_chip_handle), M_DEVBUF, M_NOWAIT);
327 	if (handle == NULL)
328 		panic("couldn't allocate todr_handle");
329 
330 	handle->cookie = tod;
331 	handle->todr_gettime = sbbc_tod_gettime;
332 	handle->todr_settime = sbbc_tod_settime;
333 
334 	handle->bus_cookie = NULL;
335 	handle->todr_setwen = NULL;
336 	todr_handle = handle;
337 }
338 
339 int
340 sbbc_tod_gettime(todr_chip_handle_t handle, struct timeval *tv)
341 {
342 	struct sbbc_sram_tod *tod = handle->cookie;
343 
344 	tv->tv_sec = tod->tod_time + tod->tod_skew;
345 	tv->tv_usec = 0;
346 	return (0);
347 }
348 
349 int
350 sbbc_tod_settime(todr_chip_handle_t handle, struct timeval *tv)
351 {
352 	struct sbbc_sram_tod *tod = handle->cookie;
353 
354 	tod->tod_skew = tv->tv_sec - tod->tod_time;
355 	return (0);
356 }
357 
358 void
359 sbbc_attach_cons(struct sbbc_softc *sc, uint32_t offset)
360 {
361 	struct sbbc_sram_cons *cons;
362 	int sgcn_is_input, sgcn_is_output, node, maj;
363 	char buf[32];
364 
365 	if (sc->sc_sram_solscie == NULL || sc->sc_sram_solscir == NULL ||
366 	    sc->sc_sram_scsolie == NULL || sc->sc_sram_scsolir == NULL)
367 		return;
368 
369 	cons = (struct sbbc_sram_cons *)(sc->sc_sram + offset);
370 	if (cons->cons_magic != SBBC_CONS_MAGIC ||
371 	    cons->cons_version < SBBC_CONS_VERSION)
372 		return;
373 
374 	sc->sc_sram_cons = sc->sc_sram + offset;
375 	sbbc_cons_input = sbbc_cons_output = sc;
376 	sgcn_is_input = sgcn_is_output = 0;
377 
378 	sc->sc_cons_si = softintr_establish(IPL_TTY, sbbc_softintr_cons, sc);
379 	if (sc->sc_cons_si == NULL)
380 		panic("%s: can't establish soft interrupt",
381 		    sc->sc_dv.dv_xname);
382 
383 	*sc->sc_sram_solscie |= SBBC_SRAM_CONS_OUT;
384 	*sc->sc_sram_scsolie |= SBBC_SRAM_CONS_IN | SBBC_SRAM_CONS_BRK;
385 
386 	/* Take over console input. */
387 	prom_serengeti_set_console_input("CON_CLNT");
388 
389 	/* Check for console input. */
390 	node = OF_instance_to_package(OF_stdin());
391 	if (OF_getprop(node, "name", buf, sizeof(buf)) > 0)
392 		sgcn_is_input = (strcmp(buf, "sgcn") == 0);
393 
394 	/* Check for console output. */
395 	node = OF_instance_to_package(OF_stdout());
396 	if (OF_getprop(node, "name", buf, sizeof(buf)) > 0)
397 		sgcn_is_output = (strcmp(buf, "sgcn") == 0);
398 
399 	if (sgcn_is_input) {
400 		cn_tab->cn_pollc = nullcnpollc;
401 		cn_tab->cn_getc = sbbc_cngetc;
402 	}
403 
404 	if (sgcn_is_output)
405 		cn_tab->cn_putc = sbbc_cnputc;
406 
407 	if (sgcn_is_input || sgcn_is_output) {
408 		/* Locate the major number. */
409 		for (maj = 0; maj < nchrdev; maj++)
410 			if (cdevsw[maj].d_open == sbbcopen)
411 				break;
412 		cn_tab->cn_dev = makedev(maj, sc->sc_dv.dv_unit);
413 
414 		/* Let current output drain. */
415 		DELAY(2000000);
416 
417 		printf("%s: console\n", sc->sc_dv.dv_xname);
418 	}
419 }
420 
421 void
422 sbbc_intr_cons(struct sbbc_softc *sc, uint32_t reason)
423 {
424 #ifdef DDB
425 	if ((reason & SBBC_SRAM_CONS_BRK) && sc == sbbc_cons_input) {
426 		if (db_console)
427 			db_enter();
428 	}
429 #endif
430 
431 	if ((reason & SBBC_SRAM_CONS_IN) && sc->sc_tty)
432 		softintr_schedule(sc->sc_cons_si);
433 }
434 
435 void
436 sbbc_softintr_cons(void *arg)
437 {
438 	struct sbbc_softc *sc = arg;
439 	struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons;
440 	uint32_t rdptr = cons->cons_in_rdptr;
441 	struct tty *tp = sc->sc_tty;
442 	int c;
443 
444 	while (rdptr != cons->cons_in_wrptr) {
445 		if (tp->t_state & TS_ISOPEN) {
446 			c = *(sc->sc_sram_cons + rdptr);
447 			(*linesw[tp->t_line].l_rint)(c, tp);
448 		}
449 
450 		if (++rdptr == cons->cons_in_end)
451 			rdptr = cons->cons_in_begin;
452 	}
453 
454 	cons->cons_in_rdptr = rdptr;
455 }
456 
457 int
458 sbbc_cnlookc(dev_t dev, int *cp)
459 {
460 	struct sbbc_softc *sc = sbbc_cons_input;
461 	struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons;
462 	uint32_t rdptr = cons->cons_in_rdptr;
463 
464 	if (rdptr == cons->cons_in_wrptr)
465 		return (0);
466 
467 	*cp = *(sc->sc_sram_cons + rdptr);
468 	if (++rdptr == cons->cons_in_end)
469 		rdptr = cons->cons_in_begin;
470 	cons->cons_in_rdptr = rdptr;
471 
472 	return (1);
473 }
474 
475 int
476 sbbc_cngetc(dev_t dev)
477 {
478 	int c;
479 
480 	while(!sbbc_cnlookc(dev, &c))
481 		;
482 
483 	return (c);
484 }
485 
486 void
487 sbbc_cnputc(dev_t dev, int c)
488 {
489 	struct sbbc_softc *sc = sbbc_cons_output;
490 	struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons;
491 	uint32_t wrptr = cons->cons_out_wrptr;
492 
493 	*(sc->sc_sram_cons + wrptr) = c;
494 	if (++wrptr == cons->cons_out_end)
495 		wrptr = cons->cons_out_begin;
496 	cons->cons_out_wrptr = wrptr;
497 
498 	*sc->sc_sram_solscir |= SBBC_SRAM_CONS_OUT;
499 	sbbc_send_intr(sc);
500 }
501 
502 int
503 sbbcopen(dev_t dev, int flag, int mode, struct proc *p)
504 {
505 	struct sbbc_softc *sc;
506 	struct tty *tp;
507 	int unit = minor(dev);
508 
509 	if (unit >= sbbc_cd.cd_ndevs)
510 		return (ENXIO);
511 	sc = sbbc_cd.cd_devs[unit];
512 	if (sc == NULL)
513 		return (ENXIO);
514 
515 	if (sc->sc_tty)
516 		tp = sc->sc_tty;
517 	else
518 		tp = sc->sc_tty = ttymalloc(0);
519 
520 	tp->t_oproc = sbbcstart;
521 	tp->t_param = sbbcparam;
522 	tp->t_dev = dev;
523 	if ((tp->t_state & TS_ISOPEN) == 0) {
524 		ttychars(tp);
525 		tp->t_iflag = TTYDEF_IFLAG;
526 		tp->t_oflag = TTYDEF_OFLAG;
527 		tp->t_cflag = TTYDEF_CFLAG;
528 		tp->t_lflag = TTYDEF_LFLAG;
529 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
530 		ttsetwater(tp);
531 	} else if ((tp->t_state & TS_XCLUDE) && suser(p))
532 		return (EBUSY);
533 	tp->t_state |= TS_CARR_ON;
534 
535 	return ((*linesw[tp->t_line].l_open)(dev, tp, p));
536 }
537 
538 int
539 sbbcclose(dev_t dev, int flag, int mode, struct proc *p)
540 {
541 	struct sbbc_softc *sc;
542 	struct tty *tp;
543 	int unit = minor(dev);
544 
545 	if (unit >= sbbc_cd.cd_ndevs)
546 		return (ENXIO);
547 	sc = sbbc_cd.cd_devs[unit];
548 	if (sc == NULL)
549 		return (ENXIO);
550 
551 	tp = sc->sc_tty;
552 	(*linesw[tp->t_line].l_close)(tp, flag, p);
553 	ttyclose(tp);
554 	return (0);
555 }
556 
557 int
558 sbbcread(dev_t dev, struct uio *uio, int flag)
559 {
560 	struct sbbc_softc *sc;
561 	struct tty *tp;
562 	int unit = minor(dev);
563 
564 	if (unit >= sbbc_cd.cd_ndevs)
565 		return (ENXIO);
566 	sc = sbbc_cd.cd_devs[unit];
567 	if (sc == NULL)
568 		return (ENXIO);
569 
570 	tp = sc->sc_tty;
571 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
572 }
573 
574 int
575 sbbcwrite(dev_t dev, struct uio *uio, int flag)
576 {
577 	struct sbbc_softc *sc;
578 	struct tty *tp;
579 	int unit = minor(dev);
580 
581 	if (unit >= sbbc_cd.cd_ndevs)
582 		return (ENXIO);
583 	sc = sbbc_cd.cd_devs[unit];
584 	if (sc == NULL)
585 		return (ENXIO);
586 
587 	tp = sc->sc_tty;
588 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
589 }
590 
591 int
592 sbbcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
593 {
594 	struct sbbc_softc *sc;
595 	struct tty *tp;
596 	int unit = minor(dev);
597 	int error;
598 
599 	if (unit >= sbbc_cd.cd_ndevs)
600 		return (ENXIO);
601 	sc = sbbc_cd.cd_devs[unit];
602 	if (sc == NULL)
603 		return (ENXIO);
604 
605 	tp = sc->sc_tty;
606 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
607 	if (error >= 0)
608 		return error;
609 	error = ttioctl(tp, cmd, data, flag, p);
610 	if (error >= 0)
611 		return (error);
612 
613 	return (ENOTTY);
614 }
615 
616 void
617 sbbcstart(struct tty *tp)
618 {
619 	int s;
620 
621 	s = spltty();
622 	if (tp->t_state & (TS_TTSTOP | TS_BUSY)) {
623 		splx(s);
624 		return;
625 	}
626 	ttwakeupwr(tp);
627 	tp->t_state |= TS_BUSY;
628 	while (tp->t_outq.c_cc != 0)
629 		sbbc_cnputc(tp->t_dev, getc(&tp->t_outq));
630 	tp->t_state &= ~TS_BUSY;
631 	splx(s);
632 }
633 
634 int
635 sbbcstop(struct tty *tp, int flag)
636 {
637 	int s;
638 
639 	s = spltty();
640 	if (tp->t_state & TS_BUSY)
641 		if ((tp->t_state & TS_TTSTOP) == 0)
642 			tp->t_state |= TS_FLUSH;
643 	splx(s);
644 	return (0);
645 }
646 
647 struct tty *
648 sbbctty(dev_t dev)
649 {
650 	struct sbbc_softc *sc;
651 	int unit = minor(dev);
652 
653 	if (unit >= sbbc_cd.cd_ndevs)
654 		return (NULL);
655 	sc = sbbc_cd.cd_devs[unit];
656 	if (sc == NULL)
657 		return (NULL);
658 
659 	return sc->sc_tty;
660 }
661 
662 int
663 sbbcparam(struct tty *tp, struct termios *t)
664 {
665 	tp->t_ispeed = t->c_ispeed;
666 	tp->t_ospeed = t->c_ospeed;
667 	tp->t_cflag = t->c_cflag;
668 	return (0);
669 }
670