No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / arm / at91 / at91usart.c
blobbcb7dd4c7cf8639258e143002eb9a68045650a6d
1 /* $Id: at91usart.c,v 1.3 2009/10/23 06:53:13 snj Exp $ */
2 /* $NetBSD: at91usart.c,v 1.2 2008/07/03 01:15:39 matt Exp $ */
4 /*
5 * Copyright (c) 2007 Embedtronics Oy. All rights reserved.
7 * Copyright (c) 1998, 1999, 2001, 2002, 2004 The NetBSD Foundation, Inc.
8 * All rights reserved.
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Jesse Off
13 * This code is derived from software contributed to The NetBSD Foundation
14 * by Ichiro FUKUHARA and Naoto Shimazaki.
16 * This code is derived from software contributed to The NetBSD Foundation
17 * by IWAMOTO Toshihiro.
19 * This code is derived from software contributed to The NetBSD Foundation
20 * by Charles M. Hannum.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
31 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
32 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
45 * Copyright (c) 1991 The Regents of the University of California.
46 * All rights reserved.
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * 3. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
72 * @(#)com.c 7.5 (Berkeley) 5/16/91
76 * TODO: hardware flow control
79 #include <sys/cdefs.h>
80 __KERNEL_RCSID(0, "$NetBSD: at91usart.c,v 1.2 2008/07/03 01:15:39 matt Exp $");
82 #include "opt_ddb.h"
83 #include "opt_kgdb.h"
85 #include "rnd.h"
86 #if NRND > 0 && defined(RND_COM)
87 #include <sys/rnd.h>
88 #endif
90 #ifdef NOTYET
92 * Override cnmagic(9) macro before including <sys/systm.h>.
93 * We need to know if cn_check_magic triggered debugger, so set a flag.
94 * Callers of cn_check_magic must declare int cn_trapped = 0;
95 * XXX: this is *ugly*!
97 #define cn_trap() \
98 do { \
99 console_debugger(); \
100 cn_trapped = 1; \
101 } while (/* CONSTCOND */ 0)
102 #endif /* NOTYET */
105 #include <sys/param.h>
106 #include <sys/systm.h>
107 #include <sys/types.h>
108 #include <sys/conf.h>
109 #include <sys/file.h>
110 #include <sys/device.h>
111 #include <sys/kernel.h>
112 #include <sys/malloc.h>
113 #include <sys/tty.h>
114 #include <sys/uio.h>
115 #include <sys/vnode.h>
116 #include <sys/kauth.h>
118 #include <machine/intr.h>
119 #include <machine/bus.h>
121 #include <arm/at91/at91reg.h>
122 #include <arm/at91/at91var.h>
123 #include <arm/at91/at91usartreg.h>
124 #include <arm/at91/at91usartvar.h>
126 #include <dev/cons.h>
128 static int at91usart_param(struct tty *, struct termios *);
129 static void at91usart_start(struct tty *);
130 static int at91usart_hwiflow(struct tty *, int);
132 #if 0
133 static u_int cflag2lcrhi(tcflag_t);
134 #endif
135 static void at91usart_set(struct at91usart_softc *);
137 #if NOTYET
138 int at91usart_cn_getc(dev_t);
139 void at91usart_cn_putc(dev_t, int);
140 void at91usart_cn_pollc(dev_t, int);
141 void at91usart_cn_probe(struct consdev *);
142 void at91usart_cn_init(struct consdev *);
144 static struct at91usart_cons_softc {
145 bus_space_tag_t sc_iot;
146 bus_space_handle_t sc_ioh;
147 bus_addr_t sc_hwbase;
148 int sc_ospeed;
149 tcflag_t sc_cflag;
150 int sc_attached;
152 u_int8_t *sc_rx_ptr;
153 u_int8_t sc_rx_fifo[64];
154 } usart_cn_sc;
156 static struct cnm_state at91usart_cnm_state;
157 #endif /* NOTYET */
159 static void at91usart_soft(void* arg);
160 inline static void at91usart_txsoft(struct at91usart_softc *, struct tty *);
161 inline static void at91usart_rxsoft(struct at91usart_softc *, struct tty *, unsigned csr);
163 #define PDC_BLOCK_SIZE 64
165 //CFATTACH_DECL(at91usart, sizeof(struct at91usart_softc),
166 // at91usart_match, at91usart_attach, NULL, NULL);
168 //#define USART_DEBUG 10
170 #ifdef USART_DEBUG
171 int usart_debug = USART_DEBUG;
172 #define DPRINTFN(n,fmt) if (usart_debug >= (n)) printf fmt
173 #else
174 #define DPRINTFN(n,fmt)
175 #endif
177 extern struct cfdriver at91usart_cd;
179 dev_type_open(at91usart_open);
180 dev_type_close(at91usart_close);
181 dev_type_read(at91usart_read);
182 dev_type_write(at91usart_write);
183 dev_type_ioctl(at91usart_ioctl);
184 dev_type_stop(at91usart_stop);
185 dev_type_tty(at91usart_tty);
186 dev_type_poll(at91usart_poll);
188 const struct cdevsw at91usart_cdevsw = {
189 at91usart_open, at91usart_close, at91usart_read, at91usart_write, at91usart_ioctl,
190 at91usart_stop, at91usart_tty, at91usart_poll, nommap, ttykqfilter, D_TTY
193 #if NOTYET
194 struct consdev at91usart_cons = {
195 at91usart_cn_probe, NULL, at91usart_cn_getc, at91usart_cn_putc, at91usart_cn_pollc, NULL,
196 NULL, NULL, NODEV, CN_REMOTE
198 #endif /* NOTYET */
200 #ifndef DEFAULT_COMSPEED
201 #define DEFAULT_COMSPEED 115200
202 #endif
204 #define COMUNIT_MASK 0x7ffff
205 #define COMDIALOUT_MASK 0x80000
207 #define COMUNIT(x) (minor(x) & COMUNIT_MASK)
208 #define COMDIALOUT(x) (minor(x) & COMDIALOUT_MASK)
210 #define COM_ISALIVE(sc) ((sc)->enabled != 0 && device_is_active((sc)->sc_dev))
212 static inline void
213 at91usart_writereg(struct at91usart_softc *sc, int reg, u_int val)
215 bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val);
218 static inline u_int
219 at91usart_readreg(struct at91usart_softc *sc, int reg)
221 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg);
223 #if 0
224 static int
225 at91usart_match(device_t parent, cfdata_t cf, void *aux)
227 if (strcmp(cf->cf_name, "at91usart") == 0)
228 return 1;
229 return 0;
231 #endif
232 static int at91usart_intr(void* arg);
234 void
235 at91usart_attach_subr(struct at91usart_softc *sc, struct at91bus_attach_args *sa)
237 struct tty *tp;
238 int err;
240 printf("\n");
242 if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, &sc->sc_ioh))
243 panic("%s: Cannot map registers", device_xname(sc->sc_dev));
245 sc->sc_iot = sa->sa_iot;
246 sc->sc_hwbase = sa->sa_addr;
247 sc->sc_dmat = sa->sa_dmat;
248 sc->sc_pid = sa->sa_pid;
250 /* allocate fifos */
251 err = at91pdc_alloc_fifo(sc->sc_dmat, &sc->sc_rx_fifo, AT91USART_RING_SIZE, BUS_DMA_READ | BUS_DMA_STREAMING);
252 if (err)
253 panic("%s: cannot allocate rx fifo", device_xname(sc->sc_dev));
255 err = at91pdc_alloc_fifo(sc->sc_dmat, &sc->sc_tx_fifo, AT91USART_RING_SIZE, BUS_DMA_WRITE | BUS_DMA_STREAMING);
256 if (err)
257 panic("%s: cannot allocate tx fifo", device_xname(sc->sc_dev));
259 /* initialize uart */
260 at91_peripheral_clock(sc->sc_pid, 1);
262 at91usart_writereg(sc, US_IDR, -1);
263 at91usart_writereg(sc, US_RTOR, 12); // 12-bit timeout
264 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
265 at91_intr_establish(sa->sa_pid, IPL_TTY, INTR_HIGH_LEVEL, at91usart_intr, sc);
266 USART_INIT(sc, 115200U);
268 #ifdef NOTYET
269 if (sc->sc_iot == usart_cn_sc.sc_iot
270 && sc->sc_hwbase == usart_cn_sc.sc_hwbase) {
271 usart_cn_sc.sc_attached = 1;
272 /* Make sure the console is always "hardwired". */
273 delay(10000); /* wait for output to finish */
274 SET(sc->sc_hwflags, COM_HW_CONSOLE);
275 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
276 SET(sc->sc_ier, USART_INT_RXRDY);
277 USARTREG(USART_IER) = USART_INT_RXRDY; // @@@@@
279 #endif // NOTYET
281 tp = ttymalloc();
282 tp->t_oproc = at91usart_start;
283 tp->t_param = at91usart_param;
284 tp->t_hwiflow = at91usart_hwiflow;
286 sc->sc_tty = tp;
288 tty_attach(tp);
290 #if NOTYET
291 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
292 int maj;
294 /* locate the major number */
295 maj = cdevsw_lookup_major(&at91usart_cdevsw);
297 cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev));
299 aprint_normal("%s: console (maj %u min %u cn_dev %u)\n",
300 device_xname(sc->sc_dev), maj, device_unit(sc->sc_dev),
301 cn_tab->cn_dev);
303 #endif /* NOTYET */
305 sc->sc_si = softint_establish(SOFTINT_SERIAL, at91usart_soft, sc);
307 #if NRND > 0 && defined(RND_COM)
308 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
309 RND_TYPE_TTY, 0);
310 #endif
312 /* if there are no enable/disable functions, assume the device
313 is always enabled */
314 if (!sc->enable)
315 sc->enabled = 1;
317 /* XXX configure register */
318 /* xxx_config(sc) */
320 SET(sc->sc_hwflags, COM_HW_DEV_OK);
323 static int
324 at91usart_param(struct tty *tp, struct termios *t)
326 struct at91usart_softc *sc
327 = device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev));
328 int s;
330 if (COM_ISALIVE(sc) == 0)
331 return (EIO);
333 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
334 return (EINVAL);
337 * For the console, always force CLOCAL and !HUPCL, so that the port
338 * is always active.
340 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
341 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
342 SET(t->c_cflag, CLOCAL);
343 CLR(t->c_cflag, HUPCL);
347 * If there were no changes, don't do anything. This avoids dropping
348 * input and improves performance when all we did was frob things like
349 * VMIN and VTIME.
351 if (tp->t_ospeed == t->c_ospeed &&
352 tp->t_cflag == t->c_cflag)
353 return (0);
355 s = spltty();
357 sc->sc_brgr = (AT91_MSTCLK / 16 + t->c_ospeed / 2) / t->c_ospeed;
359 /* And copy to tty. */
360 tp->t_ispeed = 0;
361 tp->t_ospeed = t->c_ospeed;
362 tp->t_cflag = t->c_cflag;
363 at91usart_set(sc);
365 splx(s);
368 * Update the tty layer's idea of the carrier bit.
369 * We tell tty the carrier is always on.
371 (void) (*tp->t_linesw->l_modem)(tp, 1);
373 #ifdef COM_DEBUG
374 if (com_debug)
375 comstatus(sc, "comparam ");
376 #endif
378 /* tell the upper layer about hwflow.. */
379 if (sc->hwflow)
380 (*sc->hwflow)(sc, t->c_cflag);
382 return (0);
385 static int
386 at91usart_hwiflow(struct tty *tp, int block)
388 if (block) {
389 /* tty discipline wants to block */
390 } else {
391 /* tty discipline wants to unblock */
393 return (0);
396 static __inline void
397 at91usart_start_tx(struct at91usart_softc *sc)
399 if (!sc->start_tx)
400 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTEN);
401 else
402 (*sc->start_tx)(sc);
405 static __inline void
406 at91usart_stop_tx(struct at91usart_softc *sc)
408 if (!sc->stop_tx)
409 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS);
410 else
411 (*sc->stop_tx)(sc);
414 static __inline void
415 at91usart_rx_started(struct at91usart_softc *sc)
417 if (sc->rx_started)
418 (*sc->rx_started)(sc);
421 static __inline void
422 at91usart_rx_stopped(struct at91usart_softc *sc)
424 if (sc->rx_stopped)
425 (*sc->rx_stopped)(sc);
428 static __inline void
429 at91usart_rx_rts_ctl(struct at91usart_softc *sc, int enabled)
431 if (sc->rx_rts_ctl)
432 (*sc->rx_rts_ctl)(sc, enabled);
435 static void
436 at91usart_filltx(struct at91usart_softc *sc)
438 struct tty *tp = sc->sc_tty;
439 int len;
440 void *dst;
442 // post write handler
443 AT91PDC_FIFO_POSTWRITE(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC,
444 &sc->sc_tx_fifo);
446 // copy more data to fifo:
447 if (sc->sc_tbc > 0
448 && (dst = AT91PDC_FIFO_WRPTR(&sc->sc_tx_fifo, &len)) != NULL) {
449 // copy data to fifo
450 if (len > sc->sc_tbc)
451 len = sc->sc_tbc;
452 memcpy(dst, sc->sc_tba, len);
453 sc->sc_tba += len;
454 if ((sc->sc_tbc -= len) <= 0)
455 CLR(tp->t_state, TS_BUSY);
456 // update fifo
457 AT91PDC_FIFO_WRITTEN(&sc->sc_tx_fifo, len);
458 // tell tty interface we've sent some bytes
459 ndflush(&tp->t_outq, len);
462 // start sending data...
463 if (AT91PDC_FIFO_PREWRITE(sc->sc_iot, sc->sc_ioh, sc->sc_dmat,
464 US_PDC, &sc->sc_tx_fifo, PDC_BLOCK_SIZE)) {
465 at91usart_start_tx(sc);
466 SET(sc->sc_ier, US_CSR_TXEMPTY | US_CSR_ENDTX);
467 } else {
468 CLR(sc->sc_ier, US_CSR_ENDTX);
472 static void
473 at91usart_start(struct tty *tp)
475 struct at91usart_softc *sc
476 = device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev));
477 int s;
479 if (COM_ISALIVE(sc) == 0) {
480 DPRINTFN(5, ("%s: %s / COM_ISALIVE == 0\n", device_xname(sc->sc_dev), __FUNCTION__));
481 return;
484 s = spltty();
485 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
486 DPRINTFN(5, ("%s: %s: TS_BUSY || TS_TIMEOUT || TS_TTSTOP\n", device_xname(sc->sc_dev), __FUNCTION__));
487 goto out;
490 if (!ttypull(tp))
491 goto out;
493 /* Grab the first contiguous region of buffer space. */
495 u_char *tba;
496 int tbc;
498 tba = tp->t_outq.c_cf;
499 tbc = ndqb(&tp->t_outq, 0);
501 sc->sc_tba = tba;
502 sc->sc_tbc = tbc;
505 SET(tp->t_state, TS_BUSY);
507 /* Output the first chunk of the contiguous buffer. */
508 at91usart_filltx(sc);
509 at91usart_writereg(sc, US_IER, sc->sc_ier);
510 DPRINTFN(5, ("%s: %s, ier=%08x (csr=%08x)\n", device_xname(sc->sc_dev), __FUNCTION__, sc->sc_ier, at91usart_readreg(sc, US_CSR)));
512 out:
513 splx(s);
515 return;
518 static __inline__ void
519 at91usart_break(struct at91usart_softc *sc, int onoff)
521 at91usart_writereg(sc, US_CR, onoff ? US_CR_STTBRK : US_CR_STPBRK);
524 static void
525 at91usart_shutdown(struct at91usart_softc *sc)
527 int s;
529 s = spltty();
531 /* turn of dma */
532 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
533 at91usart_writereg(sc, US_PDC + PDC_TNCR, 0);
534 at91usart_writereg(sc, US_PDC + PDC_TCR, 0);
535 at91usart_writereg(sc, US_PDC + PDC_RNCR, 0);
536 at91usart_writereg(sc, US_PDC + PDC_RCR, 0);
538 /* Turn off interrupts. */
539 at91usart_writereg(sc, US_IDR, -1);
541 /* Clear any break condition set with TIOCSBRK. */
542 at91usart_break(sc, 0);
543 at91usart_set(sc);
545 if (sc->disable) {
546 #ifdef DIAGNOSTIC
547 if (!sc->enabled)
548 panic("at91usart_shutdown: not enabled?");
549 #endif
550 (*sc->disable)(sc);
551 sc->enabled = 0;
553 splx(s);
557 at91usart_open(dev_t dev, int flag, int mode, struct lwp *l)
559 struct at91usart_softc *sc;
560 struct tty *tp;
561 int s;
562 int error;
564 sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
565 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK))
566 return (ENXIO);
568 if (!device_is_active(sc->sc_dev))
569 return (ENXIO);
571 #ifdef KGDB
573 * If this is the kgdb port, no other use is permitted.
575 if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
576 return (EBUSY);
577 #endif
579 tp = sc->sc_tty;
581 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
582 return (EBUSY);
584 s = spltty();
587 * Do the following iff this is a first open.
589 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
590 struct termios t;
592 tp->t_dev = dev;
594 if (sc->enable) {
595 if ((*sc->enable)(sc)) {
596 splx(s);
597 printf("%s: device enable failed\n",
598 device_xname(sc->sc_dev));
599 return (EIO);
601 sc->enabled = 1;
602 #if 0
603 /* XXXXXXXXXXXXXXX */
604 com_config(sc);
605 #endif
608 /* reset fifos: */
609 AT91PDC_RESET_FIFO(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC, &sc->sc_rx_fifo, 0);
610 AT91PDC_RESET_FIFO(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC, &sc->sc_tx_fifo, 1);
612 /* reset receive */
613 at91usart_writereg(sc, US_CR, US_CR_RSTSTA | US_CR_STTTO);
615 /* Turn on interrupts. */
616 sc->sc_ier = US_CSR_ENDRX|US_CSR_RXBUFF|US_CSR_TIMEOUT|US_CSR_RXBRK;
617 at91usart_writereg(sc, US_IER, sc->sc_ier);
619 /* enable DMA: */
620 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_RXTEN);
623 * Initialize the termios status to the defaults. Add in the
624 * sticky bits from TIOCSFLAGS.
626 t.c_ispeed = 0;
627 /* if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
628 t.c_ospeed = usart_cn_sc.sc_ospeed;
629 t.c_cflag = usart_cn_sc.sc_cflag;
630 } else*/ {
631 t.c_ospeed = TTYDEF_SPEED;
632 t.c_cflag = TTYDEF_CFLAG;
634 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
635 SET(t.c_cflag, CLOCAL);
636 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
637 SET(t.c_cflag, CRTSCTS);
638 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
639 SET(t.c_cflag, MDMBUF);
641 /* Make sure at91usart_param() will do something. */
642 tp->t_ospeed = 0;
643 (void) at91usart_param(tp, &t);
644 tp->t_iflag = TTYDEF_IFLAG;
645 tp->t_oflag = TTYDEF_OFLAG;
646 tp->t_lflag = TTYDEF_LFLAG;
647 ttychars(tp);
648 ttsetwater(tp);
650 /* and unblock. */
651 CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
653 #ifdef COM_DEBUG
654 if (at91usart_debug)
655 comstatus(sc, "at91usart_open ");
656 #endif
660 splx(s);
662 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
663 if (error)
664 goto bad;
666 error = (*tp->t_linesw->l_open)(dev, tp);
667 if (error)
668 goto bad;
670 return (0);
672 bad:
673 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
675 * We failed to open the device, and nobody else had it opened.
676 * Clean up the state as appropriate.
678 at91usart_shutdown(sc);
681 return (error);
685 at91usart_close(dev_t dev, int flag, int mode, struct lwp *l)
687 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
688 struct tty *tp = sc->sc_tty;
690 /* XXX This is for cons.c. */
691 if (!ISSET(tp->t_state, TS_ISOPEN))
692 return (0);
694 (*tp->t_linesw->l_close)(tp, flag);
695 ttyclose(tp);
697 if (COM_ISALIVE(sc) == 0)
698 return (0);
700 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
702 * Although we got a last close, the device may still be in
703 * use; e.g. if this was the dialout node, and there are still
704 * processes waiting for carrier on the non-dialout node.
706 at91usart_shutdown(sc);
709 return (0);
713 at91usart_read(dev_t dev, struct uio *uio, int flag)
715 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
716 struct tty *tp = sc->sc_tty;
718 if (COM_ISALIVE(sc) == 0)
719 return (EIO);
721 return ((*tp->t_linesw->l_read)(tp, uio, flag));
725 at91usart_write(dev_t dev, struct uio *uio, int flag)
727 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
728 struct tty *tp = sc->sc_tty;
730 if (COM_ISALIVE(sc) == 0)
731 return (EIO);
733 return ((*tp->t_linesw->l_write)(tp, uio, flag));
737 at91usart_poll(dev_t dev, int events, struct lwp *l)
739 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
740 struct tty *tp = sc->sc_tty;
742 if (COM_ISALIVE(sc) == 0)
743 return (EIO);
745 return ((*tp->t_linesw->l_poll)(tp, events, l));
748 struct tty *
749 at91usart_tty(dev_t dev)
751 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
752 struct tty *tp = sc->sc_tty;
754 return (tp);
758 at91usart_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
760 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
761 struct tty *tp = sc->sc_tty;
762 int error;
763 int s;
765 if (COM_ISALIVE(sc) == 0)
766 return (EIO);
768 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
769 if (error != EPASSTHROUGH)
770 return (error);
772 error = ttioctl(tp, cmd, data, flag, l);
773 if (error != EPASSTHROUGH)
774 return (error);
776 error = 0;
778 s = spltty();
780 switch (cmd) {
781 case TIOCSBRK:
782 at91usart_break(sc, 1);
783 break;
785 case TIOCCBRK:
786 at91usart_break(sc, 0);
787 break;
789 case TIOCGFLAGS:
790 *(int *)data = sc->sc_swflags;
791 break;
793 case TIOCSFLAGS:
794 error = kauth_authorize_device_tty(l->l_cred,
795 KAUTH_DEVICE_TTY_PRIVSET, tp);
796 if (error)
797 break;
798 sc->sc_swflags = *(int *)data;
799 break;
801 default:
802 error = EPASSTHROUGH;
803 break;
806 splx(s);
808 return (error);
812 * Stop output on a line.
814 void
815 at91usart_stop(struct tty *tp, int flag)
817 struct at91usart_softc *sc
818 = device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev));
819 int s;
821 s = spltty();
822 if (ISSET(tp->t_state, TS_BUSY)) {
823 /* Stop transmitting at the next chunk. */
824 sc->sc_tbc = 0;
825 if (!ISSET(tp->t_state, TS_TTSTOP))
826 SET(tp->t_state, TS_FLUSH);
828 splx(s);
831 #if 0
832 static u_int
833 cflag2lcrhi(tcflag_t cflag)
835 u_int32_t mr;
837 switch (cflag & CSIZE) {
838 default:
839 mr = 0x0;
840 break;
842 #if 0
843 mr |= (cflag & PARENB) ? LinCtrlHigh_PEN : 0;
844 mr |= (cflag & PARODD) ? 0 : LinCtrlHigh_EPS;
845 mr |= (cflag & CSTOPB) ? LinCtrlHigh_STP2 : 0;
846 mr |= LinCtrlHigh_FEN; /* FIFO always enabled */
847 #endif
848 mr |= USART_MR_PAR_NONE;
849 return (mr);
851 #endif
854 static void
855 at91usart_set(struct at91usart_softc *sc)
857 at91usart_writereg(sc, US_MR, US_MR_CHRL_8 | US_MR_PAR_NONE | US_MR_NBSTOP_1);
858 at91usart_writereg(sc, US_BRGR, sc->sc_brgr);
859 at91usart_writereg(sc, US_CR, US_CR_TXEN | US_CR_RXEN); // @@@ just in case
862 #if NOTYET
864 at91usart_cn_attach(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t ioh,
865 u_int32_t mstclk, int ospeed, tcflag_t cflag)
867 cn_tab = &at91usart_cons;
868 cn_init_magic(&at91usart_cnm_state);
869 cn_set_magic("\047\001");
871 usart_cn_sc.sc_iot = iot;
872 usart_cn_sc.sc_ioh = ioh;
873 usart_cn_sc.sc_hwbase = iobase;
874 usart_cn_sc.sc_ospeed = ospeed;
875 usart_cn_sc.sc_cflag = cflag;
877 USART_INIT(mstclk, ospeed);
879 return (0);
882 void
883 at91usart_cn_probe(struct consdev *cp)
885 cp->cn_pri = CN_REMOTE;
888 void
889 at91usart_cn_pollc(dev_t dev, int on)
891 if (on) {
892 // enable polling mode
893 USARTREG(US_IDR) = USART_INT_RXRDY;
894 } else {
895 // disable polling mode
896 USARTREG(US_IER) = USART_INT_RXRDY;
900 void
901 at91usart_cn_putc(dev_t dev, int c)
903 int s;
904 #if 0
905 bus_space_tag_t iot = usart_cn_sc.sc_iot;
906 bus_space_handle_t ioh = usart_cn_sc.sc_ioh;
907 #endif
908 s = spltty();
910 USART_PUTC(c);
912 #ifdef DEBUG
913 if (c == '\r') {
914 while((USARTREG(USART_SR) & USART_SR_TXEMPTY) == 0)
917 #endif
919 splx(s);
923 at91usart_cn_getc(dev_t dev)
925 int c, sr;
926 int s;
927 #if 0
928 bus_space_tag_t iot = usart_cn_sc.sc_iot;
929 bus_space_handle_t ioh = usart_cn_sc.sc_ioh;
930 #endif
932 s = spltty();
934 while ((c = USART_PEEKC()) == -1) {
935 splx(s);
936 s = spltty();
939 sr = USARTREG(USART_SR);
940 if (ISSET(sr, USART_SR_FRAME) && c == 0) {
941 USARTREG(USART_CR) = USART_CR_RSTSTA; // reset status bits
942 c = CNC_BREAK;
944 #ifdef DDB
945 extern int db_active;
946 if (!db_active)
947 #endif
949 int cn_trapped = 0; /* unused */
951 cn_check_magic(dev, c, at91usart_cnm_state);
953 splx(s);
955 c &= 0xff;
957 return (c);
959 #endif /* NOTYET */
961 inline static void
962 at91usart_rxsoft(struct at91usart_softc *sc, struct tty *tp, unsigned csr)
964 u_char *start, *get, *end;
965 int cc;
967 AT91PDC_FIFO_POSTREAD(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC,
968 &sc->sc_rx_fifo);
970 if (ISSET(csr, US_CSR_TIMEOUT | US_CSR_RXBRK))
971 at91usart_rx_stopped(sc);
973 while ((start = AT91PDC_FIFO_RDPTR(&sc->sc_rx_fifo, &cc)) != NULL) {
974 int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
975 int code;
977 if (!ISSET(csr, US_CSR_TIMEOUT | US_CSR_RXBRK))
978 at91usart_rx_started(sc);
980 for (get = start, end = start + cc; get < end; get++) {
981 code = *get;
982 if ((*rint)(code, tp) == -1) {
984 * The line discipline's buffer is out of space.
986 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
988 * We're either not using flow control, or the
989 * line discipline didn't tell us to block for
990 * some reason. Either way, we have no way to
991 * know when there's more space available, so
992 * just drop the rest of the data.
994 get = end;
995 printf("%s: receive missing data!\n",
996 device_xname(sc->sc_dev));
997 } else {
999 * Don't schedule any more receive processing
1000 * until the line discipline tells us there's
1001 * space available (through comhwiflow()).
1002 * Leave the rest of the data in the input
1003 * buffer.
1005 SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
1007 break;
1011 // tell we've read some bytes...
1012 AT91PDC_FIFO_READ(&sc->sc_rx_fifo, get - start);
1014 if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED))
1015 break;
1018 // h/w flow control hook:
1019 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
1020 at91usart_rx_rts_ctl(sc, (AT91PDC_FIFO_SPACE(&sc->sc_rx_fifo) > PDC_BLOCK_SIZE * 2));
1022 // write next pointer if USART is ready:
1023 if (AT91PDC_FIFO_PREREAD(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC,
1024 &sc->sc_rx_fifo, PDC_BLOCK_SIZE)) {
1025 SET(sc->sc_ier, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK);
1026 } else {
1027 CLR(sc->sc_ier, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK);
1031 inline static void
1032 at91usart_txsoft(struct at91usart_softc *sc, struct tty *tp)
1034 at91usart_filltx(sc);
1035 if (!ISSET(tp->t_state, TS_BUSY))
1036 (*tp->t_linesw->l_start)(tp);
1040 static void
1041 at91usart_soft(void* arg)
1043 struct at91usart_softc *sc = arg;
1044 int s;
1045 u_int csr;
1047 if (COM_ISALIVE(sc) == 0)
1048 return;
1050 s = spltty();
1051 csr = sc->sc_csr;
1052 while (csr != 0) {
1053 if ((csr &= sc->sc_ier) == 0)
1054 break;
1055 // splx(s);
1056 DPRINTFN(5, ("%s: %s / csr = 0x%08x\n", device_xname(sc->sc_dev), __FUNCTION__, csr));
1057 if (ISSET(csr, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK)) {
1058 /* receive interrupt */
1059 if (ISSET(csr, US_CSR_RXBRK)) {
1060 // break received!
1061 at91usart_writereg(sc, US_CR, US_CR_RSTSTA | US_CR_STTTO);
1062 } else if (ISSET(csr, US_CSR_TIMEOUT)) {
1063 // timeout received
1064 at91usart_writereg(sc, US_CR, US_CR_STTTO);
1066 at91usart_rxsoft(sc, sc->sc_tty, csr);
1068 if (ISSET(csr, US_CSR_TXEMPTY)) {
1069 at91usart_stop_tx(sc);
1070 CLR(sc->sc_ier, US_CSR_TXEMPTY);
1071 if (AT91PDC_FIFO_EMPTY(&sc->sc_tx_fifo)) {
1072 // everything sent!
1073 if (ISSET(sc->sc_tty->t_state, TS_FLUSH))
1074 CLR(sc->sc_tty->t_state, TS_FLUSH);
1077 if (ISSET(csr, US_CSR_TXEMPTY | US_CSR_ENDTX)) {
1078 /* transmit interrupt! */
1079 at91usart_txsoft(sc, sc->sc_tty);
1081 // s = spltty();
1082 csr = at91usart_readreg(sc, US_CSR);
1084 sc->sc_csr = 0;
1085 at91usart_writereg(sc, US_IER, sc->sc_ier); // re-enable interrupts
1086 splx(s);
1090 static int
1091 at91usart_intr(void* arg)
1093 struct at91usart_softc *sc = arg;
1094 u_int csr, imr;
1096 // get out if interrupts are not enabled
1097 imr = at91usart_readreg(sc, US_IMR);
1098 if (!imr)
1099 return 0;
1100 // get out if pending interrupt is not enabled
1101 csr = at91usart_readreg(sc, US_CSR);
1102 DPRINTFN(6,("%s: csr=%08X imr=%08X\n", device_xname(sc->sc_dev), csr, imr));
1103 if (!ISSET(csr, imr))
1104 return 0;
1106 // ok, we DO have some interrupts to serve! let softint do it
1107 sc->sc_csr = csr;
1108 at91usart_writereg(sc, US_IDR, -1);
1110 /* Wake up the poller. */
1111 softint_schedule(sc->sc_si);
1113 /* we're done for now */
1114 return (1);