1 /* $OpenBSD: sbbc.c,v 1.15 2022/10/12 13:39:50 kettenis 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
sbbc_match(struct device * parent,void * match,void * aux)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
sbbc_attach(struct device * parent,struct device * self,void * aux)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
sbbc_intr(void * arg)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
sbbc_send_intr(struct sbbc_softc * sc)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
sbbc_attach_tod(struct sbbc_softc * sc,uint32_t offset)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 handle->bus_cookie = NULL;
334 handle->todr_setwen = NULL;
335 handle->todr_quality = 0;
336 todr_handle = handle;
337 }
338
339 int
sbbc_tod_gettime(todr_chip_handle_t handle,struct timeval * tv)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
sbbc_tod_settime(todr_chip_handle_t handle,struct timeval * tv)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
sbbc_attach_cons(struct sbbc_softc * sc,uint32_t offset)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
sbbc_intr_cons(struct sbbc_softc * sc,uint32_t reason)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
sbbc_softintr_cons(void * arg)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
sbbc_cnlookc(dev_t dev,int * cp)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
sbbc_cngetc(dev_t dev)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
sbbc_cnputc(dev_t dev,int c)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
sbbcopen(dev_t dev,int flag,int mode,struct proc * p)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
sbbcclose(dev_t dev,int flag,int mode,struct proc * p)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
sbbcread(dev_t dev,struct uio * uio,int flag)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
sbbcwrite(dev_t dev,struct uio * uio,int flag)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
sbbcioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)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
sbbcstart(struct tty * tp)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
sbbcstop(struct tty * tp,int flag)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 *
sbbctty(dev_t dev)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
sbbcparam(struct tty * tp,struct termios * t)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