source: rtems/c/src/lib/libbsp/sparc/shared/uart/apbuart.c @ f8359c9

4.104.114.84.95
Last change on this file since f8359c9 was f8359c9, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 6, 2007 at 3:41:37 PM

2007-09-06 Joel Sherrill <joel.sherrill@…>

  • shared/uart/apbuart.c: Fix some warnings.
  • Property mode set to 100644
File size: 22.8 KB
Line 
1/*
2 *  This file contains the driver for the APBUART serial port.
3 *  No console driver, only char driver.
4 *
5 *  COPYRIGHT (c) 2007.
6 *  Gaisler Research.
7 *
8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
10 *  http://www.rtems.com/license/LICENSE.
11 *
12 *
13 *  2007-07-11, Daniel Hellstrom <daniel@gaisler.com>
14 *    Added ioctl command APBUART_CLR_STATS
15 */
16
17#include <bsp.h>
18#include <rtems/libio.h>
19#include <stdlib.h>
20#include <assert.h>
21#include <rtems/bspIo.h>
22#include <string.h>
23
24#include <ambapp.h>
25#include <apbuart.h>
26
27#ifndef DEFAULT_TXBUF_SIZE
28 #define DEFAULT_TXBUF_SIZE 32
29#endif
30#ifndef DEFAULT_RXBUF_SIZE
31 #define DEFAULT_RXBUF_SIZE 32
32#endif
33
34#ifndef APBUART_PREFIX
35 #define APBUART_PREFIX(name) apbuart##name
36#endif
37
38#if !defined(APBUART_DEVNAME) || !defined(APBUART_DEVNAME_NO)
39 #undef APBUART_DEVNAME
40 #undef APBUART_DEVNAME_NO
41 #define APBUART_DEVNAME "/dev/apbuart0"
42 #define APBUART_DEVNAME_NO(devstr,no) ((devstr)[12]='0'+(no))
43#endif
44
45#ifndef APBUART_REG_INT
46        #define APBUART_REG_INT(handler,irq,arg) set_vector(handler,irq+0x10,1)
47#endif
48
49/* Default to 40MHz system clock */
50/*#ifndef SYS_FREQ_HZ
51 #define SYS_FREQ_HZ 40000000
52#endif*/
53
54typedef struct {
55        int size;
56        unsigned char *buf,
57                      *tail,
58                            *head,
59                                                                *max;
60        int full; /* no more place in fifo */
61} apbuart_fifo;
62
63static apbuart_fifo *apbuart_fifo_create(int size);
64static void apbuart_fifo_free(apbuart_fifo *fifo);
65static inline int apbuart_fifo_isFull(apbuart_fifo *fifo);
66static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo);
67static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c);
68static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c);
69static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c);
70static void inline apbuart_fifo_skip(apbuart_fifo *fifo);
71
72static rtems_device_driver apbuart_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor,  void *arg);
73static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
74static rtems_device_driver apbuart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
75static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
76static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
77static rtems_device_driver apbuart_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
78
79typedef struct {
80        ambapp_apb_uart *regs;
81        int irq;
82        int minor;
83        int scaler;
84        unsigned int baud;     
85
86        int txblk;    /* Make write block until at least 1 char has
87                       * been put into software send fifo
88                                                                 */
89        int tx_flush; /* Set this to block until all data has
90                       * placed into the hardware send fifo
91                                                                 */
92        int rxblk;    /* Make read block until at least 1 char has
93                       * been received (or taken from software fifo).
94                                                                 */
95        int started;  /* Set to 1 when in running mode */       
96       
97        int ascii_mode; /* Set to 1 to make \n be printed as \r\n */
98       
99        /* TX/RX software FIFO Buffers */
100        apbuart_fifo *txfifo;
101        apbuart_fifo *rxfifo;
102       
103        apbuart_stats stats;
104       
105        rtems_id dev_sem;
106        rtems_id rx_sem;
107        rtems_id tx_sem;
108} apbuart_priv;
109
110static int dev_cnt;
111static apbuart_priv *apbuarts;
112static unsigned int sys_freq_hz;
113
114#define APBUART_DRIVER_TABLE_ENTRY { apbuart_initialize, apbuart_open, apbuart_close, apbuart_read, apbuart_write, apbuart_control }
115
116static rtems_driver_address_table apbuart_driver = APBUART_DRIVER_TABLE_ENTRY;
117static amba_confarea_type *amba_bus;
118
119static void apbuart_interrupt(apbuart_priv *uart);
120static void apbuart_interrupt_handler(rtems_vector_number v);
121static void apbuart_hw_close(apbuart_priv *uart);
122static void apbuart_hw_open(apbuart_priv *uart);
123
124/* Uncomment for debug output */
125/* #define DEBUG 1
126 #define FUNCDEBUG 1 */
127
128#ifdef DEBUG
129#define DBG(x...) printk(x)
130#else
131#define DBG(x...)
132#endif
133#ifdef FUNCDEBUG
134#define FUNCDBG(x...) printk(x)
135#else
136#define FUNCDBG(x...)
137#endif
138
139#ifndef READ_REG
140        #define READ_REG(address) _APBUART_READ_REG((unsigned int)(address))
141  static __inline__ unsigned int _APBUART_READ_REG(unsigned int addr) {
142        unsigned int tmp;
143        asm(" lda [%1]1, %0 "
144            : "=r"(tmp)
145            : "r"(addr)
146           );
147        return tmp;
148        }
149#endif
150
151#if 0
152static int apbuart_outbyte_try(ambapp_apb_uart *regs,  unsigned char ch)
153{
154        if ( (READ_REG(&regs->status) & LEON_REG_UART_STATUS_THE) == 0 )
155                return -1; /* Failed */
156       
157        /* There is room in fifo, put ch in it */
158        regs->data = (unsigned int) ch;
159        return 0;
160}
161
162
163static int apbuart_inbyte_try(ambapp_apb_uart *regs)
164{
165        unsigned int status;
166        /* Clear errors if any */       
167        if ( (status=READ_REG(&regs->status)) & LEON_REG_UART_STATUS_ERR) {
168                regs->status = status & ~LEON_REG_UART_STATUS_ERR;
169        }
170       
171        /* Is Data available? */
172        if ( (READ_REG(&regs->status) & LEON_REG_UART_STATUS_DR) == 0 )
173                return -1; /* No data avail */
174       
175        /* Return Data */
176        return (int)READ_REG(&regs->data);
177}
178
179static int apbuart_write_support(apbuart_priv *uart, const char *buf, int len)
180{
181        int nwrite = 0;
182
183        while (nwrite < len) {
184                if ( apbuart_outbyte_try(minor, *buf++) ){
185                        /* TX Fifo full */
186                       
187                }
188                nwrite++;
189        }
190        return nwrite;
191}
192#endif
193
194static void apbuart_hw_open(apbuart_priv *uart){
195        unsigned int scaler;
196       
197        /* Calculate Baudrate */
198        if ( uart->scaler > 0 ) {
199                scaler = uart->scaler;
200        }else{
201                scaler = (((sys_freq_hz*10)/(uart->baud*8))-5)/10;
202        }
203       
204        /* Set new baud rate */
205        uart->regs->scaler = scaler;
206       
207        /* Enable receiver & Transmitter */
208        uart->regs->ctrl = APBUART_CTRL_RE | APBUART_CTRL_RF | APBUART_CTRL_RI | APBUART_CTRL_TI;
209}
210
211static void apbuart_hw_close(apbuart_priv *uart){
212        /* disable receiver & transmitter & all IRQs */
213        uart->regs->ctrl = 0;
214}
215
216/* interrupt handler */
217static void apbuart_interrupt_handler(rtems_vector_number v){
218        int minor;
219       
220        /* convert to */
221  for(minor = 0; minor < dev_cnt; minor++) {
222        if ( v == (apbuarts[minor].irq+0x10) ) {
223                        apbuart_interrupt(&apbuarts[minor]);
224                        return;
225                }
226        }
227}
228
229/* The interrupt handler, taking care of the
230 * APBUART hardware
231 */
232static void apbuart_interrupt(apbuart_priv *uart){
233        unsigned int status;
234        int empty;
235        unsigned char c, *next_char = NULL;
236        int signal;
237       
238        /* Clear & record any error */
239        status = READ_REG(&uart->regs->status);
240        if ( status & (APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE) ){
241                /* Data overrun */
242                if ( status & APBUART_STATUS_OV ){
243                        uart->stats.hw_dovr++;
244                }
245                /* Parity error */
246                if ( status & APBUART_STATUS_PE ){
247                        uart->stats.hw_parity++;
248                }
249                /* Framing error */
250                if ( status & APBUART_STATUS_FE ){
251                        uart->stats.hw_frame++;
252                }
253                uart->regs->status = status & ~(APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE);
254        }
255       
256        /* Empty RX fifo into software fifo */
257        signal = 0;
258        while ( (status=READ_REG(&uart->regs->status)) & APBUART_STATUS_DR ){
259                c = READ_REG(&uart->regs->data);
260                if ( apbuart_fifo_isFull(uart->rxfifo) ){
261                        uart->stats.sw_dovr++;
262      DBG("]");
263                        break;
264                }
265                /* put into fifo */
266                apbuart_fifo_put(uart->rxfifo,c);
267   
268                /* bump RX counter */
269                uart->stats.rx_cnt++;
270   
271                signal = 1;
272        }
273       
274        /* Wake RX thread if any */
275        if ( signal )
276                rtems_semaphore_release(uart->rx_sem);
277       
278        /* If room in HW fifo and we got more chars to be sent */
279        if ( !(status & APBUART_STATUS_TF) ){
280               
281                if ( apbuart_fifo_isEmpty(uart->txfifo) ){
282                        /* Turn off TX interrupt when no data is to be sent */
283                        if ( status & APBUART_STATUS_TE ){
284                                uart->regs->ctrl = READ_REG(&uart->regs->ctrl) & ~APBUART_CTRL_TF;
285                                DBG("?");
286                        }
287                        return;
288                }
289               
290                /* signal when there will be more room in SW fifo */
291                if ( apbuart_fifo_isFull(uart->txfifo) )
292                        signal = 1;
293               
294                do{
295                        /* Put data into HW TX fifo */
296                        apbuart_fifo_peek(uart->txfifo,&next_char);
297                        c = *next_char;
298                        if ( uart->ascii_mode && ( c == '\n') ){
299                                uart->regs->data = '\n';
300                                *next_char = '\r'; /* avoid sending mutiple '\n' or '\r' */
301                        }else{
302                                uart->regs->data = c;
303                                apbuart_fifo_skip(uart->txfifo); /* remove sent char from fifo */
304                        }
305                        uart->regs->ctrl = READ_REG(&uart->regs->ctrl) | APBUART_CTRL_TE | APBUART_CTRL_TF;
306                        DBG("!");
307                }while(!(empty=apbuart_fifo_isEmpty(uart->txfifo)) && 
308                       !((status=READ_REG(&uart->regs->status))&APBUART_STATUS_TF) );
309               
310                /* Wake userspace thread, on empty or full fifo
311                 * This makes tx_flush and block work.
312                 */
313                if ( signal || empty ){
314                        rtems_semaphore_release(uart->tx_sem);
315                }
316        }
317}
318
319int APBUART_PREFIX(_register)(amba_confarea_type *bus) {
320        rtems_status_code r;
321        rtems_device_major_number m;
322
323        amba_bus = bus;
324
325        FUNCDBG("apbuart_register:\n");
326
327        if ((r = rtems_io_register_driver(0, &apbuart_driver, &m)) == RTEMS_SUCCESSFUL) {
328                DBG("APBUART driver successfully registered, major: %d\n", m);
329        } else {
330                switch(r) {
331                case RTEMS_TOO_MANY:
332                        printk("APBUART rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); return -1;
333                case RTEMS_INVALID_NUMBER: 
334                        printk("APBUART rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); return -1;
335                case RTEMS_RESOURCE_IN_USE:
336                        printk("APBUART rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); return -1;
337                default:
338                   printk("APBUART rtems_io_register_driver failed\n");
339                         return -1;
340                }
341        }
342        return 0;
343}
344
345static rtems_device_driver apbuart_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor,  void *arg)
346{
347   
348        rtems_status_code status;
349        int i;
350        amba_apb_device dev;
351        char fs_name[20];
352
353        FUNCDBG("apbuart_initialize\n");
354
355        /* Find all APB UART devices */
356        dev_cnt = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_APBUART);
357        if ( dev_cnt < 1 ){
358                /* Failed to find any CAN cores! */
359                printk("APBUART: Failed to find any APBUART cores\n\r");
360                return -1;
361        }
362       
363        strcpy(fs_name,APBUART_DEVNAME);
364       
365        DBG("Found %d APBUART(s)\n\r",dev_cnt);
366       
367        /* Allocate memory for device structures */
368        apbuarts = malloc(sizeof(apbuart_priv) * dev_cnt);
369        if ( !apbuarts ){
370                printk("APBUART: Failed to allocate SW memory\n\r");
371                return -1;
372        }
373 
374  memset(apbuarts,0,sizeof(sizeof(apbuart_priv) * dev_cnt));
375               
376        /* Detect System Frequency from initialized timer */
377#ifndef SYS_FREQ_HZ
378#if defined(LEON3)
379        /* LEON3: find timer address via AMBA Plug&Play info */ 
380        {
381                amba_apb_device gptimer;
382                LEON3_Timer_Regs_Map *tregs;
383               
384                if ( amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_GPTIMER,&gptimer) == 1 ){
385                        tregs = (LEON3_Timer_Regs_Map *)gptimer.start;
386                        sys_freq_hz = (tregs->scaler_reload+1)*1000*1000;
387                        DBG("APBUART: detected %dHZ system frequency\n\r",sys_freq_hz);
388                }else{
389                        sys_freq_hz = 40000000; /* Default to 40MHz */
390                        printk("APBUART: Failed to detect system frequency\n\r");
391                }
392               
393        }
394#elif defined(LEON2)
395        /* LEON2: use hardcoded address to get to timer */
396        {
397                LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
398                sys_freq_hz = (regs->Scaler_Reload+1)*1000*1000;
399        }
400#else
401  #error CPU not supported for OC_CAN driver
402#endif
403#else
404        /* Use hardcoded frequency */
405        sys_freq_hz = SYS_FREQ_HZ;
406#endif
407               
408        for(i=0; i<dev_cnt; i++){
409                /* Get AMBA AHB device info from Plug&Play */
410                amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,GAISLER_APBUART,&dev,i);
411               
412                printk("APBUART[%d]: at 0x%x irq %d (0x%x)\n\r",i,dev.start,dev.irq,(unsigned int)&apbuarts[i]);
413               
414                apbuarts[i].regs = (ambapp_apb_uart *)dev.start;
415                apbuarts[i].irq = dev.irq;
416                apbuarts[i].minor = i;
417               
418                /* Clear HW regs */
419                apbuarts[i].regs->status = 0;
420                apbuarts[i].regs->ctrl = 0;   
421               
422                /* Allocate default software buffers */
423                apbuarts[i].txfifo = apbuart_fifo_create(DEFAULT_TXBUF_SIZE);           
424                apbuarts[i].rxfifo = apbuart_fifo_create(DEFAULT_RXBUF_SIZE);
425                if ( !apbuarts[i].txfifo || !apbuarts[i].rxfifo )
426                        rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
427               
428                APBUART_DEVNAME_NO(fs_name,i);
429
430                /* Bind name to device */
431                DBG("APBUART[%d]: binding to name %s\n\r",i,fs_name);
432                status = rtems_io_register_name(fs_name, major, i);
433                if (status != RTEMS_SUCCESSFUL)
434                        rtems_fatal_error_occurred(status);
435               
436                /* Setup interrupt handler for each channel */
437        APBUART_REG_INT(APBUART_PREFIX(_interrupt_handler), apbuarts[i].irq, &apbuarts[i]);
438               
439                /* Device A Semaphore created with count = 1 */
440                if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'D', '0'+i),
441                     1,
442                     RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, 
443                     0,
444                     &apbuarts[i].dev_sem) != RTEMS_SUCCESSFUL )
445                        return RTEMS_INTERNAL_ERROR;
446               
447                if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'T', '0'+i),
448                     1,
449                     RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, 
450                     0,
451                     &apbuarts[i].tx_sem) != RTEMS_SUCCESSFUL )
452                        return RTEMS_INTERNAL_ERROR;
453                                 
454                if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'R', '0'+i),
455                     1,
456                     RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, 
457                     0,
458                     &apbuarts[i].rx_sem) != RTEMS_SUCCESSFUL )
459                        return RTEMS_INTERNAL_ERROR;
460
461        }
462        return RTEMS_SUCCESSFUL;
463}
464
465static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
466{ 
467        apbuart_priv *uart;
468       
469        FUNCDBG("apbuart_open: major %d, minor %d\n", major, minor);
470
471        if ( (minor < 0) || (minor >= dev_cnt) ) {
472                DBG("Wrong minor %d\n", minor);
473                return RTEMS_INVALID_NAME;
474        }
475       
476        uart = &apbuarts[minor];
477
478        if (rtems_semaphore_obtain(uart->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
479                DBG("apbuart_open: resource in use\n");
480                return RTEMS_RESOURCE_IN_USE;
481        }
482       
483        /* Clear HW regs */
484        uart->regs->status = 0;
485        uart->regs->ctrl = 0;
486       
487        /* Set Defaults */
488       
489        /* 38400 baudrate */
490        uart->scaler = 0; /* use uart->baud */
491        uart->baud = 38400;
492       
493        /* Default to Blocking mode */
494        uart->txblk = 1;
495        uart->rxblk = 1;
496               
497        /* Default to no flush mode */
498        uart->tx_flush = 0;
499
500        /* non-ascii mode */
501        uart->ascii_mode = 0;
502 
503  /* not started */
504  uart->started = 0;
505       
506        if ( !uart->txfifo || (uart->txfifo->size!=DEFAULT_TXBUF_SIZE) ){
507                apbuart_fifo_free(uart->txfifo);
508                uart->txfifo = apbuart_fifo_create(DEFAULT_TXBUF_SIZE);
509        }
510       
511        if ( !uart->rxfifo || (uart->rxfifo->size!=DEFAULT_RXBUF_SIZE) ){
512                apbuart_fifo_free(uart->rxfifo);
513                uart->rxfifo = apbuart_fifo_create(DEFAULT_RXBUF_SIZE);
514        }
515       
516        if ( !uart->rxfifo || !uart->txfifo ){
517                /* Failed to get memory */
518                return RTEMS_NO_MEMORY;
519        }
520       
521        /* Now user must call ioctl(START,0) to begin */
522       
523        return RTEMS_SUCCESSFUL;
524}
525
526static rtems_device_driver apbuart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
527{
528        apbuart_priv *uart = &apbuarts[minor];
529       
530        FUNCDBG("apbuart_close[%d]:\n",minor);
531       
532        apbuart_hw_close(uart);
533
534        /* Software state will be set when open is called again */
535        rtems_semaphore_release(uart->rx_sem);
536        rtems_semaphore_release(uart->tx_sem);
537        uart->started = 0;
538       
539        rtems_semaphore_release(uart->dev_sem);
540       
541        return RTEMS_SUCCESSFUL;
542}
543 
544static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
545{
546        rtems_libio_rw_args_t *rw_args;
547        unsigned int count = 0, oldLevel;
548        unsigned char *buf;
549        apbuart_priv *uart = &apbuarts[minor];
550       
551        rw_args = (rtems_libio_rw_args_t *) arg;
552
553        FUNCDBG("apbuart_read\n");
554       
555        buf = (unsigned char *)rw_args->buffer;
556        if ( (rw_args->count < 1) || !buf )
557                return RTEMS_INVALID_NAME; /* EINVAL */
558
559        rtems_interrupt_disable(oldLevel);
560        do {
561                if ( (unsigned int)uart < 0x40000000 ) {
562      printk("UART %x is screwed\n",uart);
563    }
564                /* Read from SW fifo */
565                if ( apbuart_fifo_get(uart->rxfifo,&buf[count]) != 0 ){                 
566                        /* non blocking or read at least 1 byte */
567                        if ( (count > 0) || (!uart->rxblk) )
568                                break; /* Return */
569                       
570                        rtems_interrupt_enable(oldLevel);
571
572                        /* Block thread until a char is received */
573                        rtems_semaphore_obtain(uart->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
574     
575                        rtems_interrupt_disable(oldLevel);
576                        continue;
577                }
578               
579                /* Got char from SW FIFO */
580                count++;
581               
582        } while (count < rw_args->count );
583       
584        rtems_interrupt_enable(oldLevel);
585
586        rw_args->bytes_moved = count;
587       
588        if (count == 0)
589                return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
590
591        return RTEMS_SUCCESSFUL;
592}
593 
594static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
595{
596        rtems_libio_rw_args_t *rw_args;
597        unsigned int count, oldLevel, ctrl;
598        char *buf;
599        apbuart_priv *uart = &apbuarts[minor];
600        int direct=0;
601       
602   
603        rw_args = (rtems_libio_rw_args_t *) arg;
604 
605        FUNCDBG("apbuart_write\n");
606       
607        buf = rw_args->buffer;
608       
609        if ( rw_args->count < 1 || !buf )
610                return RTEMS_INVALID_NAME; /* EINVAL */ 
611       
612        count = 0;
613        rtems_interrupt_disable(oldLevel);
614        /* Do we need to start to send first char direct via HW
615         * to get IRQ going.
616         */
617       
618        ctrl = READ_REG(&uart->regs->ctrl);
619        if ( (ctrl & APBUART_CTRL_TF) == 0 ){
620                /* TX interrupt is disabled ==>
621                 * SW FIFO is empty and,
622                 * HW FIFO empty
623                 */
624                uart->regs->ctrl = ctrl | APBUART_CTRL_TF;
625                if ( uart->ascii_mode && (buf[0] == '\n') ){
626                        uart->regs->data = '\r';
627                }else{
628                        uart->regs->data = buf[0];
629                        count++;
630                }
631                uart->regs->ctrl = ctrl | APBUART_CTRL_TE | APBUART_CTRL_TF;
632                direct = 1;
633        }
634       
635        while( count < rw_args->count ) {
636                /* write to HW FIFO direct skipping SW FIFO */
637                if ( direct && ((READ_REG(&uart->regs->status) & APBUART_STATUS_TF) == 0) ){
638                        uart->regs->data = buf[count];
639                }
640                /* write to SW FIFO */
641                else if ( apbuart_fifo_put(uart->txfifo,buf[count]) ){
642                        direct = 0;
643                        DBG("APBUART[%d]: write: SW FIFO Full\n\r",minor);
644                       
645                        /* is full, block? */
646                        if ( ((count < 1) && uart->txblk) || uart->tx_flush ){
647                       
648                                rtems_interrupt_enable(oldLevel);
649                               
650                                rtems_semaphore_obtain(uart->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
651                               
652                                rtems_interrupt_disable(oldLevel);
653                       
654                                /* Do we need to start to send first char direct via HW
655                                 * to get IRQ going.
656                                 */
657       
658                                ctrl = READ_REG(&uart->regs->ctrl);
659                                if ( (ctrl & APBUART_CTRL_TF) == 0 ){
660                                        /* TX interrupt is disabled ==>
661                                         * SW FIFO is empty and,
662                                         * HW FIFO empty
663                                         */
664                                        uart->regs->ctrl = ctrl | APBUART_CTRL_TF;
665                                        if ( uart->ascii_mode && (buf[count] == '\n') ){
666                                                uart->regs->data = '\r';
667                                        }else{
668                                                uart->regs->data = buf[count];
669                                                count++;
670                                        }
671                                        uart->regs->ctrl = ctrl | APBUART_CTRL_TF | APBUART_CTRL_TE;
672                                        direct = 1;
673                                }
674                               
675                                continue;
676                        }
677                        /* don't block, return current status */
678                        break;
679                }else{
680                        direct = 0;
681                }
682               
683                count++;
684               
685        }
686
687        rtems_interrupt_enable(oldLevel);
688       
689        rw_args->bytes_moved = count;
690       
691        if (count == 0)
692                return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
693 
694        return RTEMS_SUCCESSFUL;
695}
696
697static rtems_device_driver apbuart_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
698{
699        rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
700        unsigned int *data = ioarg->buffer;
701        apbuart_priv *uart = &apbuarts[minor];
702        int size;
703        unsigned int baudrate, blocking;
704        apbuart_stats *stats;
705
706        FUNCDBG("apbuart_control [%i,%i]\n",major, minor);
707 
708        if (!ioarg)
709                return RTEMS_INVALID_NAME;
710
711  ioarg->ioctl_return = 0;
712        switch(ioarg->command) {
713       
714        /* Enable Receiver & transmitter */
715        case APBUART_START:
716                if ( uart->started )
717                        return RTEMS_INVALID_NAME;
718                apbuart_hw_open(uart);
719                uart->started = 1;
720                break;
721       
722        /* Close Receiver & transmitter */
723        case APBUART_STOP:
724                if ( !uart->started )
725                        return RTEMS_INVALID_NAME;
726                apbuart_hw_close(uart);
727                uart->started = 0;
728                break;
729       
730        /* Set RX FIFO Software buffer length
731         * It is only possible to change buffer size in
732         * non-running mode.
733         */
734        case APBUART_SET_RXFIFO_LEN:
735                if ( uart->started )
736                        return RTEMS_RESOURCE_IN_USE; /* EBUSY */
737       
738                size = (int)ioarg->buffer;
739                if ( size < 1 ) 
740                        return RTEMS_INVALID_NAME; /* EINVAL */
741               
742                /* Free old buffer */
743                apbuart_fifo_free(uart->rxfifo);
744               
745                /* Allocate new buffer & init it */
746                uart->rxfifo = apbuart_fifo_create(size);
747                if ( !uart->rxfifo )
748                        return RTEMS_NO_MEMORY;
749                break;
750
751        /* Set TX FIFO Software buffer length
752         * It is only possible to change buffer size
753         * while in non-running mode.
754         */
755        case APBUART_SET_TXFIFO_LEN:
756                if ( uart->started )
757                        return RTEMS_RESOURCE_IN_USE; /* EBUSY */
758               
759                size = (int)ioarg->buffer;
760                if ( size < 1 ) 
761                        return RTEMS_INVALID_NAME; /* EINVAL */
762               
763                /* Free old buffer */
764                apbuart_fifo_free(uart->txfifo);
765               
766                /* Allocate new buffer & init it */
767                uart->txfifo = apbuart_fifo_create(size);
768                if ( !uart->txfifo )
769                        return RTEMS_NO_MEMORY;
770                break;
771       
772        case APBUART_SET_BAUDRATE:
773                /* Set baud rate of */
774                baudrate = (int)ioarg->buffer;
775                if ( (baudrate < 1) || (baudrate > 115200) ){
776                        return RTEMS_INVALID_NAME;
777                }
778                uart->scaler = 0; /* use uart->baud */
779                uart->baud = baudrate;
780                break;
781       
782        case APBUART_SET_SCALER:
783                /* use uart->scaler not uart->baud */
784                uart->scaler = data[0];
785                break;
786       
787        case APBUART_SET_BLOCKING:
788                blocking = (unsigned int)ioarg->buffer;
789                uart->rxblk = ( blocking & APBUART_BLK_RX );
790                uart->txblk = ( blocking & APBUART_BLK_TX );
791                uart->tx_flush = ( blocking & APBUART_BLK_FLUSH );
792                break;
793       
794        case APBUART_GET_STATS:
795                stats = (void *)ioarg->buffer;
796                if ( !stats )
797                        return RTEMS_INVALID_NAME;
798               
799                /* Copy Stats */
800                *stats = uart->stats;
801                break;
802 
803  case APBUART_CLR_STATS:
804                /* Clear/reset Stats */
805    memset(&uart->stats,0,sizeof(uart->stats));
806                break;
807   
808        case APBUART_SET_ASCII_MODE:
809                uart->ascii_mode = (int)ioarg->buffer;
810                break;
811   
812        default:
813                return RTEMS_NOT_DEFINED;
814        }
815        return RTEMS_SUCCESSFUL;
816}
817
818
819/******************* APBUART FIFO implementation ***********************/
820
821static apbuart_fifo *apbuart_fifo_create(int size){
822        apbuart_fifo *fifo;
823        fifo = (apbuart_fifo *) malloc(size + sizeof(apbuart_fifo));
824        if ( fifo ) {
825                /* Init fifo */
826                fifo->size = size;
827                fifo->buf = (unsigned char *)(fifo+1);
828                fifo->tail = fifo->buf;
829                fifo->head = fifo->buf;
830                fifo->max = &fifo->buf[size-1];
831                fifo->full=0;
832        }
833        return fifo;
834}
835
836static void apbuart_fifo_free(apbuart_fifo *fifo){
837        if ( fifo )
838                free(fifo);
839}
840
841static inline int apbuart_fifo_isFull(apbuart_fifo *fifo){
842        return fifo->full;
843}
844
845static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo){
846        if ( (fifo->head == fifo->tail) && !fifo->full )
847                return -1;
848        return 0;
849}
850
851static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c){
852        if ( !fifo->full ){
853                *fifo->head = c;
854                fifo->head = (fifo->head >= fifo->max ) ? fifo->buf : fifo->head+1;
855                if ( fifo->head == fifo->tail )
856                        fifo->full = -1;
857                return 0;
858        }
859        return -1;
860}
861
862static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c){
863        if ( apbuart_fifo_isEmpty(fifo) )
864                return -1;
865        if ( c )
866                *c = *fifo->tail;
867        fifo->tail = (fifo->tail >= fifo->max ) ? fifo->buf : fifo->tail+1;
868        fifo->full = 0;
869        return 0;
870}
871
872static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c){
873        if ( apbuart_fifo_isEmpty(fifo) )
874                return -1;
875        if ( c )
876                *c = fifo->tail;
877        return 0;
878}
879
880static void inline apbuart_fifo_skip(apbuart_fifo *fifo){
881        if ( !apbuart_fifo_isEmpty(fifo) ){
882                fifo->tail = (fifo->tail >= fifo->max ) ? fifo->buf : fifo->tail+1;
883                fifo->full = 0;
884        }
885}
Note: See TracBrowser for help on using the repository browser.