1*433d6423SLionel Sambuc #include <minix/config.h>
2*433d6423SLionel Sambuc #include <minix/drivers.h>
3*433d6423SLionel Sambuc #include <minix/vm.h>
4*433d6423SLionel Sambuc #include <minix/type.h>
5*433d6423SLionel Sambuc #include <minix/board.h>
6*433d6423SLionel Sambuc #include <sys/mman.h>
7*433d6423SLionel Sambuc #include <assert.h>
8*433d6423SLionel Sambuc #include <signal.h>
9*433d6423SLionel Sambuc #include <termios.h>
10*433d6423SLionel Sambuc #include "omap_serial.h"
11*433d6423SLionel Sambuc #include "tty.h"
12*433d6423SLionel Sambuc
13*433d6423SLionel Sambuc #if NR_RS_LINES > 0
14*433d6423SLionel Sambuc
15*433d6423SLionel Sambuc #define UART_FREQ 48000000L /* timer frequency */
16*433d6423SLionel Sambuc #if 0
17*433d6423SLionel Sambuc #define DFLT_BAUD TSPEED_DEF /* default baud rate */
18*433d6423SLionel Sambuc #else
19*433d6423SLionel Sambuc #define DFLT_BAUD B115200 /* default baud rate */
20*433d6423SLionel Sambuc #endif
21*433d6423SLionel Sambuc
22*433d6423SLionel Sambuc
23*433d6423SLionel Sambuc #define RS_IBUFSIZE 40960 /* RS232 input buffer size */
24*433d6423SLionel Sambuc #define RS_OBUFSIZE 40960 /* RS232 output buffer size */
25*433d6423SLionel Sambuc
26*433d6423SLionel Sambuc /* Input buffer watermarks.
27*433d6423SLionel Sambuc * The external device is asked to stop sending when the buffer
28*433d6423SLionel Sambuc * exactly reaches high water, or when TTY requests it. Sending restarts
29*433d6423SLionel Sambuc * when the input buffer empties below the low watermark.
30*433d6423SLionel Sambuc */
31*433d6423SLionel Sambuc #define RS_ILOWWATER (1 * RS_IBUFSIZE / 4)
32*433d6423SLionel Sambuc #define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
33*433d6423SLionel Sambuc
34*433d6423SLionel Sambuc /* Output buffer low watermark.
35*433d6423SLionel Sambuc * TTY is notified when the output buffer empties below the low watermark, so
36*433d6423SLionel Sambuc * it may continue filling the buffer if doing a large write.
37*433d6423SLionel Sambuc */
38*433d6423SLionel Sambuc #define RS_OLOWWATER (1 * RS_OBUFSIZE / 4)
39*433d6423SLionel Sambuc
40*433d6423SLionel Sambuc /* Macros to handle flow control.
41*433d6423SLionel Sambuc * Interrupts must be off when they are used.
42*433d6423SLionel Sambuc * Time is critical - already the function call for outb() is annoying.
43*433d6423SLionel Sambuc * If outb() can be done in-line, tests to avoid it can be dropped.
44*433d6423SLionel Sambuc * istart() tells external device we are ready by raising RTS.
45*433d6423SLionel Sambuc * istop() tells external device we are not ready by dropping RTS.
46*433d6423SLionel Sambuc * DTR is kept high all the time (it probably should be raised by open and
47*433d6423SLionel Sambuc * dropped by close of the device).
48*433d6423SLionel Sambuc * OUT2 is also kept high all the time.
49*433d6423SLionel Sambuc */
50*433d6423SLionel Sambuc #define istart(rs) \
51*433d6423SLionel Sambuc (serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS|UART_MCR_DTR),\
52*433d6423SLionel Sambuc (rs)->idevready = TRUE)
53*433d6423SLionel Sambuc #define istop(rs) \
54*433d6423SLionel Sambuc (serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_DTR), \
55*433d6423SLionel Sambuc (rs)->idevready = FALSE)
56*433d6423SLionel Sambuc
57*433d6423SLionel Sambuc /* Macro to tell if device is ready. The rs->cts field is set to UART_MSR_CTS
58*433d6423SLionel Sambuc * if CLOCAL is in effect for a line without a CTS wire.
59*433d6423SLionel Sambuc */
60*433d6423SLionel Sambuc #define devready(rs) ((serial_in(rs, OMAP3_MSR) | rs->cts) & UART_MSR_CTS)
61*433d6423SLionel Sambuc
62*433d6423SLionel Sambuc /* Macro to tell if transmitter is ready. */
63*433d6423SLionel Sambuc #define txready(rs) (serial_in(rs, OMAP3_LSR) & UART_LSR_THRE)
64*433d6423SLionel Sambuc
65*433d6423SLionel Sambuc /* RS232 device structure, one per device. */
66*433d6423SLionel Sambuc typedef struct rs232 {
67*433d6423SLionel Sambuc tty_t *tty; /* associated TTY structure */
68*433d6423SLionel Sambuc
69*433d6423SLionel Sambuc int icount; /* number of bytes in the input buffer */
70*433d6423SLionel Sambuc char *ihead; /* next free spot in input buffer */
71*433d6423SLionel Sambuc char *itail; /* first byte to give to TTY */
72*433d6423SLionel Sambuc char idevready; /* nonzero if we are ready to receive (RTS) */
73*433d6423SLionel Sambuc char cts; /* normally 0, but MS_CTS if CLOCAL is set */
74*433d6423SLionel Sambuc
75*433d6423SLionel Sambuc unsigned char ostate; /* combination of flags: */
76*433d6423SLionel Sambuc #define ODONE 1 /* output completed (< output enable bits) */
77*433d6423SLionel Sambuc #define ORAW 2 /* raw mode for xoff disable (< enab. bits) */
78*433d6423SLionel Sambuc #define OWAKEUP 4 /* tty_wakeup() pending (asm code only) */
79*433d6423SLionel Sambuc #define ODEVREADY UART_MSR_CTS /* external device hardware ready (CTS) */
80*433d6423SLionel Sambuc #define OQUEUED 0x20 /* output buffer not empty */
81*433d6423SLionel Sambuc #define OSWREADY 0x40 /* external device software ready (no xoff) */
82*433d6423SLionel Sambuc #define ODEVHUP UART_MSR_DCD /* external device has dropped carrier */
83*433d6423SLionel Sambuc #define OSOFTBITS (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
84*433d6423SLionel Sambuc /* user-defined bits */
85*433d6423SLionel Sambuc #if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
86*433d6423SLionel Sambuc /* a weak sanity check */
87*433d6423SLionel Sambuc #error /* bits are not unique */
88*433d6423SLionel Sambuc #endif
89*433d6423SLionel Sambuc unsigned char oxoff; /* char to stop output */
90*433d6423SLionel Sambuc char inhibited; /* output inhibited? (follows tty_inhibited) */
91*433d6423SLionel Sambuc char drain; /* if set drain output and reconfigure line */
92*433d6423SLionel Sambuc int ocount; /* number of bytes in the output buffer */
93*433d6423SLionel Sambuc char *ohead; /* next free spot in output buffer */
94*433d6423SLionel Sambuc char *otail; /* next char to output */
95*433d6423SLionel Sambuc
96*433d6423SLionel Sambuc phys_bytes phys_base; /* UART physical base address (I/O map) */
97*433d6423SLionel Sambuc unsigned int reg_offset; /* UART register offset */
98*433d6423SLionel Sambuc unsigned int ier; /* copy of ier register */
99*433d6423SLionel Sambuc unsigned int scr; /* copy of scr register */
100*433d6423SLionel Sambuc unsigned int fcr; /* copy of fcr register */
101*433d6423SLionel Sambuc unsigned int dll; /* copy of dll register */
102*433d6423SLionel Sambuc unsigned int dlh; /* copy of dlh register */
103*433d6423SLionel Sambuc unsigned int uartclk; /* UART clock rate */
104*433d6423SLionel Sambuc
105*433d6423SLionel Sambuc unsigned char lstatus; /* last line status */
106*433d6423SLionel Sambuc int rx_overrun_events;
107*433d6423SLionel Sambuc
108*433d6423SLionel Sambuc int irq; /* irq for this line */
109*433d6423SLionel Sambuc int irq_hook_id; /* interrupt hook */
110*433d6423SLionel Sambuc int irq_hook_kernel_id; /* id as returned from sys_irqsetpolicy */
111*433d6423SLionel Sambuc
112*433d6423SLionel Sambuc char ibuf[RS_IBUFSIZE]; /* input buffer */
113*433d6423SLionel Sambuc char obuf[RS_OBUFSIZE]; /* output buffer */
114*433d6423SLionel Sambuc } rs232_t;
115*433d6423SLionel Sambuc
116*433d6423SLionel Sambuc static rs232_t rs_lines[NR_RS_LINES];
117*433d6423SLionel Sambuc
118*433d6423SLionel Sambuc typedef struct uart_port {
119*433d6423SLionel Sambuc phys_bytes base_addr;
120*433d6423SLionel Sambuc int irq;
121*433d6423SLionel Sambuc } uart_port_t;
122*433d6423SLionel Sambuc
123*433d6423SLionel Sambuc /* OMAP3 UART base addresses. */
124*433d6423SLionel Sambuc static uart_port_t dm37xx_ports[] = {
125*433d6423SLionel Sambuc { OMAP3_UART1_BASE, 72}, /* UART1 */
126*433d6423SLionel Sambuc { OMAP3_UART2_BASE, 73}, /* UART2 */
127*433d6423SLionel Sambuc { OMAP3_UART3_BASE, 74}, /* UART3 */
128*433d6423SLionel Sambuc { 0, 0 }
129*433d6423SLionel Sambuc };
130*433d6423SLionel Sambuc
131*433d6423SLionel Sambuc static uart_port_t am335x_ports[] = {
132*433d6423SLionel Sambuc { 0x44E09000 , 72 }, /* UART0 */
133*433d6423SLionel Sambuc { 0, 0 },
134*433d6423SLionel Sambuc { 0, 0 },
135*433d6423SLionel Sambuc { 0, 0 }
136*433d6423SLionel Sambuc };
137*433d6423SLionel Sambuc
138*433d6423SLionel Sambuc
139*433d6423SLionel Sambuc static int rs_write(tty_t *tp, int try);
140*433d6423SLionel Sambuc static void rs_echo(tty_t *tp, int c);
141*433d6423SLionel Sambuc static int rs_ioctl(tty_t *tp, int try);
142*433d6423SLionel Sambuc static void rs_config(rs232_t *rs);
143*433d6423SLionel Sambuc static int rs_read(tty_t *tp, int try);
144*433d6423SLionel Sambuc static int rs_icancel(tty_t *tp, int try);
145*433d6423SLionel Sambuc static int rs_ocancel(tty_t *tp, int try);
146*433d6423SLionel Sambuc static void rs_ostart(rs232_t *rs);
147*433d6423SLionel Sambuc static int rs_break_on(tty_t *tp, int try);
148*433d6423SLionel Sambuc static int rs_break_off(tty_t *tp, int try);
149*433d6423SLionel Sambuc static int rs_close(tty_t *tp, int try);
150*433d6423SLionel Sambuc static int rs_open(tty_t *tp, int try);
151*433d6423SLionel Sambuc static void rs232_handler(rs232_t *rs);
152*433d6423SLionel Sambuc static void rs_reset(rs232_t *rs);
153*433d6423SLionel Sambuc static unsigned int check_modem_status(rs232_t *rs);
154*433d6423SLionel Sambuc static int termios_baud_rate(struct termios *term);
155*433d6423SLionel Sambuc
156*433d6423SLionel Sambuc static inline unsigned int readw(vir_bytes addr);
157*433d6423SLionel Sambuc static inline unsigned int serial_in(rs232_t *rs, int offset);
158*433d6423SLionel Sambuc static inline void serial_out(rs232_t *rs, int offset, int val);
159*433d6423SLionel Sambuc static inline void writew(vir_bytes addr, int val);
160*433d6423SLionel Sambuc static void write_chars(rs232_t *rs);
161*433d6423SLionel Sambuc static void read_chars(rs232_t *rs, unsigned int status);
162*433d6423SLionel Sambuc
163*433d6423SLionel Sambuc static inline unsigned int
readw(vir_bytes addr)164*433d6423SLionel Sambuc readw(vir_bytes addr)
165*433d6423SLionel Sambuc {
166*433d6423SLionel Sambuc return *((volatile unsigned int *) addr);
167*433d6423SLionel Sambuc }
168*433d6423SLionel Sambuc
169*433d6423SLionel Sambuc static inline void
writew(vir_bytes addr,int val)170*433d6423SLionel Sambuc writew(vir_bytes addr, int val)
171*433d6423SLionel Sambuc {
172*433d6423SLionel Sambuc *((volatile unsigned int *) addr) = val;
173*433d6423SLionel Sambuc }
174*433d6423SLionel Sambuc
175*433d6423SLionel Sambuc static inline unsigned int
serial_in(rs232_t * rs,int offset)176*433d6423SLionel Sambuc serial_in(rs232_t *rs, int offset)
177*433d6423SLionel Sambuc {
178*433d6423SLionel Sambuc offset <<= rs->reg_offset;
179*433d6423SLionel Sambuc return readw(rs->phys_base + offset);
180*433d6423SLionel Sambuc }
181*433d6423SLionel Sambuc
182*433d6423SLionel Sambuc static inline void
serial_out(rs232_t * rs,int offset,int val)183*433d6423SLionel Sambuc serial_out(rs232_t *rs, int offset, int val)
184*433d6423SLionel Sambuc {
185*433d6423SLionel Sambuc offset <<= rs->reg_offset;
186*433d6423SLionel Sambuc writew(rs->phys_base + offset, val);
187*433d6423SLionel Sambuc }
188*433d6423SLionel Sambuc
189*433d6423SLionel Sambuc static void
rs_reset(rs232_t * rs)190*433d6423SLionel Sambuc rs_reset(rs232_t *rs)
191*433d6423SLionel Sambuc {
192*433d6423SLionel Sambuc u32_t syss;
193*433d6423SLionel Sambuc
194*433d6423SLionel Sambuc serial_out(rs, OMAP3_SYSC, UART_SYSC_SOFTRESET);
195*433d6423SLionel Sambuc
196*433d6423SLionel Sambuc /* Poll until done */
197*433d6423SLionel Sambuc do {
198*433d6423SLionel Sambuc syss = serial_in(rs, OMAP3_SYSS);
199*433d6423SLionel Sambuc } while (!(syss & UART_SYSS_RESETDONE));
200*433d6423SLionel Sambuc }
201*433d6423SLionel Sambuc
202*433d6423SLionel Sambuc static int
rs_write(register tty_t * tp,int try)203*433d6423SLionel Sambuc rs_write(register tty_t *tp, int try)
204*433d6423SLionel Sambuc {
205*433d6423SLionel Sambuc /* (*devwrite)() routine for RS232. */
206*433d6423SLionel Sambuc
207*433d6423SLionel Sambuc rs232_t *rs = tp->tty_priv;
208*433d6423SLionel Sambuc int r, count, ocount;
209*433d6423SLionel Sambuc
210*433d6423SLionel Sambuc if (rs->inhibited != tp->tty_inhibited) {
211*433d6423SLionel Sambuc /* Inhibition state has changed. */
212*433d6423SLionel Sambuc rs->ostate |= OSWREADY;
213*433d6423SLionel Sambuc if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;
214*433d6423SLionel Sambuc rs->inhibited = tp->tty_inhibited;
215*433d6423SLionel Sambuc }
216*433d6423SLionel Sambuc
217*433d6423SLionel Sambuc if (rs->drain) {
218*433d6423SLionel Sambuc /* Wait for the line to drain then reconfigure and continue
219*433d6423SLionel Sambuc * output. */
220*433d6423SLionel Sambuc if (rs->ocount > 0) return 0;
221*433d6423SLionel Sambuc rs->drain = FALSE;
222*433d6423SLionel Sambuc rs_config(rs);
223*433d6423SLionel Sambuc }
224*433d6423SLionel Sambuc /* While there is something to do. */
225*433d6423SLionel Sambuc for (;;) {
226*433d6423SLionel Sambuc ocount = buflen(rs->obuf) - rs->ocount;
227*433d6423SLionel Sambuc count = bufend(rs->obuf) - rs->ohead;
228*433d6423SLionel Sambuc if (count > ocount) count = ocount;
229*433d6423SLionel Sambuc if (count > tp->tty_outleft) count = tp->tty_outleft;
230*433d6423SLionel Sambuc if (count == 0 || tp->tty_inhibited) {
231*433d6423SLionel Sambuc if (try) return 0;
232*433d6423SLionel Sambuc break;
233*433d6423SLionel Sambuc }
234*433d6423SLionel Sambuc
235*433d6423SLionel Sambuc if (try) return 1;
236*433d6423SLionel Sambuc
237*433d6423SLionel Sambuc /* Copy from user space to the RS232 output buffer. */
238*433d6423SLionel Sambuc if (tp->tty_outcaller == KERNEL) {
239*433d6423SLionel Sambuc /* We're trying to print on kernel's behalf */
240*433d6423SLionel Sambuc memcpy(rs->ohead,
241*433d6423SLionel Sambuc (char *) tp->tty_outgrant + tp->tty_outcum,
242*433d6423SLionel Sambuc count);
243*433d6423SLionel Sambuc } else {
244*433d6423SLionel Sambuc if ((r = sys_safecopyfrom(tp->tty_outcaller,
245*433d6423SLionel Sambuc tp->tty_outgrant, tp->tty_outcum,
246*433d6423SLionel Sambuc (vir_bytes) rs->ohead, count)) != OK) {
247*433d6423SLionel Sambuc return 0;
248*433d6423SLionel Sambuc }
249*433d6423SLionel Sambuc }
250*433d6423SLionel Sambuc
251*433d6423SLionel Sambuc /* Perform output processing on the output buffer. */
252*433d6423SLionel Sambuc out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count,
253*433d6423SLionel Sambuc &ocount);
254*433d6423SLionel Sambuc if (count == 0) {
255*433d6423SLionel Sambuc break;
256*433d6423SLionel Sambuc }
257*433d6423SLionel Sambuc
258*433d6423SLionel Sambuc /* Assume echoing messed up by output. */
259*433d6423SLionel Sambuc tp->tty_reprint = TRUE;
260*433d6423SLionel Sambuc
261*433d6423SLionel Sambuc /* Bookkeeping. */
262*433d6423SLionel Sambuc rs->ocount += ocount;
263*433d6423SLionel Sambuc rs_ostart(rs);
264*433d6423SLionel Sambuc if ((rs->ohead += ocount) >= bufend(rs->obuf))
265*433d6423SLionel Sambuc rs->ohead -= buflen(rs->obuf);
266*433d6423SLionel Sambuc tp->tty_outcum += count;
267*433d6423SLionel Sambuc if ((tp->tty_outleft -= count) == 0) {
268*433d6423SLionel Sambuc /* Output is finished, reply to the writer. */
269*433d6423SLionel Sambuc if (tp->tty_outcaller != KERNEL)
270*433d6423SLionel Sambuc chardriver_reply_task(tp->tty_outcaller,
271*433d6423SLionel Sambuc tp->tty_outid, tp->tty_outcum);
272*433d6423SLionel Sambuc tp->tty_outcum = 0;
273*433d6423SLionel Sambuc tp->tty_outcaller = NONE;
274*433d6423SLionel Sambuc }
275*433d6423SLionel Sambuc
276*433d6423SLionel Sambuc }
277*433d6423SLionel Sambuc if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
278*433d6423SLionel Sambuc /* Oops, the line has hung up. */
279*433d6423SLionel Sambuc if (tp->tty_outcaller != KERNEL)
280*433d6423SLionel Sambuc chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
281*433d6423SLionel Sambuc EIO);
282*433d6423SLionel Sambuc tp->tty_outleft = tp->tty_outcum = 0;
283*433d6423SLionel Sambuc tp->tty_outcaller = NONE;
284*433d6423SLionel Sambuc }
285*433d6423SLionel Sambuc
286*433d6423SLionel Sambuc return 1;
287*433d6423SLionel Sambuc }
288*433d6423SLionel Sambuc
289*433d6423SLionel Sambuc static void
rs_echo(tty_t * tp,int character)290*433d6423SLionel Sambuc rs_echo(tty_t *tp, int character)
291*433d6423SLionel Sambuc {
292*433d6423SLionel Sambuc /* Echo one character. (Like rs_write, but only one character, optionally.) */
293*433d6423SLionel Sambuc
294*433d6423SLionel Sambuc rs232_t *rs = tp->tty_priv;
295*433d6423SLionel Sambuc int count, ocount;
296*433d6423SLionel Sambuc
297*433d6423SLionel Sambuc ocount = buflen(rs->obuf) - rs->ocount;
298*433d6423SLionel Sambuc if (ocount == 0) return; /* output buffer full */
299*433d6423SLionel Sambuc count = 1;
300*433d6423SLionel Sambuc *rs->ohead = character; /* add one character */
301*433d6423SLionel Sambuc
302*433d6423SLionel Sambuc out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
303*433d6423SLionel Sambuc if (count == 0) return;
304*433d6423SLionel Sambuc
305*433d6423SLionel Sambuc rs->ocount += ocount;
306*433d6423SLionel Sambuc rs_ostart(rs);
307*433d6423SLionel Sambuc if ((rs->ohead += ocount) >= bufend(rs->obuf))
308*433d6423SLionel Sambuc rs->ohead -= buflen(rs->obuf);
309*433d6423SLionel Sambuc }
310*433d6423SLionel Sambuc
311*433d6423SLionel Sambuc static int
rs_ioctl(tty_t * tp,int UNUSED (dummy))312*433d6423SLionel Sambuc rs_ioctl(tty_t *tp, int UNUSED(dummy))
313*433d6423SLionel Sambuc {
314*433d6423SLionel Sambuc /* Reconfigure the line as soon as the output has drained. */
315*433d6423SLionel Sambuc rs232_t *rs = tp->tty_priv;
316*433d6423SLionel Sambuc
317*433d6423SLionel Sambuc rs->drain = TRUE;
318*433d6423SLionel Sambuc return 0; /* dummy */
319*433d6423SLionel Sambuc }
320*433d6423SLionel Sambuc
321*433d6423SLionel Sambuc static unsigned int
omap_get_divisor(rs232_t * rs,unsigned int baud)322*433d6423SLionel Sambuc omap_get_divisor(rs232_t *rs, unsigned int baud)
323*433d6423SLionel Sambuc {
324*433d6423SLionel Sambuc /* Calculate divisor value. The 16750 has two oversampling modes to reach
325*433d6423SLionel Sambuc * high baud rates with little error rate (see table 17-1 in OMAP TRM).
326*433d6423SLionel Sambuc * Baud rates 460800, 921600, 1843200, and 3686400 use 13x oversampling,
327*433d6423SLionel Sambuc * the other rates 16x. The baud rate is calculated as follows:
328*433d6423SLionel Sambuc * baud rate = (functional clock / oversampling) / divisor.
329*433d6423SLionel Sambuc */
330*433d6423SLionel Sambuc
331*433d6423SLionel Sambuc unsigned int oversampling;
332*433d6423SLionel Sambuc assert(baud != 0);
333*433d6423SLionel Sambuc
334*433d6423SLionel Sambuc switch(baud) {
335*433d6423SLionel Sambuc case B460800: /* Fall through */
336*433d6423SLionel Sambuc case B921600: /* Fall through */
337*433d6423SLionel Sambuc #if 0
338*433d6423SLionel Sambuc case B1843200: /* Fall through */
339*433d6423SLionel Sambuc case B3686400:
340*433d6423SLionel Sambuc #endif
341*433d6423SLionel Sambuc oversampling = 13; break;
342*433d6423SLionel Sambuc default: oversampling = 16;
343*433d6423SLionel Sambuc }
344*433d6423SLionel Sambuc
345*433d6423SLionel Sambuc return (rs->uartclk / oversampling) / baud;
346*433d6423SLionel Sambuc }
347*433d6423SLionel Sambuc
348*433d6423SLionel Sambuc static int
termios_baud_rate(struct termios * term)349*433d6423SLionel Sambuc termios_baud_rate(struct termios *term)
350*433d6423SLionel Sambuc {
351*433d6423SLionel Sambuc int baud;
352*433d6423SLionel Sambuc switch(term->c_ospeed) {
353*433d6423SLionel Sambuc case B300: baud = 300; break;
354*433d6423SLionel Sambuc case B600: baud = 600; break;
355*433d6423SLionel Sambuc case B1200: baud = 1200; break;
356*433d6423SLionel Sambuc case B2400: baud = 2400; break;
357*433d6423SLionel Sambuc case B4800: baud = 4800; break;
358*433d6423SLionel Sambuc case B9600: baud = 9600; break;
359*433d6423SLionel Sambuc case B38400: baud = 38400; break;
360*433d6423SLionel Sambuc case B57600: baud = 57600; break;
361*433d6423SLionel Sambuc case B115200: baud = 115200; break;
362*433d6423SLionel Sambuc case B0:
363*433d6423SLionel Sambuc default:
364*433d6423SLionel Sambuc /* Reset the speed to the default speed, then call ourselves
365*433d6423SLionel Sambuc * to convert the default speed to a baudrate. This call will
366*433d6423SLionel Sambuc * always return a value without inducing another recursive
367*433d6423SLionel Sambuc * call. */
368*433d6423SLionel Sambuc term->c_ospeed = DFLT_BAUD;
369*433d6423SLionel Sambuc baud = termios_baud_rate(term);
370*433d6423SLionel Sambuc }
371*433d6423SLionel Sambuc
372*433d6423SLionel Sambuc return baud;
373*433d6423SLionel Sambuc }
rs_config(rs232_t * rs)374*433d6423SLionel Sambuc static void rs_config(rs232_t *rs)
375*433d6423SLionel Sambuc {
376*433d6423SLionel Sambuc /* Set various line control parameters for RS232 I/O. */
377*433d6423SLionel Sambuc tty_t *tp = rs->tty;
378*433d6423SLionel Sambuc unsigned int divisor, efr, lcr, mcr, baud;
379*433d6423SLionel Sambuc
380*433d6423SLionel Sambuc /* Fifo and DMA settings */
381*433d6423SLionel Sambuc /* See OMAP35x TRM 17.5.1.1.2 */
382*433d6423SLionel Sambuc lcr = serial_in(rs, OMAP3_LCR); /* 1a */
383*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 1b */
384*433d6423SLionel Sambuc efr = serial_in(rs, OMAP3_EFR); /* 2a */
385*433d6423SLionel Sambuc serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB); /* 2b */
386*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A); /* 3 */
387*433d6423SLionel Sambuc mcr = serial_in(rs, OMAP3_MCR); /* 4a */
388*433d6423SLionel Sambuc serial_out(rs, OMAP3_MCR, mcr | UART_MCR_TCRTLR); /* 4b */
389*433d6423SLionel Sambuc /* Set up FIFO */
390*433d6423SLionel Sambuc rs->fcr = 0;
391*433d6423SLionel Sambuc /* Set FIFO interrupt trigger levels high */
392*433d6423SLionel Sambuc rs->fcr |= (0x3 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT);
393*433d6423SLionel Sambuc rs->fcr |= (0x3 << OMAP_UART_FCR_TX_FIFO_TRIG_SHIFT);
394*433d6423SLionel Sambuc rs->fcr |= UART_FCR_ENABLE_FIFO;
395*433d6423SLionel Sambuc serial_out(rs, OMAP3_FCR, rs->fcr); /* 5 */
396*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 6 */
397*433d6423SLionel Sambuc /* DMA triggers, not supported by this driver */ /* 7 */
398*433d6423SLionel Sambuc rs->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
399*433d6423SLionel Sambuc serial_out(rs, OMAP3_SCR, rs->scr); /* 8 */
400*433d6423SLionel Sambuc serial_out(rs, OMAP3_EFR, efr); /* 9 */
401*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A); /* 10 */
402*433d6423SLionel Sambuc serial_out(rs, OMAP3_MCR, mcr); /* 11 */
403*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, lcr); /* 12 */
404*433d6423SLionel Sambuc
405*433d6423SLionel Sambuc /* RS232 needs to know the xoff character, and if CTS works. */
406*433d6423SLionel Sambuc rs->oxoff = tp->tty_termios.c_cc[VSTOP];
407*433d6423SLionel Sambuc rs->cts = (tp->tty_termios.c_cflag & CLOCAL) ? UART_MSR_CTS : 0;
408*433d6423SLionel Sambuc baud = termios_baud_rate(&tp->tty_termios);
409*433d6423SLionel Sambuc
410*433d6423SLionel Sambuc /* Look up the 16750 rate divisor from the output speed. */
411*433d6423SLionel Sambuc divisor = omap_get_divisor(rs, baud);
412*433d6423SLionel Sambuc rs->dll = divisor & 0xFF;
413*433d6423SLionel Sambuc rs->dlh = divisor >> 8;
414*433d6423SLionel Sambuc
415*433d6423SLionel Sambuc /* Compute line control flag bits. */
416*433d6423SLionel Sambuc lcr = 0;
417*433d6423SLionel Sambuc if (tp->tty_termios.c_cflag & PARENB) {
418*433d6423SLionel Sambuc lcr |= UART_LCR_PARITY;
419*433d6423SLionel Sambuc if (!(tp->tty_termios.c_cflag & PARODD)) lcr |= UART_LCR_EPAR;
420*433d6423SLionel Sambuc }
421*433d6423SLionel Sambuc if (tp->tty_termios.c_cflag & CSTOPB) lcr |= UART_LCR_STOP;
422*433d6423SLionel Sambuc switch(tp->tty_termios.c_cflag & CSIZE) {
423*433d6423SLionel Sambuc case CS5:
424*433d6423SLionel Sambuc lcr |= UART_LCR_WLEN5;
425*433d6423SLionel Sambuc break;
426*433d6423SLionel Sambuc case CS6:
427*433d6423SLionel Sambuc lcr |= UART_LCR_WLEN6;
428*433d6423SLionel Sambuc break;
429*433d6423SLionel Sambuc case CS7:
430*433d6423SLionel Sambuc lcr |= UART_LCR_WLEN7;
431*433d6423SLionel Sambuc break;
432*433d6423SLionel Sambuc default:
433*433d6423SLionel Sambuc case CS8:
434*433d6423SLionel Sambuc lcr |= UART_LCR_WLEN8;
435*433d6423SLionel Sambuc break;
436*433d6423SLionel Sambuc }
437*433d6423SLionel Sambuc
438*433d6423SLionel Sambuc /* Lock out interrupts while setting the speed. The receiver register
439*433d6423SLionel Sambuc * is going to be hidden by the div_low register, but the input
440*433d6423SLionel Sambuc * interrupt handler relies on reading it to clear the interrupt and
441*433d6423SLionel Sambuc * avoid looping forever.
442*433d6423SLionel Sambuc */
443*433d6423SLionel Sambuc
444*433d6423SLionel Sambuc if (sys_irqdisable(&rs->irq_hook_kernel_id) != OK)
445*433d6423SLionel Sambuc panic("unable to disable interrupts");
446*433d6423SLionel Sambuc
447*433d6423SLionel Sambuc /* Select the baud rate divisor registers and change the rate. */
448*433d6423SLionel Sambuc /* See OMAP35x TRM 17.5.1.1.3 */
449*433d6423SLionel Sambuc serial_out(rs, OMAP3_MDR1, OMAP_MDR1_DISABLE); /* 1 */
450*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 2 */
451*433d6423SLionel Sambuc efr = serial_in(rs, OMAP3_EFR); /* 3a */
452*433d6423SLionel Sambuc serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB); /* 3b */
453*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, 0); /* 4 */
454*433d6423SLionel Sambuc serial_out(rs, OMAP3_IER, 0); /* 5 */
455*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 6 */
456*433d6423SLionel Sambuc serial_out(rs, OMAP3_DLL, rs->dll); /* 7 */
457*433d6423SLionel Sambuc serial_out(rs, OMAP3_DLH, rs->dlh); /* 7 */
458*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, 0); /* 8 */
459*433d6423SLionel Sambuc serial_out(rs, OMAP3_IER, rs->ier); /* 9 */
460*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 10 */
461*433d6423SLionel Sambuc serial_out(rs, OMAP3_EFR, efr); /* 11 */
462*433d6423SLionel Sambuc serial_out(rs, OMAP3_LCR, lcr); /* 12 */
463*433d6423SLionel Sambuc if (baud > 230400 && baud != 3000000)
464*433d6423SLionel Sambuc serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE13X); /* 13 */
465*433d6423SLionel Sambuc else
466*433d6423SLionel Sambuc serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE16X);
467*433d6423SLionel Sambuc
468*433d6423SLionel Sambuc rs->ostate = devready(rs) | ORAW | OSWREADY; /* reads MSR */
469*433d6423SLionel Sambuc if ((tp->tty_termios.c_lflag & IXON) && rs->oxoff != _POSIX_VDISABLE)
470*433d6423SLionel Sambuc rs->ostate &= ~ORAW;
471*433d6423SLionel Sambuc (void) serial_in(rs, OMAP3_IIR);
472*433d6423SLionel Sambuc
473*433d6423SLionel Sambuc if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
474*433d6423SLionel Sambuc panic("unable to enable interrupts");
475*433d6423SLionel Sambuc }
476*433d6423SLionel Sambuc
477*433d6423SLionel Sambuc void
rs_init(tty_t * tp)478*433d6423SLionel Sambuc rs_init(tty_t *tp)
479*433d6423SLionel Sambuc {
480*433d6423SLionel Sambuc /* Initialize RS232 for one line. */
481*433d6423SLionel Sambuc register rs232_t *rs;
482*433d6423SLionel Sambuc int line;
483*433d6423SLionel Sambuc uart_port_t this_omap3;
484*433d6423SLionel Sambuc char l[10];
485*433d6423SLionel Sambuc struct minix_mem_range mr;
486*433d6423SLionel Sambuc struct machine machine;
487*433d6423SLionel Sambuc
488*433d6423SLionel Sambuc /* Associate RS232 and TTY structures. */
489*433d6423SLionel Sambuc line = tp - &tty_table[NR_CONS];
490*433d6423SLionel Sambuc
491*433d6423SLionel Sambuc /* See if kernel debugging is enabled; if so, don't initialize this
492*433d6423SLionel Sambuc * serial line, making tty not look at the irq and returning ENXIO
493*433d6423SLionel Sambuc * for all requests on it from userland. (The kernel will use it.)
494*433d6423SLionel Sambuc */
495*433d6423SLionel Sambuc if(env_get_param(SERVARNAME, l, sizeof(l)-1) == OK && atoi(l) == line){
496*433d6423SLionel Sambuc printf("TTY: rs232 line %d not initialized (used by kernel)\n",
497*433d6423SLionel Sambuc line);
498*433d6423SLionel Sambuc return;
499*433d6423SLionel Sambuc }
500*433d6423SLionel Sambuc
501*433d6423SLionel Sambuc rs = tp->tty_priv = &rs_lines[line];
502*433d6423SLionel Sambuc rs->tty = tp;
503*433d6423SLionel Sambuc
504*433d6423SLionel Sambuc /* Set up input queue. */
505*433d6423SLionel Sambuc rs->ihead = rs->itail = rs->ibuf;
506*433d6423SLionel Sambuc
507*433d6423SLionel Sambuc sys_getmachine(&machine);
508*433d6423SLionel Sambuc
509*433d6423SLionel Sambuc if (BOARD_IS_BBXM(machine.board_id)){
510*433d6423SLionel Sambuc this_omap3 = dm37xx_ports[line];
511*433d6423SLionel Sambuc } else if (BOARD_IS_BB(machine.board_id)){
512*433d6423SLionel Sambuc this_omap3 = am335x_ports[line];
513*433d6423SLionel Sambuc } else {
514*433d6423SLionel Sambuc return;
515*433d6423SLionel Sambuc }
516*433d6423SLionel Sambuc if (this_omap3.base_addr == 0) return;
517*433d6423SLionel Sambuc
518*433d6423SLionel Sambuc /* Configure memory access */
519*433d6423SLionel Sambuc mr.mr_base = rs->phys_base;
520*433d6423SLionel Sambuc mr.mr_limit = rs->phys_base + 0x100;
521*433d6423SLionel Sambuc if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
522*433d6423SLionel Sambuc panic("Unable to request access to UART memory");
523*433d6423SLionel Sambuc }
524*433d6423SLionel Sambuc rs->phys_base = (vir_bytes) vm_map_phys(SELF,
525*433d6423SLionel Sambuc (void *) this_omap3.base_addr, 0x100);
526*433d6423SLionel Sambuc
527*433d6423SLionel Sambuc if (rs->phys_base == (vir_bytes) MAP_FAILED) {
528*433d6423SLionel Sambuc panic("Unable to request access to UART memory");
529*433d6423SLionel Sambuc }
530*433d6423SLionel Sambuc rs->reg_offset = 2;
531*433d6423SLionel Sambuc
532*433d6423SLionel Sambuc rs->uartclk = UART_FREQ;
533*433d6423SLionel Sambuc rs->ohead = rs->otail = rs->obuf;
534*433d6423SLionel Sambuc
535*433d6423SLionel Sambuc /* Override system default baud rate. We do this because u-boot
536*433d6423SLionel Sambuc * configures the UART for a baud rate of 115200 b/s and the kernel
537*433d6423SLionel Sambuc * directly sends data over serial out upon boot up. If we then
538*433d6423SLionel Sambuc * suddenly change the settings, the output will be garbled during
539*433d6423SLionel Sambuc * booting.
540*433d6423SLionel Sambuc */
541*433d6423SLionel Sambuc tp->tty_termios.c_ospeed = DFLT_BAUD;
542*433d6423SLionel Sambuc
543*433d6423SLionel Sambuc /* Configure IRQ */
544*433d6423SLionel Sambuc rs->irq = this_omap3.irq;
545*433d6423SLionel Sambuc
546*433d6423SLionel Sambuc /* callback with irq line number + 1 because using line number 0
547*433d6423SLionel Sambuc fails eslewhere */
548*433d6423SLionel Sambuc rs->irq_hook_kernel_id = rs->irq_hook_id = line + 1;
549*433d6423SLionel Sambuc
550*433d6423SLionel Sambuc /* sys_irqsetpolicy modifies irq_hook_kernel_id. this modified id
551*433d6423SLionel Sambuc * needs to be used in sys_irqenable and similar calls.
552*433d6423SLionel Sambuc */
553*433d6423SLionel Sambuc if (sys_irqsetpolicy(rs->irq, 0, &rs->irq_hook_kernel_id) != OK) {
554*433d6423SLionel Sambuc printf("RS232: Couldn't obtain hook for irq %d\n", rs->irq);
555*433d6423SLionel Sambuc } else {
556*433d6423SLionel Sambuc if (sys_irqenable(&rs->irq_hook_kernel_id) != OK) {
557*433d6423SLionel Sambuc printf("RS232: Couldn't enable irq %d (hooked)\n",
558*433d6423SLionel Sambuc rs->irq);
559*433d6423SLionel Sambuc }
560*433d6423SLionel Sambuc }
561*433d6423SLionel Sambuc
562*433d6423SLionel Sambuc /* When we get called back we get called back using the original
563*433d6423SLionel Sambuc * hook_id bit set. e.g. if we register with hook_id 5 the callback
564*433d6423SLionel Sambuc * calls us with the 5 th bit set */
565*433d6423SLionel Sambuc rs_irq_set |= (1 << (rs->irq_hook_id ));
566*433d6423SLionel Sambuc
567*433d6423SLionel Sambuc /* Enable interrupts */
568*433d6423SLionel Sambuc rs_reset(rs);
569*433d6423SLionel Sambuc rs->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_MSI;
570*433d6423SLionel Sambuc rs_config(rs);
571*433d6423SLionel Sambuc
572*433d6423SLionel Sambuc /* Fill in TTY function hooks. */
573*433d6423SLionel Sambuc tp->tty_devread = rs_read;
574*433d6423SLionel Sambuc tp->tty_devwrite = rs_write;
575*433d6423SLionel Sambuc tp->tty_echo = rs_echo;
576*433d6423SLionel Sambuc tp->tty_icancel = rs_icancel;
577*433d6423SLionel Sambuc tp->tty_ocancel = rs_ocancel;
578*433d6423SLionel Sambuc tp->tty_ioctl = rs_ioctl;
579*433d6423SLionel Sambuc tp->tty_break_on = rs_break_on;
580*433d6423SLionel Sambuc tp->tty_break_off = rs_break_off;
581*433d6423SLionel Sambuc tp->tty_open = rs_open;
582*433d6423SLionel Sambuc tp->tty_close = rs_close;
583*433d6423SLionel Sambuc
584*433d6423SLionel Sambuc /* Tell external device we are ready. */
585*433d6423SLionel Sambuc istart(rs);
586*433d6423SLionel Sambuc }
587*433d6423SLionel Sambuc
588*433d6423SLionel Sambuc void
rs_interrupt(message * m)589*433d6423SLionel Sambuc rs_interrupt(message *m)
590*433d6423SLionel Sambuc {
591*433d6423SLionel Sambuc unsigned long irq_set;
592*433d6423SLionel Sambuc int line;
593*433d6423SLionel Sambuc rs232_t *rs;
594*433d6423SLionel Sambuc
595*433d6423SLionel Sambuc irq_set = m->m_notify.interrupts;
596*433d6423SLionel Sambuc for (line = 0, rs = rs_lines; line < NR_RS_LINES; line++, rs++) {
597*433d6423SLionel Sambuc if (irq_set & (1 << rs->irq_hook_id)) {
598*433d6423SLionel Sambuc rs232_handler(rs);
599*433d6423SLionel Sambuc if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
600*433d6423SLionel Sambuc panic("unable to enable interrupts");
601*433d6423SLionel Sambuc }
602*433d6423SLionel Sambuc }
603*433d6423SLionel Sambuc }
604*433d6423SLionel Sambuc
605*433d6423SLionel Sambuc static int
rs_icancel(tty_t * tp,int UNUSED (dummy))606*433d6423SLionel Sambuc rs_icancel(tty_t *tp, int UNUSED(dummy))
607*433d6423SLionel Sambuc {
608*433d6423SLionel Sambuc /* Cancel waiting input. */
609*433d6423SLionel Sambuc rs232_t *rs = tp->tty_priv;
610*433d6423SLionel Sambuc
611*433d6423SLionel Sambuc rs->icount = 0;
612*433d6423SLionel Sambuc rs->itail = rs->ihead;
613*433d6423SLionel Sambuc istart(rs);
614*433d6423SLionel Sambuc return 0; /* dummy */
615*433d6423SLionel Sambuc }
616*433d6423SLionel Sambuc
617*433d6423SLionel Sambuc static int
rs_ocancel(tty_t * tp,int UNUSED (dummy))618*433d6423SLionel Sambuc rs_ocancel(tty_t *tp, int UNUSED(dummy))
619*433d6423SLionel Sambuc {
620*433d6423SLionel Sambuc /* Cancel pending output. */
621*433d6423SLionel Sambuc rs232_t *rs = tp->tty_priv;
622*433d6423SLionel Sambuc
623*433d6423SLionel Sambuc rs->ostate &= ~(ODONE | OQUEUED);
624*433d6423SLionel Sambuc rs->ocount = 0;
625*433d6423SLionel Sambuc rs->otail = rs->ohead;
626*433d6423SLionel Sambuc
627*433d6423SLionel Sambuc return 0; /* dummy */
628*433d6423SLionel Sambuc }
629*433d6423SLionel Sambuc
630*433d6423SLionel Sambuc static int
rs_read(tty_t * tp,int try)631*433d6423SLionel Sambuc rs_read(tty_t *tp, int try)
632*433d6423SLionel Sambuc {
633*433d6423SLionel Sambuc /* Process characters from the circular input buffer. */
634*433d6423SLionel Sambuc
635*433d6423SLionel Sambuc rs232_t *rs = tp->tty_priv;
636*433d6423SLionel Sambuc int icount, count, ostate;
637*433d6423SLionel Sambuc
638*433d6423SLionel Sambuc if (!(tp->tty_termios.c_cflag & CLOCAL)) {
639*433d6423SLionel Sambuc if (try) return 1;
640*433d6423SLionel Sambuc
641*433d6423SLionel Sambuc /* Send a SIGHUP if hangup detected. */
642*433d6423SLionel Sambuc ostate = rs->ostate;
643*433d6423SLionel Sambuc rs->ostate &= ~ODEVHUP; /* save ostate, clear DEVHUP */
644*433d6423SLionel Sambuc if (ostate & ODEVHUP) {
645*433d6423SLionel Sambuc sigchar(tp, SIGHUP, 1);
646*433d6423SLionel Sambuc tp->tty_termios.c_ospeed = B0;/* Disable further I/O.*/
647*433d6423SLionel Sambuc return 0;
648*433d6423SLionel Sambuc }
649*433d6423SLionel Sambuc }
650*433d6423SLionel Sambuc
651*433d6423SLionel Sambuc if (try) {
652*433d6423SLionel Sambuc return(rs->icount > 0);
653*433d6423SLionel Sambuc }
654*433d6423SLionel Sambuc
655*433d6423SLionel Sambuc while ((count = rs->icount) > 0) {
656*433d6423SLionel Sambuc icount = bufend(rs->ibuf) - rs->itail;
657*433d6423SLionel Sambuc if (count > icount) count = icount;
658*433d6423SLionel Sambuc
659*433d6423SLionel Sambuc /* Perform input processing on (part of) the input buffer. */
660*433d6423SLionel Sambuc if ((count = in_process(tp, rs->itail, count)) == 0) break;
661*433d6423SLionel Sambuc rs->icount -= count;
662*433d6423SLionel Sambuc if (!rs->idevready && rs->icount < RS_ILOWWATER) istart(rs);
663*433d6423SLionel Sambuc if ((rs->itail += count) == bufend(rs->ibuf))
664*433d6423SLionel Sambuc rs->itail = rs->ibuf;
665*433d6423SLionel Sambuc }
666*433d6423SLionel Sambuc
667*433d6423SLionel Sambuc return 0;
668*433d6423SLionel Sambuc }
669*433d6423SLionel Sambuc
670*433d6423SLionel Sambuc static void
rs_ostart(rs232_t * rs)671*433d6423SLionel Sambuc rs_ostart(rs232_t *rs)
672*433d6423SLionel Sambuc {
673*433d6423SLionel Sambuc /* Tell RS232 there is something waiting in the output buffer. */
674*433d6423SLionel Sambuc
675*433d6423SLionel Sambuc rs->ostate |= OQUEUED;
676*433d6423SLionel Sambuc if (txready(rs)) write_chars(rs);
677*433d6423SLionel Sambuc }
678*433d6423SLionel Sambuc
679*433d6423SLionel Sambuc static int
rs_break_on(tty_t * tp,int UNUSED (dummy))680*433d6423SLionel Sambuc rs_break_on(tty_t *tp, int UNUSED(dummy))
681*433d6423SLionel Sambuc {
682*433d6423SLionel Sambuc /* Raise break condition */
683*433d6423SLionel Sambuc rs232_t *rs = tp->tty_priv;
684*433d6423SLionel Sambuc unsigned int lsr;
685*433d6423SLionel Sambuc
686*433d6423SLionel Sambuc lsr = serial_in(rs, OMAP3_LSR);
687*433d6423SLionel Sambuc serial_out(rs, OMAP3_LSR, lsr | UART_LSR_BI);
688*433d6423SLionel Sambuc return 0; /* dummy */
689*433d6423SLionel Sambuc }
690*433d6423SLionel Sambuc
691*433d6423SLionel Sambuc static int
rs_break_off(tty_t * tp,int UNUSED (dummy))692*433d6423SLionel Sambuc rs_break_off(tty_t *tp, int UNUSED(dummy))
693*433d6423SLionel Sambuc {
694*433d6423SLionel Sambuc /* Clear break condition */
695*433d6423SLionel Sambuc rs232_t *rs = tp->tty_priv;
696*433d6423SLionel Sambuc unsigned int lsr;
697*433d6423SLionel Sambuc
698*433d6423SLionel Sambuc lsr = serial_in(rs, OMAP3_LSR);
699*433d6423SLionel Sambuc serial_out(rs, OMAP3_LSR, lsr & ~UART_LSR_BI);
700*433d6423SLionel Sambuc return 0; /* dummy */
701*433d6423SLionel Sambuc }
702*433d6423SLionel Sambuc
703*433d6423SLionel Sambuc static int
rs_open(tty_t * tp,int UNUSED (dummy))704*433d6423SLionel Sambuc rs_open(tty_t *tp, int UNUSED(dummy))
705*433d6423SLionel Sambuc {
706*433d6423SLionel Sambuc /* Set the speed to 115200 by default */
707*433d6423SLionel Sambuc tp->tty_termios.c_ospeed = DFLT_BAUD;
708*433d6423SLionel Sambuc return 0;
709*433d6423SLionel Sambuc }
710*433d6423SLionel Sambuc
711*433d6423SLionel Sambuc static int
rs_close(tty_t * tp,int UNUSED (dummy))712*433d6423SLionel Sambuc rs_close(tty_t *tp, int UNUSED(dummy))
713*433d6423SLionel Sambuc {
714*433d6423SLionel Sambuc /* The line is closed; optionally hang up. */
715*433d6423SLionel Sambuc rs232_t *rs = tp->tty_priv;
716*433d6423SLionel Sambuc
717*433d6423SLionel Sambuc if (tp->tty_termios.c_cflag & HUPCL) {
718*433d6423SLionel Sambuc serial_out(rs, OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS);
719*433d6423SLionel Sambuc if (rs->ier & UART_IER_THRI) {
720*433d6423SLionel Sambuc rs->ier &= ~UART_IER_THRI;
721*433d6423SLionel Sambuc serial_out(rs, OMAP3_IER, rs->ier);
722*433d6423SLionel Sambuc }
723*433d6423SLionel Sambuc }
724*433d6423SLionel Sambuc return 0; /* dummy */
725*433d6423SLionel Sambuc }
726*433d6423SLionel Sambuc
727*433d6423SLionel Sambuc /* Low level (interrupt) routines. */
728*433d6423SLionel Sambuc
729*433d6423SLionel Sambuc static void
rs232_handler(struct rs232 * rs)730*433d6423SLionel Sambuc rs232_handler(struct rs232 *rs)
731*433d6423SLionel Sambuc {
732*433d6423SLionel Sambuc /* Handle interrupt of a UART port */
733*433d6423SLionel Sambuc unsigned int iir, lsr;
734*433d6423SLionel Sambuc
735*433d6423SLionel Sambuc iir = serial_in(rs, OMAP3_IIR);
736*433d6423SLionel Sambuc if (iir & UART_IIR_NO_INT) /* No interrupt */
737*433d6423SLionel Sambuc return;
738*433d6423SLionel Sambuc
739*433d6423SLionel Sambuc lsr = serial_in(rs, OMAP3_LSR);
740*433d6423SLionel Sambuc if (iir & UART_IIR_RDI) { /* Data ready interrupt */
741*433d6423SLionel Sambuc if (lsr & UART_LSR_DR) {
742*433d6423SLionel Sambuc read_chars(rs, lsr);
743*433d6423SLionel Sambuc }
744*433d6423SLionel Sambuc }
745*433d6423SLionel Sambuc check_modem_status(rs);
746*433d6423SLionel Sambuc if (iir & UART_IIR_THRI) {
747*433d6423SLionel Sambuc if (lsr & UART_LSR_THRE) {
748*433d6423SLionel Sambuc /* Ready to send and space available */
749*433d6423SLionel Sambuc write_chars(rs);
750*433d6423SLionel Sambuc }
751*433d6423SLionel Sambuc }
752*433d6423SLionel Sambuc }
753*433d6423SLionel Sambuc
754*433d6423SLionel Sambuc static void
read_chars(rs232_t * rs,unsigned int status)755*433d6423SLionel Sambuc read_chars(rs232_t *rs, unsigned int status)
756*433d6423SLionel Sambuc {
757*433d6423SLionel Sambuc unsigned char c;
758*433d6423SLionel Sambuc
759*433d6423SLionel Sambuc if(serial_in(rs,OMAP3_LSR) & OMAP3_LSR_RXOE) {
760*433d6423SLionel Sambuc rs->rx_overrun_events++;
761*433d6423SLionel Sambuc }
762*433d6423SLionel Sambuc
763*433d6423SLionel Sambuc /* check the line status to know if there are more chars */
764*433d6423SLionel Sambuc while (serial_in(rs, OMAP3_LSR) & UART_LSR_DR) {
765*433d6423SLionel Sambuc c = serial_in(rs, OMAP3_RHR);
766*433d6423SLionel Sambuc if (!(rs->ostate & ORAW)) {
767*433d6423SLionel Sambuc if (c == rs->oxoff) {
768*433d6423SLionel Sambuc rs->ostate &= ~OSWREADY;
769*433d6423SLionel Sambuc } else if (!(rs->ostate & OSWREADY)) {
770*433d6423SLionel Sambuc rs->ostate = OSWREADY;
771*433d6423SLionel Sambuc }
772*433d6423SLionel Sambuc }
773*433d6423SLionel Sambuc
774*433d6423SLionel Sambuc if (rs->icount == buflen(rs->ibuf)) {
775*433d6423SLionel Sambuc /* no buffer space? keep reading */
776*433d6423SLionel Sambuc continue;
777*433d6423SLionel Sambuc }
778*433d6423SLionel Sambuc
779*433d6423SLionel Sambuc if (++rs->icount == RS_IHIGHWATER && rs->idevready) {
780*433d6423SLionel Sambuc istop(rs);
781*433d6423SLionel Sambuc }
782*433d6423SLionel Sambuc
783*433d6423SLionel Sambuc *rs->ihead = c;
784*433d6423SLionel Sambuc if (++rs->ihead == bufend(rs->ibuf)) {
785*433d6423SLionel Sambuc rs->ihead = rs->ibuf;
786*433d6423SLionel Sambuc }
787*433d6423SLionel Sambuc
788*433d6423SLionel Sambuc if (rs->icount == 1) {
789*433d6423SLionel Sambuc rs->tty->tty_events = 1;
790*433d6423SLionel Sambuc }
791*433d6423SLionel Sambuc }
792*433d6423SLionel Sambuc }
793*433d6423SLionel Sambuc
794*433d6423SLionel Sambuc static void
write_chars(rs232_t * rs)795*433d6423SLionel Sambuc write_chars(rs232_t *rs)
796*433d6423SLionel Sambuc {
797*433d6423SLionel Sambuc /* If there is output to do and everything is ready, do it (local device is
798*433d6423SLionel Sambuc * known ready).
799*433d6423SLionel Sambuc * Notify TTY when the buffer goes empty.
800*433d6423SLionel Sambuc */
801*433d6423SLionel Sambuc
802*433d6423SLionel Sambuc if (rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY)) {
803*433d6423SLionel Sambuc /* Bit test allows ORAW and requires the others. */
804*433d6423SLionel Sambuc serial_out(rs, OMAP3_THR, *rs->otail);
805*433d6423SLionel Sambuc if (++rs->otail == bufend(rs->obuf))
806*433d6423SLionel Sambuc rs->otail = rs->obuf;
807*433d6423SLionel Sambuc if (--rs->ocount == 0) {
808*433d6423SLionel Sambuc /* Turn on ODONE flag, turn off OQUEUED */
809*433d6423SLionel Sambuc rs->ostate ^= (ODONE | OQUEUED);
810*433d6423SLionel Sambuc rs->tty->tty_events = 1;
811*433d6423SLionel Sambuc if (rs->ier & UART_IER_THRI) {
812*433d6423SLionel Sambuc rs->ier &= ~UART_IER_THRI;
813*433d6423SLionel Sambuc serial_out(rs, OMAP3_IER, rs->ier);
814*433d6423SLionel Sambuc }
815*433d6423SLionel Sambuc } else {
816*433d6423SLionel Sambuc if (rs->icount == RS_OLOWWATER)
817*433d6423SLionel Sambuc rs->tty->tty_events = 1;
818*433d6423SLionel Sambuc if (!(rs->ier & UART_IER_THRI)) {
819*433d6423SLionel Sambuc rs->ier |= UART_IER_THRI;
820*433d6423SLionel Sambuc serial_out(rs, OMAP3_IER, rs->ier);
821*433d6423SLionel Sambuc }
822*433d6423SLionel Sambuc }
823*433d6423SLionel Sambuc }
824*433d6423SLionel Sambuc }
825*433d6423SLionel Sambuc
826*433d6423SLionel Sambuc static unsigned int
check_modem_status(rs232_t * rs)827*433d6423SLionel Sambuc check_modem_status(rs232_t *rs)
828*433d6423SLionel Sambuc {
829*433d6423SLionel Sambuc /* Check modem status */
830*433d6423SLionel Sambuc
831*433d6423SLionel Sambuc unsigned int msr;
832*433d6423SLionel Sambuc
833*433d6423SLionel Sambuc msr = serial_in(rs, OMAP3_MSR); /* Resets modem interrupt */
834*433d6423SLionel Sambuc if ((msr & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD) {
835*433d6423SLionel Sambuc rs->ostate |= ODEVHUP;
836*433d6423SLionel Sambuc rs->tty->tty_events = 1;
837*433d6423SLionel Sambuc }
838*433d6423SLionel Sambuc
839*433d6423SLionel Sambuc if (!devready(rs))
840*433d6423SLionel Sambuc rs->ostate &= ~ODEVREADY;
841*433d6423SLionel Sambuc else
842*433d6423SLionel Sambuc rs->ostate |= ODEVREADY;
843*433d6423SLionel Sambuc
844*433d6423SLionel Sambuc return msr;
845*433d6423SLionel Sambuc }
846*433d6423SLionel Sambuc
847*433d6423SLionel Sambuc #endif /* NR_RS_LINES > 0 */
848*433d6423SLionel Sambuc
849