source: rtems/c/src/lib/libcpu/sh/sh7045/sci/sci_termios.c @ 1c6926c1

Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on Mar 21, 2017 at 7:39:48 PM

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

  • Property mode set to 100644
File size: 10.0 KB
Line 
1/*
2 * Termios console serial driver.
3 */
4
5/*
6 * Based on SCI driver by Ralf Corsepius and John M. Mills
7 *
8 * Author: Radzislaw Galler <rgaller@et.put.poznan.pl>
9 *
10 *  COPYRIGHT (c) 1989-2001.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 *
17 */
18
19#include <bsp.h>
20#include <stdlib.h>
21
22#include <libchip/serial.h>
23#include <libchip/sersupp.h>
24
25#include <rtems/libio.h>
26#include <rtems/iosupp.h>
27
28#include <rtems/score/sh_io.h>
29#include <rtems/score/ispsh7045.h>
30#include <rtems/score/iosh7045.h>
31
32#include <sh/sh7_sci.h>
33#include <sh/sh7_pfc.h>
34#include <sh/sci_termios.h>
35
36
37/*
38 * Some handy macros
39 */
40#define SH_SCI_REG_DATA(_data, _minor, _register) \
41 (write8(_data, Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)))
42
43#define SH_SCI_REG_FLAG(_flag, _minor, _register) \
44 (write8(read8(Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)) | (_flag), \
45         Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)))
46
47#define SH_SCI_REG_MASK(_flag, _minor, _register) \
48 (write8(read8(Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)) & ~(_flag),\
49         Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)))
50
51/*
52 * NOTE: Some SH variants have 3 sci devices
53 */
54
55#define SCI_MINOR_DEVICES       2
56
57
58/*
59 * Automatically generated function imported from scitab.rel
60 */
61extern int _sci_get_brparms(
62  speed_t       spd,
63  unsigned char *smr,
64  unsigned char *brr
65);
66
67/*
68 * Translate termios flags into SCI settings
69 */
70int sh_sci_set_attributes(
71  int minor,
72  const struct termios *t
73)
74{
75    uint8_t     smr;
76    uint8_t     brr;
77    int a;
78
79    tcflag_t c_cflag = t->c_cflag;
80    speed_t spd = t->c_ospeed;
81
82    if ( spd ) {
83        if ( _sci_get_brparms( spd, &smr, &brr ) != 0 )
84            return -1 ;
85    }
86
87    if ( c_cflag & CSIZE ) {
88        if ( c_cflag & CS8 )
89            smr &= ~SCI_SEVEN_BIT_DATA;
90        else if ( c_cflag & CS7 )
91            smr |= SCI_SEVEN_BIT_DATA;
92        else
93            return -1 ;
94    }
95
96    if ( c_cflag & CSTOPB )
97        smr |= SCI_STOP_BITS_2;
98    else
99        smr &= ~SCI_STOP_BITS_2;
100
101    if ( c_cflag & PARENB )
102        smr |= SCI_PARITY_ON ;
103    else
104        smr &= ~SCI_PARITY_ON ;
105
106    if ( c_cflag & PARODD )
107        smr |= SCI_ODD_PARITY ;
108    else
109        smr &= ~SCI_ODD_PARITY;
110
111    SH_SCI_REG_MASK((SCI_RE | SCI_TE), minor, SCI_SCR);
112
113    SH_SCI_REG_DATA(smr, minor, SCI_SMR);
114    SH_SCI_REG_DATA(brr, minor, SCI_BRR);
115
116    for (a=0; a < 10000L; a++) { /* Delay one bit */
117        __asm__ volatile ("nop");
118    }
119
120    SH_SCI_REG_FLAG((SCI_RE | SCI_TE), minor, SCI_SCR);
121
122    return 0;
123}
124
125/*
126 * Receive-data-full ISR
127 *
128 * The same routine for all interrupt sources of the same type.
129 */
130static rtems_isr sh_sci_rx_isr(rtems_vector_number vector)
131{
132    int minor;
133
134    for (minor = 0; minor < Console_Port_Count; minor++) {
135        if (Console_Port_Tbl[minor]->ulIntVector == vector) {
136            char   temp8;
137
138            /*
139             * FIXME: error handling should be added
140             */
141            temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_RDR);
142
143            rtems_termios_enqueue_raw_characters(
144                Console_Port_Data[minor].termios_data, &temp8, 1);
145
146            SH_SCI_REG_MASK(SCI_RDRF, minor, SCI_SSR);
147            break;
148        }
149    }
150}
151
152/*
153 * Transmit-data-empty ISR
154 *
155 * The same routine for all interrupt sources of the same type.
156 */
157static rtems_isr sh_sci_tx_isr(rtems_vector_number vector)
158{
159    int minor;
160
161    for (minor = 0; minor < Console_Port_Count; minor++) {
162        if (Console_Port_Tbl[minor]->ulDataPort == vector) {
163            /*
164             * FIXME: Error handling should be added
165             */
166
167            /*
168             * Mask end-of-transmission interrupt
169             */
170            SH_SCI_REG_MASK(SCI_TIE, minor, SCI_SCR);
171
172            if (rtems_termios_dequeue_characters(
173                   Console_Port_Data[minor].termios_data, 1)) {
174                /*
175                 * More characters to be received - interrupt must be enabled
176                 */
177                SH_SCI_REG_FLAG(SCI_TIE, minor, SCI_SCR);
178            }
179            break;
180        }
181    }
182}
183
184
185/*
186 * Initialization of serial port
187 */
188void sh_sci_init(int minor)
189{
190    uint16_t   temp16;
191
192    /*
193     * set PFC registers to enable I/O pins
194     */
195    if ((minor == 0)) {
196        temp16 = read16(PFC_PACRL2);         /* disable SCK0, DMA, IRQ */
197        temp16 &= ~(PA2MD1 | PA2MD0);
198        temp16 |= (PA_TXD0 | PA_RXD0);       /* enable pins for Tx0, Rx0 */
199        write16(temp16, PFC_PACRL2);
200
201    } else if (minor == 1) {
202        temp16 = read16(PFC_PACRL2);          /* disable SCK1, DMA, IRQ */
203        temp16 &= ~(PA5MD1 | PA5MD0);
204        temp16 |= (PA_TXD1 | PA_RXD1);        /* enable pins for Tx1, Rx1 */
205        write16(temp16, PFC_PACRL2);
206    }
207
208    /*
209     * Non-default hardware setup occurs in sh_sci_first_open
210     */
211}
212
213/*
214 * Initialization of interrupts
215 *
216 * Interrupts can be started only after opening a device, so interrupt
217 * flags are set up in sh_sci_first_open function
218 */
219void sh_sci_initialize_interrupts(int minor)
220{
221    rtems_isr_entry old_isr;
222    rtems_status_code status;
223
224    sh_sci_init(minor);
225    /*
226     * Disable IRQ of SCIx
227     */
228    status = sh_set_irq_priority( Console_Port_Tbl[minor]->ulIntVector, 0);
229
230    if (status != RTEMS_SUCCESSFUL)
231        rtems_fatal_error_occurred(status);
232
233    SH_SCI_REG_MASK(SCI_RIE, minor, SCI_SCR);
234
235    /*
236     * Catch apropriate vectors
237     */
238    status = rtems_interrupt_catch(
239        sh_sci_rx_isr,
240        Console_Port_Tbl[minor]->ulIntVector,
241        &old_isr);
242
243    if (status != RTEMS_SUCCESSFUL)
244        rtems_fatal_error_occurred(status);
245
246    status = rtems_interrupt_catch(
247        sh_sci_tx_isr,
248        Console_Port_Tbl[minor]->ulDataPort,
249        &old_isr);
250
251    if (status != RTEMS_SUCCESSFUL)
252        rtems_fatal_error_occurred(status);
253
254    /*
255     * Enable IRQ of SCIx
256     */
257    SH_SCI_REG_FLAG(SCI_RIE, minor, SCI_SCR);
258
259    status = sh_set_irq_priority(
260        Console_Port_Tbl[minor]->ulIntVector,
261        Console_Port_Tbl[minor]->ulCtrlPort2);
262
263    if (status != RTEMS_SUCCESSFUL)
264        rtems_fatal_error_occurred(status);
265}
266
267
268/*
269 *  Open entry point
270 *   Sets up port and pins for selected sci.
271 */
272
273int sh_sci_first_open(
274  int major,
275  int minor,
276  void *arg
277)
278{
279    char   temp8;
280    unsigned int a ;
281
282    /*
283     * check for valid minor number
284     */
285    if (( minor > ( SCI_MINOR_DEVICES -1 )) || ( minor < 0 )) {
286        return RTEMS_INVALID_NUMBER;
287    }
288
289    /*
290     * set up SCI registers
291     */
292    /* Clear SCR - disable Tx and Rx */
293    SH_SCI_REG_DATA(0x00, minor, SCI_SCR);
294
295    /* set SMR and BRR - baudrate and format */
296    sh_sci_set_attributes(minor, Console_Port_Tbl[minor]->pDeviceParams);
297
298    for (a=0; a < 10000L; a++) {                      /* Delay */
299        __asm__ volatile ("nop");
300    }
301
302    write8((SCI_RE | SCI_TE),              /* enable async. Tx and Rx */
303           Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SCR);
304
305    /*
306     * clear error flags
307     */
308    temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR);
309    while(temp8 & (SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER)) {
310        /* flush input */
311        temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_RDR);
312
313        /* clear some flags */
314        SH_SCI_REG_FLAG((SCI_RDRF|SCI_ORER|SCI_FER|SCI_PER), minor, SCI_SSR);
315
316        /* check if everything is OK */
317        temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR);
318    }
319
320    /* Clear RDRF flag */
321    SH_SCI_REG_DATA(0x00, minor, SCI_TDR); /* force output */
322
323    /* Clear the TDRE bit */
324    SH_SCI_REG_FLAG(SCI_TDRE, minor, SCI_SSR);
325
326    /*
327     * Interrupt setup
328     */
329    if (Console_Port_Tbl[minor]->pDeviceFns->deviceOutputUsesInterrupts) {
330        SH_SCI_REG_FLAG(SCI_RIE, minor, SCI_SCR);
331    }
332
333    return RTEMS_SUCCESSFUL ;
334}
335
336/*
337 *  Close entry point
338 */
339
340int sh_sci_last_close(
341  int major,
342  int minor,
343  void *arg
344)
345{
346    /* FIXME: Incomplete */
347
348    /* Shutdown interrupts if necessary */
349    if (Console_Port_Tbl[minor]->pDeviceFns->deviceOutputUsesInterrupts)
350    {
351        SH_SCI_REG_MASK((SCI_TIE | SCI_RIE), minor, SCI_SCR);
352    }
353    return RTEMS_SUCCESSFUL ;
354}
355
356/*
357 * Interrupt aware write routine
358 */
359ssize_t sh_sci_write_support_int(
360  int            minor,
361  const char    *buf,
362  size_t         len
363)
364{
365    if (!len)
366        return 0;
367    /*
368     * Put data into TDR and clear transmission-end-flag
369     */
370    SH_SCI_REG_DATA(*buf, minor, SCI_TDR);
371    SH_SCI_REG_MASK(SCI_TDRE, minor, SCI_SSR);
372    /*
373     * Enable interrupt
374     */
375    SH_SCI_REG_FLAG(SCI_TIE, minor, SCI_SCR);
376
377    return 1;
378}
379
380/*
381 * Polled write method
382 */
383ssize_t sh_sci_write_support_polled(
384  int            minor,
385  const char    *buf,
386  size_t         len
387)
388{
389    int count = 0;
390
391    while(count < len) {
392        sh_sci_write_polled(minor, buf[count]);
393        count++;
394    }
395    /*
396     * Return number of bytes written
397     */
398    return count;
399}
400
401/*
402 * Polled write of one character at a time
403 */
404void sh_sci_write_polled(
405  int     minor,
406  char    c
407)
408{
409    /*
410     * Wait for end of previous character
411     */
412    while(!(read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR) & SCI_TDRE));
413    /*
414     * Send the character
415     */
416    SH_SCI_REG_DATA(c, minor, SCI_TDR);
417
418    /*
419     * Clear TDRE flag
420     */
421    SH_SCI_REG_MASK(SCI_TDRE, minor, SCI_SSR);
422}
423
424/*
425 * Non-blocking read
426 */
427int sh_sci_inbyte_nonblocking_polled(int minor)
428{
429    char   inbyte;
430
431    /*
432     * Check if input buffer is full
433     */
434    if (read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR) & SCI_RDRF) {
435        inbyte = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_RDR);
436        SH_SCI_REG_MASK(SCI_RDRF, minor, SCI_SSR);
437
438        /*
439         * Check for errors
440         */
441        if (read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR) &
442           (SCI_ORER | SCI_FER | SCI_PER)) {
443            SH_SCI_REG_MASK((SCI_ORER | SCI_FER | SCI_PER), minor, SCI_SSR);
444            return -1;
445        }
446        return (int)inbyte;
447    }
448    return -1;
449}
Note: See TracBrowser for help on using the repository browser.