source: rtems/c/src/lib/libcpu/m68k/mcf5206/console/mcfuart.c @ 9a73f421

4.104.114.9
Last change on this file since 9a73f421 was 9a73f421, checked in by Ralf Corsepius <ralf.corsepius@…>, on Sep 2, 2008 at 12:55:44 PM

Eliminate rtems_boolean.

  • Property mode set to 100644
File size: 15.0 KB
Line 
1/*
2 * Generic UART Serial driver for Motorola Coldfire processors
3 *
4 * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russian Fed.
5 * Author: Victor V. Vengerov <vvv@oktet.ru>
6 *
7 *  COPYRIGHT (c) 1989-2000.
8 *  On-Line Applications Research Corporation (OAR).
9 *
10 *  The license and distribution terms for this file may be
11 *  found in the file LICENSE in this distribution or at
12 *
13 *  http://www.rtems.com/license/LICENSE.
14 *
15 *  $Id$
16 *
17 */
18
19#include <rtems.h>
20#include <termios.h>
21#include <rtems/libio.h>
22#include "mcf5206/mcfuart.h"
23
24/*
25 * int_driven_uart -- mapping between interrupt vector number and
26 * UART descriptor structures
27 */
28static struct {
29    mcfuart *uart;
30    int      vec;
31} int_driven_uart[2];
32
33/* Forward function declarations */
34static rtems_isr
35mcfuart_interrupt_handler(rtems_vector_number vec);
36         
37/*
38 * mcfuart_init --
39 *     This function verifies the input parameters and perform initialization
40 *     of the Motorola Coldfire on-chip UART descriptor structure.
41 *
42 * PARAMETERS:
43 *     uart - pointer to the UART channel descriptor structure
44 *     tty - pointer to termios structure
45 *     int_driven - interrupt-driven (1) or polled (0) I/O mode
46 *     chn - channel number (0/1)
47 *     rx_buf - pointer to receive buffer
48 *     rx_buf_len - receive buffer length
49 *
50 * RETURNS:
51 *     RTEMS_SUCCESSFUL if all parameters are valid, or error code
52 */
53rtems_status_code
54mcfuart_init(mcfuart *uart, void *tty, uint8_t   intvec,
55             uint32_t   chn)
56{
57    if (uart == NULL)
58        return RTEMS_INVALID_ADDRESS;
59   
60    if ((chn <= 0) || (chn > MCF5206E_UART_CHANNELS))
61        return RTEMS_INVALID_NUMBER;
62   
63    uart->chn = chn;
64    uart->intvec = intvec;
65    uart->tty = tty;
66   
67    return RTEMS_SUCCESSFUL;
68}
69
70/* mcfuart_set_baudrate --
71 *     Program the UART timer to specified baudrate
72 *
73 * PARAMETERS:
74 *     uart - pointer to UART descriptor structure
75 *     baud - termios baud rate (B50, B9600, etc...)
76 *
77 * RETURNS:
78 *     none
79 */
80static void
81mcfuart_set_baudrate(mcfuart *uart, speed_t baud)
82{
83    uint32_t   div;
84    uint32_t   rate;
85    switch (baud)
86    {
87        case B50:     rate = 50; break;
88        case B75:     rate = 75; break;
89        case B110:    rate = 110; break;
90        case B134:    rate = 134; break;
91        case B150:    rate = 150; break;
92        case B200:    rate = 200; break;
93        case B300:    rate = 300; break;
94        case B600:    rate = 600; break;
95        case B1200:   rate = 1200; break;
96        case B2400:   rate = 2400; break;
97        case B4800:   rate = 4800; break;
98        case B9600:   rate = 9600; break;
99        case B19200:  rate = 19200; break;
100        case B38400:  rate = 38400; break;
101        case B57600:  rate = 57600; break;
102#ifdef B115200
103        case B115200: rate = 115200; break;
104#endif
105#ifdef B230400
106        case B230400: rate = 230400; break;
107#endif
108        default:      rate = 9600; break;
109    }
110       
111    div = SYSTEM_CLOCK_FREQUENCY / (rate * 32);
112   
113    *MCF5206E_UBG1(MBAR,uart->chn) = (uint8_t)((div >> 8) & 0xff);
114    *MCF5206E_UBG2(MBAR,uart->chn) = (uint8_t)(div & 0xff);
115}
116
117/*
118 * mcfuart_reset --
119 *     This function perform the hardware initialization of Motorola
120 *     Coldfire processor on-chip UART controller using parameters
121 *     filled by the mcfuart_init function.
122 *
123 * PARAMETERS:
124 *     uart - pointer to UART channel descriptor structure
125 *
126 * RETURNS:
127 *     RTEMS_SUCCESSFUL if channel is initialized successfully, error
128 *     code in other case
129 *
130 * ALGORITHM:
131 *     This function in general follows to algorith described in MCF5206e
132 *     User's Manual, 12.5 UART Module Initialization Sequence
133 */
134rtems_status_code
135mcfuart_reset(mcfuart *uart)
136{
137    register uint32_t   chn;
138    rtems_status_code rc;
139   
140    if (uart == NULL)
141        return RTEMS_INVALID_ADDRESS;
142   
143    chn = uart->chn;
144   
145    /* Reset the receiver and transmitter */
146    *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_RX;
147    *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_TX;
148   
149    /*
150     * Program the vector number for a UART module interrupt, or
151     * disable UART interrupts if polled I/O. Enable the desired
152     * interrupt sources.
153     */
154    if (uart->intvec != 0)
155    {
156        int_driven_uart[chn - 1].uart = uart;
157        int_driven_uart[chn - 1].vec = uart->intvec;
158        rc = rtems_interrupt_catch(mcfuart_interrupt_handler, uart->intvec,
159                                   &uart->old_handler);
160        if (rc != RTEMS_SUCCESSFUL)
161            return rc;
162        *MCF5206E_UIVR(MBAR,chn) = uart->intvec;
163        *MCF5206E_UIMR(MBAR,chn) = MCF5206E_UIMR_FFULL;
164        *MCF5206E_UACR(MBAR,chn) = MCF5206E_UACR_IEC;
165        *MCF5206E_IMR(MBAR) &= ~MCF5206E_INTR_BIT(uart->chn == 1 ?
166                                                  MCF5206E_INTR_UART_1 :
167                                                  MCF5206E_INTR_UART_2);
168    }
169    else
170    {
171        *MCF5206E_UIMR(MBAR,chn) = 0;
172    }
173   
174    /* Select the receiver and transmitter clock. */
175    mcfuart_set_baudrate(uart, B19200); /* dBUG defaults (unfortunately,
176                                           it is differ to termios default */
177    *MCF5206E_UCSR(MBAR,chn) = 
178        MCF5206E_UCSR_RCS_TIMER | MCF5206E_UCSR_TCS_TIMER;
179   
180    /* Mode Registers 1,2 - set termios defaults (8N1) */
181    *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_MR;
182    *MCF5206E_UMR(MBAR,chn) = 
183/*      MCF5206E_UMR1_RXRTS | */
184        MCF5206E_UMR1_PM_NO_PARITY |
185        MCF5206E_UMR1_BC_8;
186    *MCF5206E_UMR(MBAR,chn) =
187        MCF5206E_UMR2_CM_NORMAL |
188/*      MCF5206E_UMR2_TXCTS | */
189        MCF5206E_UMR2_SB_1;
190   
191    /* Enable Receiver and Transmitter */
192    *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_MISC_RESET_ERR;
193    *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_TC_ENABLE;
194    *MCF5206E_UCR(MBAR,chn) = MCF5206E_UCR_RC_ENABLE;
195   
196    return RTEMS_SUCCESSFUL;
197}
198
199/*
200 * mcfuart_disable --
201 *     This function disable the operations on Motorola Coldfire UART
202 *     controller
203 *
204 * PARAMETERS:
205 *     uart - pointer to UART channel descriptor structure
206 *
207 * RETURNS:
208 *     RTEMS_SUCCESSFUL if UART closed successfuly, or error code in
209 *     other case
210 */
211rtems_status_code
212mcfuart_disable(mcfuart *uart)
213{
214    rtems_status_code rc;
215    *MCF5206E_UCR(MBAR,uart->chn) = 
216        MCF5206E_UCR_TC_DISABLE |
217        MCF5206E_UCR_RC_DISABLE;
218    if (uart->intvec != 0)
219    {
220        *MCF5206E_IMR(MBAR) |=  MCF5206E_INTR_BIT(uart->chn == 1 ?
221                                                  MCF5206E_INTR_UART_1 :
222                                                  MCF5206E_INTR_UART_2);
223        rc = rtems_interrupt_catch(uart->old_handler, uart->intvec, NULL);
224        int_driven_uart[uart->chn - 1].uart = NULL;
225        int_driven_uart[uart->chn - 1].vec = 0;
226        if (rc != RTEMS_SUCCESSFUL)
227            return rc;
228    }
229    return RTEMS_SUCCESSFUL;
230}
231
232/*
233 * mcfuart_set_attributes --
234 *     This function parse the termios attributes structure and perform
235 *     the appropriate settings in hardware.
236 *
237 * PARAMETERS:
238 *     uart - pointer to the UART descriptor structure
239 *     t - pointer to termios parameters
240 *
241 * RETURNS:
242 *     RTEMS_SUCCESSFUL
243 */
244int
245mcfuart_set_attributes(mcfuart *uart, const struct termios *t)
246{
247    int level;
248    speed_t baud;
249    uint8_t   umr1, umr2;
250   
251    baud = cfgetospeed(t);
252    umr1 = 0;
253    umr2 = MCF5206E_UMR2_CM_NORMAL;
254   
255    /* Set flow control */
256    if ((t->c_cflag & CRTSCTS) != 0)
257    {
258        umr1 |= MCF5206E_UMR1_RXRTS;
259        umr2 |= MCF5206E_UMR2_TXCTS;
260    }
261   
262    /* Set character size */
263    switch (t->c_cflag & CSIZE)
264    {
265        case CS5: umr1 |= MCF5206E_UMR1_BC_5; break;
266        case CS6: umr1 |= MCF5206E_UMR1_BC_6; break;
267        case CS7: umr1 |= MCF5206E_UMR1_BC_7; break;
268        case CS8: umr1 |= MCF5206E_UMR1_BC_8; break;
269    }
270   
271    /* Set number of stop bits */
272    if ((t->c_cflag & CSTOPB) != 0)
273    {
274        if ((t->c_cflag & CSIZE) == CS5)
275        {
276            umr2 |= MCF5206E_UMR2_SB5_2;
277        }
278        else
279        {
280            umr2 |= MCF5206E_UMR2_SB_2;
281        }
282    }
283    else
284    {
285        if ((t->c_cflag & CSIZE) == CS5)
286        {
287            umr2 |= MCF5206E_UMR2_SB5_1;
288        }
289        else
290        {
291            umr2 |= MCF5206E_UMR2_SB_1;
292        }
293    }
294   
295    /* Set parity mode */
296    if ((t->c_cflag & PARENB) != 0)
297    {
298        if ((t->c_cflag & PARODD) != 0)
299        {
300            umr1 |= MCF5206E_UMR1_PM_ODD;
301        }
302        else
303        {
304            umr1 |= MCF5206E_UMR1_PM_EVEN;
305        }
306    }
307    else
308    {
309        umr1 |= MCF5206E_UMR1_PM_NO_PARITY;
310    }
311   
312    rtems_interrupt_disable(level);
313    *MCF5206E_UCR(MBAR,uart->chn) = 
314        MCF5206E_UCR_TC_DISABLE | MCF5206E_UCR_RC_DISABLE;
315    mcfuart_set_baudrate(uart, baud);
316    *MCF5206E_UCR(MBAR,uart->chn) = MCF5206E_UCR_MISC_RESET_MR;
317    *MCF5206E_UMR(MBAR,uart->chn) = umr1;
318    *MCF5206E_UMR(MBAR,uart->chn) = umr2;
319    if ((t->c_cflag & CREAD) != 0)
320    {
321        *MCF5206E_UCR(MBAR,uart->chn) = 
322            MCF5206E_UCR_TC_ENABLE | MCF5206E_UCR_RC_ENABLE;
323    }
324    else
325    {
326        *MCF5206E_UCR(MBAR,uart->chn) = MCF5206E_UCR_TC_ENABLE;
327    }
328    rtems_interrupt_enable(level);
329   
330    return RTEMS_SUCCESSFUL;
331}
332
333/*
334 * mcfuart_poll_read --
335 *     This function tried to read character from MCF UART and perform
336 *     error handling. When parity or framing error occured, return
337 *     value dependent on termios input mode flags:
338 *         - received character, if IGNPAR == 1
339 *         - 0, if IGNPAR == 0 and PARMRK == 0
340 *         - 0xff and 0x00 on next poll_read invocation, if IGNPAR == 0 and
341 *           PARMRK == 1
342 *
343 * PARAMETERS:
344 *     uart - pointer to UART descriptor structure
345 *
346 * RETURNS:
347 *     code of received character or -1 if no characters received.
348 */
349int
350mcfuart_poll_read(mcfuart *uart)
351{
352    uint8_t   usr;
353    int ch;
354    if (uart->parerr_mark_flag == true)
355    {
356        uart->parerr_mark_flag = false;
357        return 0;
358    }
359    usr = *MCF5206E_USR(MBAR,uart->chn);
360    if ((usr & MCF5206E_USR_RXRDY) != 0)
361    {
362        if (((usr & (MCF5206E_USR_FE | MCF5206E_USR_PE)) != 0) &&
363            !(uart->c_iflag & IGNPAR))
364        {
365            ch = *MCF5206E_URB(MBAR,uart->chn); /* Clear error bits */
366            if (uart->c_iflag & PARMRK)
367            {
368                uart->parerr_mark_flag = true;
369                ch = 0xff;
370            }
371            else
372            {
373                ch = 0;
374            }
375        }
376        else
377        {
378            ch = *MCF5206E_URB(MBAR,uart->chn);
379        }
380    }
381    else
382        ch = -1;
383    return ch;
384}
385
386/*
387 * mcfuart_poll_write --
388 *     This function transmit buffer byte-by-byte in polling mode.
389 *
390 * PARAMETERS:
391 *     uart - pointer to the UART descriptor structure
392 *     buf - pointer to transmit buffer
393 *     len - transmit buffer length
394 *
395 * RETURNS:
396 *     0
397 */
398int
399mcfuart_poll_write(mcfuart *uart, const char *buf, int len)
400{
401    while (len--)
402    {
403        while ((*MCF5206E_USR(MBAR, uart->chn) & MCF5206E_USR_TXRDY) == 0);
404        *MCF5206E_UTB(MBAR, uart->chn) = *buf++;
405    }
406    return 0;
407}
408
409/* mcfuart_interrupt_handler --
410 *     UART interrupt handler routine
411 *
412 * PARAMETERS:
413 *     vec - interrupt vector number
414 *
415 * RETURNS:
416 *     none
417 */
418static rtems_isr
419mcfuart_interrupt_handler(rtems_vector_number vec)
420{
421    mcfuart *uart;
422    register uint8_t   usr;
423    register uint8_t   uisr;
424    register int chn;
425    register int bp = 0;
426   
427    /* Find UART descriptor from vector number */
428    if (int_driven_uart[0].vec == vec)
429        uart = int_driven_uart[0].uart;
430    else if (int_driven_uart[1].vec == vec)
431        uart = int_driven_uart[1].uart;
432    else
433        return;
434   
435    chn = uart->chn;
436   
437    uisr = *MCF5206E_UISR(MBAR, chn);
438    if (uisr & MCF5206E_UISR_DB)
439    {
440        *MCF5206E_UCR(MBAR, chn) = MCF5206E_UCR_MISC_RESET_BRK;
441    }
442   
443    /* Receiving */
444    while (1)
445    {
446        char buf[32];
447        usr = *MCF5206E_USR(MBAR,chn);
448        if ((bp < sizeof(buf) - 1) && ((usr & MCF5206E_USR_RXRDY) != 0))
449        {
450            /* Receive character and handle frame/parity errors */
451            if (((usr & (MCF5206E_USR_FE | MCF5206E_USR_PE)) != 0) &&
452                !(uart->c_iflag & IGNPAR))
453            {
454                if (uart->c_iflag & PARMRK)
455                {
456                    buf[bp++] = 0xff;
457                    buf[bp++] = 0x00;
458                }
459                else
460                {
461                    buf[bp++] = 0x00;
462                }
463            }
464            else
465            {
466                buf[bp++] = *MCF5206E_URB(MBAR, chn);
467            }
468           
469            /* Reset error condition if any errors has been detected */
470            if (usr & (MCF5206E_USR_RB | MCF5206E_USR_FE | 
471                       MCF5206E_USR_PE | MCF5206E_USR_OE))
472            {
473                *MCF5206E_UCR(MBAR, chn) = MCF5206E_UCR_MISC_RESET_ERR;
474            }
475        }
476        else
477        {
478            if (bp != 0)
479                rtems_termios_enqueue_raw_characters(uart->tty, buf, bp);
480            break;
481        }
482    }
483   
484    /* Transmitting */
485    while (1)
486    {
487        if ((*MCF5206E_USR(MBAR, chn) & MCF5206E_USR_TXRDY) == 0)
488            break;
489        if (uart->tx_buf != NULL)
490        {
491            if (uart->tx_ptr >= uart->tx_buf_len)
492            {
493                register int dequeue = uart->tx_buf_len;
494                *MCF5206E_UIMR(MBAR, uart->chn) = MCF5206E_UIMR_FFULL;
495                uart->tx_buf = NULL;
496                uart->tx_ptr = uart->tx_buf_len = 0;
497                rtems_termios_dequeue_characters(uart->tty, dequeue);
498            }
499            else
500            {
501                *MCF5206E_UTB(MBAR, chn) = uart->tx_buf[uart->tx_ptr++];
502            }
503        }
504        else
505            break;
506    }
507}
508
509/* mcfuart_interrupt_write --
510 *     This function initiate transmitting of the buffer in interrupt mode.
511 *
512 * PARAMETERS:
513 *     uart - pointer to the UART descriptor structure
514 *     buf - pointer to transmit buffer
515 *     len - transmit buffer length
516 *
517 * RETURNS:
518 *     0
519 */
520int
521mcfuart_interrupt_write(mcfuart *uart, const char *buf, int len)
522{
523    int level;
524    rtems_interrupt_disable(level);
525    uart->tx_buf = buf;
526    uart->tx_buf_len = len;
527    uart->tx_ptr = 0;
528    *MCF5206E_UIMR(MBAR, uart->chn) = 
529            MCF5206E_UIMR_FFULL | MCF5206E_UIMR_TXRDY;
530    while (((*MCF5206E_USR(MBAR,uart->chn) & MCF5206E_USR_TXRDY) != 0) &&
531           (uart->tx_ptr < uart->tx_buf_len))
532    {
533        *MCF5206E_UTB(MBAR,uart->chn) = uart->tx_buf[uart->tx_ptr++];
534    }
535    rtems_interrupt_enable(level);
536    return 0;
537}
538
539/* mcfuart_stop_remote_tx --
540 *     This function stop data flow from remote device.
541 *
542 * PARAMETERS:
543 *     uart - pointer to the UART descriptor structure
544 *
545 * RETURNS:
546 *     RTEMS_SUCCESSFUL
547 */
548int
549mcfuart_stop_remote_tx(mcfuart *uart)
550{
551    *MCF5206E_UOP0(MBAR, uart->chn) = 1;
552    return RTEMS_SUCCESSFUL;
553}
554
555/* mcfuart_start_remote_tx --
556 *     This function resume data flow from remote device.
557 *
558 * PARAMETERS:
559 *     uart - pointer to the UART descriptor structure
560 *
561 * RETURNS:
562 *     RTEMS_SUCCESSFUL
563 */
564int
565mcfuart_start_remote_tx(mcfuart *uart)
566{
567    *MCF5206E_UOP1(MBAR, uart->chn) = 1;
568    return RTEMS_SUCCESSFUL;
569}
Note: See TracBrowser for help on using the repository browser.