1*eb7eaf8dSmpi /* $OpenBSD: vcctty.c,v 1.15 2021/10/24 17:05:04 mpi Exp $ */
2b072e723Skettenis /*
3b072e723Skettenis * Copyright (c) 2009 Mark Kettenis
4b072e723Skettenis *
5b072e723Skettenis * Permission to use, copy, modify, and distribute this software for any
6b072e723Skettenis * purpose with or without fee is hereby granted, provided that the above
7b072e723Skettenis * copyright notice and this permission notice appear in all copies.
8b072e723Skettenis *
9b072e723Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10b072e723Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11b072e723Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12b072e723Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13b072e723Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14b072e723Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15b072e723Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16b072e723Skettenis */
17b072e723Skettenis
18b072e723Skettenis #include <sys/param.h>
19b072e723Skettenis #include <sys/conf.h>
20b072e723Skettenis #include <sys/device.h>
21b072e723Skettenis #include <sys/malloc.h>
22b072e723Skettenis #include <sys/proc.h>
23b072e723Skettenis #include <sys/systm.h>
24b072e723Skettenis #include <sys/tty.h>
25b072e723Skettenis
26b072e723Skettenis #include <machine/autoconf.h>
27b072e723Skettenis #include <machine/conf.h>
28b072e723Skettenis #include <machine/hypervisor.h>
29b072e723Skettenis #include <machine/mdesc.h>
30b072e723Skettenis
31b072e723Skettenis #include <dev/cons.h>
32b072e723Skettenis #include <sparc64/dev/cbusvar.h>
33b072e723Skettenis #include <sparc64/dev/ldcvar.h>
34b072e723Skettenis
35b072e723Skettenis #ifdef VCCTTY_DEBUG
36b072e723Skettenis #define DPRINTF(x) printf x
37b072e723Skettenis #else
38b072e723Skettenis #define DPRINTF(x)
39b072e723Skettenis #endif
40b072e723Skettenis
41b072e723Skettenis #define VCCTTY_TX_ENTRIES 128
42b072e723Skettenis #define VCCTTY_RX_ENTRIES 128
43b072e723Skettenis
44b072e723Skettenis struct vcctty_msg {
45b072e723Skettenis uint8_t type;
46b072e723Skettenis uint8_t size;
47b072e723Skettenis uint16_t rsvd;
48b072e723Skettenis uint32_t ctrl_msg;
49b072e723Skettenis uint8_t data[56];
50b072e723Skettenis };
51b072e723Skettenis
52b072e723Skettenis /* Packet types. */
53b072e723Skettenis #define LDC_CONSOLE_CTRL 0x01
54b072e723Skettenis #define LDC_CONSOLE_DATA 0x02
55b072e723Skettenis
56b072e723Skettenis struct vcctty_softc {
57b072e723Skettenis struct device sc_dv;
58b072e723Skettenis bus_space_tag_t sc_bustag;
59b072e723Skettenis bus_dma_tag_t sc_dmatag;
60b072e723Skettenis
61b3a497edSkettenis uint64_t sc_tx_ino;
62b3a497edSkettenis uint64_t sc_rx_ino;
63b072e723Skettenis void *sc_tx_ih;
64b072e723Skettenis void *sc_rx_ih;
65b072e723Skettenis
66b072e723Skettenis struct ldc_conn sc_lc;
67b072e723Skettenis
68b072e723Skettenis struct tty *sc_tty;
69b072e723Skettenis };
70b072e723Skettenis
71b072e723Skettenis int vcctty_match(struct device *, void *, void *);
72b072e723Skettenis void vcctty_attach(struct device *, struct device *, void *);
73b072e723Skettenis
74*eb7eaf8dSmpi const struct cfattach vcctty_ca = {
75b072e723Skettenis sizeof(struct vcctty_softc), vcctty_match, vcctty_attach
76b072e723Skettenis };
77b072e723Skettenis
78b072e723Skettenis struct cfdriver vcctty_cd = {
79b072e723Skettenis NULL, "vcctty", DV_DULL
80b072e723Skettenis };
81b072e723Skettenis
82b072e723Skettenis int vcctty_tx_intr(void *);
83b072e723Skettenis int vcctty_rx_intr(void *);
84b072e723Skettenis
85ae51ad54Skettenis void vcctty_send_data(struct vcctty_softc *, struct tty *);
86b072e723Skettenis void vcctty_send_break(struct vcctty_softc *);
87b072e723Skettenis
88b072e723Skettenis void vccttystart(struct tty *);
89b072e723Skettenis int vccttyparam(struct tty *, struct termios *);
90f62a4008Skettenis int vccttyhwiflow(struct tty *, int);
91b072e723Skettenis
92b072e723Skettenis int
vcctty_match(struct device * parent,void * match,void * aux)93b072e723Skettenis vcctty_match(struct device *parent, void *match, void *aux)
94b072e723Skettenis {
95b072e723Skettenis return (1);
96b072e723Skettenis }
97b072e723Skettenis
98b072e723Skettenis void
vcctty_attach(struct device * parent,struct device * self,void * aux)99b072e723Skettenis vcctty_attach(struct device *parent, struct device *self, void *aux)
100b072e723Skettenis {
101b072e723Skettenis struct vcctty_softc *sc = (struct vcctty_softc *)self;
102b072e723Skettenis struct cbus_attach_args *ca = aux;
103b072e723Skettenis struct ldc_conn *lc;
104b072e723Skettenis int err;
105b072e723Skettenis
106b072e723Skettenis sc->sc_bustag = ca->ca_bustag;
107b072e723Skettenis sc->sc_dmatag = ca->ca_dmatag;
108b3a497edSkettenis sc->sc_tx_ino = ca->ca_tx_ino;
109b3a497edSkettenis sc->sc_rx_ino = ca->ca_rx_ino;
110b072e723Skettenis
111b3a497edSkettenis printf(": ivec 0x%llx, 0x%llx", sc->sc_tx_ino, sc->sc_rx_ino);
112b072e723Skettenis
113b072e723Skettenis /*
114b072e723Skettenis * Un-configure queues before registering interrupt handlers,
115b072e723Skettenis * such that we dont get any stale LDC packets or events.
116b072e723Skettenis */
117b072e723Skettenis hv_ldc_tx_qconf(ca->ca_id, 0, 0);
118b072e723Skettenis hv_ldc_rx_qconf(ca->ca_id, 0, 0);
119b072e723Skettenis
120b3a497edSkettenis sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_tx_ino,
121b072e723Skettenis IPL_TTY, 0, vcctty_tx_intr, sc, sc->sc_dv.dv_xname);
122b3a497edSkettenis sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_rx_ino,
123b072e723Skettenis IPL_TTY, 0, vcctty_rx_intr, sc, sc->sc_dv.dv_xname);
124b072e723Skettenis if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) {
125b072e723Skettenis printf(", can't establish interrupt\n");
126b072e723Skettenis return;
127b072e723Skettenis }
128b072e723Skettenis
129b072e723Skettenis lc = &sc->sc_lc;
130b072e723Skettenis lc->lc_id = ca->ca_id;
131b072e723Skettenis lc->lc_sc = sc;
132b072e723Skettenis
133b072e723Skettenis lc->lc_txq = ldc_queue_alloc(sc->sc_dmatag, VCCTTY_TX_ENTRIES);
134b072e723Skettenis if (lc->lc_txq == NULL) {
135b072e723Skettenis printf(", can't allocate tx queue\n");
136b072e723Skettenis return;
137b072e723Skettenis }
138b072e723Skettenis
139b072e723Skettenis lc->lc_rxq = ldc_queue_alloc(sc->sc_dmatag, VCCTTY_RX_ENTRIES);
140b072e723Skettenis if (lc->lc_rxq == NULL) {
141b072e723Skettenis printf(", can't allocate rx queue\n");
142b072e723Skettenis goto free_txqueue;
143b072e723Skettenis }
144b072e723Skettenis
145b072e723Skettenis err = hv_ldc_tx_qconf(lc->lc_id,
146b072e723Skettenis lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
147b072e723Skettenis if (err != H_EOK)
148b072e723Skettenis printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
149b072e723Skettenis
150b072e723Skettenis err = hv_ldc_rx_qconf(lc->lc_id,
151b072e723Skettenis lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
152b072e723Skettenis if (err != H_EOK)
15302aa388cSkettenis printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
154b072e723Skettenis
155b3a497edSkettenis cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_ENABLED);
156b3a497edSkettenis cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_ENABLED);
157ea2f3eeeSkettenis
158b072e723Skettenis printf(" domain \"%s\"\n", ca->ca_name);
159b072e723Skettenis return;
160b072e723Skettenis
161b072e723Skettenis free_txqueue:
162b072e723Skettenis ldc_queue_free(sc->sc_dmatag, lc->lc_txq);
163b072e723Skettenis }
164b072e723Skettenis
165b072e723Skettenis int
vcctty_tx_intr(void * arg)166b072e723Skettenis vcctty_tx_intr(void *arg)
167b072e723Skettenis {
168b072e723Skettenis struct vcctty_softc *sc = arg;
169b072e723Skettenis struct ldc_conn *lc = &sc->sc_lc;
170b072e723Skettenis uint64_t tx_head, tx_tail, tx_state;
171b072e723Skettenis int err;
172b072e723Skettenis
173b072e723Skettenis err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
174b072e723Skettenis if (err != H_EOK) {
175b072e723Skettenis printf("%s: hv_ldc_tx_get_state %d\n", __func__, err);
176b072e723Skettenis return (0);
177b072e723Skettenis }
178b072e723Skettenis
179b072e723Skettenis if (tx_state != lc->lc_tx_state) {
180b072e723Skettenis switch (tx_state) {
181b072e723Skettenis case LDC_CHANNEL_DOWN:
1828f296756Sstsp DPRINTF(("%s: Tx link down\n", __func__));
183b072e723Skettenis break;
184b072e723Skettenis case LDC_CHANNEL_UP:
1858f296756Sstsp DPRINTF(("%s: Tx link up\n", __func__));
186b072e723Skettenis break;
187b072e723Skettenis case LDC_CHANNEL_RESET:
1888f296756Sstsp DPRINTF(("%s: Tx link reset\n", __func__));
189b072e723Skettenis break;
190b072e723Skettenis }
191b072e723Skettenis lc->lc_tx_state = tx_state;
192b072e723Skettenis }
193b072e723Skettenis
194b072e723Skettenis return (1);
195b072e723Skettenis }
196b072e723Skettenis
197b072e723Skettenis int
vcctty_rx_intr(void * arg)198b072e723Skettenis vcctty_rx_intr(void *arg)
199b072e723Skettenis {
200b072e723Skettenis struct vcctty_softc *sc = arg;
201b072e723Skettenis struct tty *tp = sc->sc_tty;
202b072e723Skettenis struct ldc_conn *lc = &sc->sc_lc;
203b072e723Skettenis uint64_t rx_head, rx_tail, rx_state;
204b072e723Skettenis struct vcctty_msg *msg;
205b072e723Skettenis int err;
206b072e723Skettenis int i;
207b072e723Skettenis
208b072e723Skettenis err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state);
209b072e723Skettenis if (err != H_EOK) {
210b072e723Skettenis printf("%s: hv_ldc_rx_get_state %d\n", __func__, err);
211b072e723Skettenis return (0);
212b072e723Skettenis }
213b072e723Skettenis
214b072e723Skettenis if (rx_state != lc->lc_rx_state) {
215b072e723Skettenis switch (rx_state) {
216b072e723Skettenis case LDC_CHANNEL_DOWN:
2178f296756Sstsp DPRINTF(("%s: Rx link down\n", __func__));
218b072e723Skettenis break;
219b072e723Skettenis case LDC_CHANNEL_UP:
2208f296756Sstsp DPRINTF(("%s: Rx link up\n", __func__));
221b072e723Skettenis break;
222b072e723Skettenis case LDC_CHANNEL_RESET:
2238f296756Sstsp DPRINTF(("%s: Rx link reset\n", __func__));
224b072e723Skettenis break;
225b072e723Skettenis }
226b072e723Skettenis lc->lc_rx_state = rx_state;
227b072e723Skettenis return (1);
228b072e723Skettenis }
229b072e723Skettenis
230b072e723Skettenis if (rx_head == rx_tail)
231b072e723Skettenis return (0);
232b072e723Skettenis
233b072e723Skettenis msg = (struct vcctty_msg *)(lc->lc_rxq->lq_va + rx_head);
234b072e723Skettenis if (tp && msg->type == LDC_CONSOLE_DATA) {
235b072e723Skettenis for (i = 0; i < msg->size; i++) {
236b072e723Skettenis if (tp->t_state & TS_ISOPEN)
237b072e723Skettenis (*linesw[tp->t_line].l_rint)(msg->data[i], tp);
238b072e723Skettenis }
239b072e723Skettenis }
240b072e723Skettenis
241b072e723Skettenis rx_head += sizeof(*msg);
242b072e723Skettenis rx_head &= ((lc->lc_rxq->lq_nentries * sizeof(*msg)) - 1);
243b072e723Skettenis err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head);
244b072e723Skettenis if (err != H_EOK)
245b072e723Skettenis printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err);
246b072e723Skettenis
247b072e723Skettenis return (1);
248b072e723Skettenis }
249b072e723Skettenis
250b072e723Skettenis void
vcctty_send_data(struct vcctty_softc * sc,struct tty * tp)251ae51ad54Skettenis vcctty_send_data(struct vcctty_softc *sc, struct tty *tp)
252b072e723Skettenis {
253b072e723Skettenis struct ldc_conn *lc = &sc->sc_lc;
254b072e723Skettenis uint64_t tx_head, tx_tail, tx_state;
255ae51ad54Skettenis uint64_t next_tx_tail;
256b072e723Skettenis struct vcctty_msg *msg;
257b072e723Skettenis int err;
258b072e723Skettenis
259b072e723Skettenis err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
260b072e723Skettenis if (err != H_EOK || tx_state != LDC_CHANNEL_UP)
261b072e723Skettenis return;
262b072e723Skettenis
263ae51ad54Skettenis while (tp->t_outq.c_cc > 0) {
264ae51ad54Skettenis next_tx_tail = tx_tail + sizeof(*msg);
265ae51ad54Skettenis next_tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*msg)) - 1);
266ae51ad54Skettenis
267ae51ad54Skettenis if (next_tx_tail == tx_head)
268ae51ad54Skettenis return;
269ae51ad54Skettenis
270b072e723Skettenis msg = (struct vcctty_msg *)(lc->lc_txq->lq_va + tx_tail);
271b072e723Skettenis bzero(msg, sizeof(*msg));
272b072e723Skettenis msg->type = LDC_CONSOLE_DATA;
273ae51ad54Skettenis msg->size = q_to_b(&tp->t_outq, msg->data, sizeof(msg->data));
274b072e723Skettenis
275ae51ad54Skettenis err = hv_ldc_tx_set_qtail(lc->lc_id, next_tx_tail);
276b072e723Skettenis if (err != H_EOK)
277b072e723Skettenis printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
278ae51ad54Skettenis tx_tail = next_tx_tail;
279ae51ad54Skettenis }
280b072e723Skettenis }
281b072e723Skettenis
282b072e723Skettenis void
vcctty_send_break(struct vcctty_softc * sc)283b072e723Skettenis vcctty_send_break(struct vcctty_softc *sc)
284b072e723Skettenis {
285b072e723Skettenis struct ldc_conn *lc = &sc->sc_lc;
286b072e723Skettenis uint64_t tx_head, tx_tail, tx_state;
287b072e723Skettenis struct vcctty_msg *msg;
288b072e723Skettenis int err;
289b072e723Skettenis
290b072e723Skettenis err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
291b072e723Skettenis if (err != H_EOK || tx_state != LDC_CHANNEL_UP)
292b072e723Skettenis return;
293b072e723Skettenis
294b072e723Skettenis msg = (struct vcctty_msg *)(lc->lc_txq->lq_va + tx_tail);
295b072e723Skettenis bzero(msg, sizeof(*msg));
296b072e723Skettenis msg->type = LDC_CONSOLE_CTRL;
297b072e723Skettenis msg->ctrl_msg = CONS_BREAK;
298b072e723Skettenis
299b072e723Skettenis tx_tail += sizeof(*msg);
300b072e723Skettenis tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*msg)) - 1);
301b072e723Skettenis err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
302b072e723Skettenis if (err != H_EOK)
303b072e723Skettenis printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
304b072e723Skettenis }
305b072e723Skettenis
306b072e723Skettenis int
vccttyopen(dev_t dev,int flag,int mode,struct proc * p)307b072e723Skettenis vccttyopen(dev_t dev, int flag, int mode, struct proc *p)
308b072e723Skettenis {
309b072e723Skettenis struct vcctty_softc *sc;
310b072e723Skettenis struct tty *tp;
311b072e723Skettenis int unit = minor(dev);
312b072e723Skettenis
313e7c7aa84Smiod if (unit >= vcctty_cd.cd_ndevs)
314b072e723Skettenis return (ENXIO);
315b072e723Skettenis sc = vcctty_cd.cd_devs[unit];
316b072e723Skettenis if (sc == NULL)
317b072e723Skettenis return (ENXIO);
318b072e723Skettenis
319b072e723Skettenis if (sc->sc_tty)
320b072e723Skettenis tp = sc->sc_tty;
321b072e723Skettenis else
322197ff252Sderaadt tp = sc->sc_tty = ttymalloc(0);
323b072e723Skettenis
324b072e723Skettenis tp->t_oproc = vccttystart;
325b072e723Skettenis tp->t_param = vccttyparam;
326f62a4008Skettenis tp->t_hwiflow = vccttyhwiflow;
327b072e723Skettenis tp->t_dev = dev;
328b072e723Skettenis if ((tp->t_state & TS_ISOPEN) == 0) {
329b072e723Skettenis ttychars(tp);
330b072e723Skettenis tp->t_iflag = TTYDEF_IFLAG;
331b072e723Skettenis tp->t_oflag = TTYDEF_OFLAG;
332f62a4008Skettenis tp->t_cflag = TTYDEF_CFLAG | CRTSCTS;
333b072e723Skettenis tp->t_lflag = TTYDEF_LFLAG;
334b072e723Skettenis tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
335b072e723Skettenis ttsetwater(tp);
3363e676399Smpi } else if ((tp->t_state & TS_XCLUDE) && suser(p))
337b072e723Skettenis return (EBUSY);
338b072e723Skettenis tp->t_state |= TS_CARR_ON;
339b072e723Skettenis
34079f6c33aStedu return ((*linesw[tp->t_line].l_open)(dev, tp, p));
341b072e723Skettenis }
342b072e723Skettenis
343b072e723Skettenis int
vccttyclose(dev_t dev,int flag,int mode,struct proc * p)344b072e723Skettenis vccttyclose(dev_t dev, int flag, int mode, struct proc *p)
345b072e723Skettenis {
346b072e723Skettenis struct vcctty_softc *sc;
347b072e723Skettenis struct tty *tp;
348b072e723Skettenis int unit = minor(dev);
349b072e723Skettenis
350e7c7aa84Smiod if (unit >= vcctty_cd.cd_ndevs)
351b072e723Skettenis return (ENXIO);
352b072e723Skettenis sc = vcctty_cd.cd_devs[unit];
353b072e723Skettenis if (sc == NULL)
354b072e723Skettenis return (ENXIO);
355b072e723Skettenis
356b072e723Skettenis tp = sc->sc_tty;
35779f6c33aStedu (*linesw[tp->t_line].l_close)(tp, flag, p);
358b072e723Skettenis ttyclose(tp);
359b072e723Skettenis return (0);
360b072e723Skettenis }
361b072e723Skettenis
362b072e723Skettenis int
vccttyread(dev_t dev,struct uio * uio,int flag)363b072e723Skettenis vccttyread(dev_t dev, struct uio *uio, int flag)
364b072e723Skettenis {
365b072e723Skettenis struct vcctty_softc *sc;
366b072e723Skettenis struct tty *tp;
367b072e723Skettenis int unit = minor(dev);
368b072e723Skettenis
369e7c7aa84Smiod if (unit >= vcctty_cd.cd_ndevs)
370b072e723Skettenis return (ENXIO);
371b072e723Skettenis sc = vcctty_cd.cd_devs[unit];
372b072e723Skettenis if (sc == NULL)
373b072e723Skettenis return (ENXIO);
374b072e723Skettenis
375b072e723Skettenis tp = sc->sc_tty;
376b072e723Skettenis return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
377b072e723Skettenis }
378b072e723Skettenis
379b072e723Skettenis int
vccttywrite(dev_t dev,struct uio * uio,int flag)380b072e723Skettenis vccttywrite(dev_t dev, struct uio *uio, int flag)
381b072e723Skettenis {
382b072e723Skettenis struct vcctty_softc *sc;
383b072e723Skettenis struct tty *tp;
384b072e723Skettenis int unit = minor(dev);
385b072e723Skettenis
386e7c7aa84Smiod if (unit >= vcctty_cd.cd_ndevs)
387b072e723Skettenis return (ENXIO);
388b072e723Skettenis sc = vcctty_cd.cd_devs[unit];
389b072e723Skettenis if (sc == NULL)
390b072e723Skettenis return (ENXIO);
391b072e723Skettenis
392b072e723Skettenis tp = sc->sc_tty;
393b072e723Skettenis return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
394b072e723Skettenis }
395b072e723Skettenis
396b072e723Skettenis int
vccttyioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)397b072e723Skettenis vccttyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
398b072e723Skettenis {
399b072e723Skettenis struct vcctty_softc *sc;
400b072e723Skettenis struct tty *tp;
401b072e723Skettenis int unit = minor(dev);
402b072e723Skettenis int error;
403b072e723Skettenis
404e7c7aa84Smiod if (unit >= vcctty_cd.cd_ndevs)
405b072e723Skettenis return (ENXIO);
406b072e723Skettenis sc = vcctty_cd.cd_devs[unit];
407b072e723Skettenis if (sc == NULL)
408b072e723Skettenis return (ENXIO);
409b072e723Skettenis
410b072e723Skettenis tp = sc->sc_tty;
411b072e723Skettenis error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
412b072e723Skettenis if (error >= 0)
413b072e723Skettenis return error;
414b072e723Skettenis error = ttioctl(tp, cmd, data, flag, p);
415b072e723Skettenis if (error >= 0)
416b072e723Skettenis return (error);
417b072e723Skettenis
418b072e723Skettenis error = 0;
419b072e723Skettenis
420b072e723Skettenis switch (cmd) {
421b072e723Skettenis case TIOCSBRK:
422b072e723Skettenis vcctty_send_break(sc);
423b072e723Skettenis break;
424b072e723Skettenis case TIOCCBRK:
425b072e723Skettenis /* BREAK gets cleared automatically. */
426b072e723Skettenis break;
427b072e723Skettenis default:
428b072e723Skettenis error = ENOTTY;
429b072e723Skettenis break;
430b072e723Skettenis }
431b072e723Skettenis
432b072e723Skettenis return (error);
433b072e723Skettenis }
434b072e723Skettenis
435b072e723Skettenis void
vccttystart(struct tty * tp)436b072e723Skettenis vccttystart(struct tty *tp)
437b072e723Skettenis {
438b072e723Skettenis struct vcctty_softc *sc = vcctty_cd.cd_devs[minor(tp->t_dev)];
439b072e723Skettenis int s;
440b072e723Skettenis
441b072e723Skettenis s = spltty();
442ae51ad54Skettenis if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
443b072e723Skettenis splx(s);
444b072e723Skettenis return;
445b072e723Skettenis }
4464cc8800eSnicm ttwakeupwr(tp);
447b072e723Skettenis tp->t_state |= TS_BUSY;
448ae51ad54Skettenis if (tp->t_outq.c_cc > 0)
449ae51ad54Skettenis vcctty_send_data(sc, tp);
450b072e723Skettenis tp->t_state &= ~TS_BUSY;
451ae51ad54Skettenis if (tp->t_outq.c_cc > 0) {
452ae51ad54Skettenis tp->t_state |= TS_TIMEOUT;
453ae51ad54Skettenis timeout_add(&tp->t_rstrt_to, 1);
454ae51ad54Skettenis }
455b072e723Skettenis splx(s);
456b072e723Skettenis }
457b072e723Skettenis
458b072e723Skettenis int
vccttystop(struct tty * tp,int flag)459b072e723Skettenis vccttystop(struct tty *tp, int flag)
460b072e723Skettenis {
461b072e723Skettenis int s;
462b072e723Skettenis
463b072e723Skettenis s = spltty();
464b072e723Skettenis if (tp->t_state & TS_BUSY)
465b072e723Skettenis if ((tp->t_state & TS_TTSTOP) == 0)
466b072e723Skettenis tp->t_state |= TS_FLUSH;
467b072e723Skettenis splx(s);
468b072e723Skettenis return (0);
469b072e723Skettenis }
470b072e723Skettenis
471b072e723Skettenis struct tty *
vccttytty(dev_t dev)472b072e723Skettenis vccttytty(dev_t dev)
473b072e723Skettenis {
474b072e723Skettenis struct vcctty_softc *sc;
475b072e723Skettenis int unit = minor(dev);
476b072e723Skettenis
477e7c7aa84Smiod if (unit >= vcctty_cd.cd_ndevs)
478b072e723Skettenis return (NULL);
479b072e723Skettenis sc = vcctty_cd.cd_devs[unit];
480b072e723Skettenis if (sc == NULL)
481b072e723Skettenis return (NULL);
482b072e723Skettenis
483b072e723Skettenis return sc->sc_tty;
484b072e723Skettenis }
485b072e723Skettenis
486b072e723Skettenis int
vccttyparam(struct tty * tp,struct termios * t)487b072e723Skettenis vccttyparam(struct tty *tp, struct termios *t)
488b072e723Skettenis {
489b072e723Skettenis tp->t_ispeed = t->c_ispeed;
490b072e723Skettenis tp->t_ospeed = t->c_ospeed;
491b072e723Skettenis tp->t_cflag = t->c_cflag;
492b072e723Skettenis return (0);
493b072e723Skettenis }
494f62a4008Skettenis
495f62a4008Skettenis int
vccttyhwiflow(struct tty * tp,int stop)496f62a4008Skettenis vccttyhwiflow(struct tty *tp, int stop)
497f62a4008Skettenis {
498f62a4008Skettenis struct vcctty_softc *sc = vcctty_cd.cd_devs[minor(tp->t_dev)];
499b3a497edSkettenis uint64_t state = stop ? INTR_DISABLED : INTR_ENABLED;
500f62a4008Skettenis
501b3a497edSkettenis cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, state);
502b3a497edSkettenis cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, state);
503f62a4008Skettenis
504f62a4008Skettenis return (1);
505f62a4008Skettenis }
506