1 /******************************************************************************
2 *                                                                             *
3 * License Agreement                                                           *
4 *                                                                             *
5 * Copyright (c) 2006 Altera Corporation, San Jose, California, USA.           *
6 * All rights reserved.                                                        *
7 *                                                                             *
8 * Permission is hereby granted, free of charge, to any person obtaining a     *
9 * copy of this software and associated documentation files (the "Software"),  *
10 * to deal in the Software without restriction, including without limitation   *
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,    *
12 * and/or sell copies of the Software, and to permit persons to whom the       *
13 * Software is furnished to do so, subject to the following conditions:        *
14 *                                                                             *
15 * The above copyright notice and this permission notice shall be included in  *
16 * all copies or substantial portions of the Software.                         *
17 *                                                                             *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    *
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     *
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         *
24 * DEALINGS IN THE SOFTWARE.                                                   *
25 *                                                                             *
26 *                                                                             *
27 ******************************************************************************/
28 
29 #include <string.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <limits.h>
33 
34 #include <sys/stat.h>
35 
36 #include "sys/alt_irq.h"
37 #include "sys/alt_alarm.h"
38 #include "sys/ioctl.h"
39 #include "alt_types.h"
40 
41 #include "altera_avalon_jtag_uart_regs.h"
42 #include "altera_avalon_jtag_uart.h"
43 
44 #include "sys/alt_log_printf.h"
45 
46 #ifdef __ucosii__
47 #include "includes.h"
48 #endif /* __ucosii__ */
49 
50 #ifdef ALTERA_AVALON_JTAG_UART_SMALL
51 
52 /* ----------------------------------------------------------- */
53 /* ------------------------ SMALL DRIVER --------------------- */
54 /* ----------------------------------------------------------- */
55 
56 /* Write routine.  The small version blocks when there is no space to write
57  * into, so it's performance will be very bad if you are writing more than
58  * one FIFOs worth of data.  But you said you didn't want to use interrupts :-)
59  */
60 
altera_avalon_jtag_uart_write(altera_avalon_jtag_uart_state * sp,const char * ptr,int count,int flags)61 int altera_avalon_jtag_uart_write(altera_avalon_jtag_uart_state* sp,
62   const char * ptr, int count, int flags)
63 {
64   unsigned int base = sp->base;
65 
66   const char * end = ptr + count;
67 
68   while (ptr < end)
69     if ((IORD_ALTERA_AVALON_JTAG_UART_CONTROL(base) & ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK) != 0)
70       IOWR_ALTERA_AVALON_JTAG_UART_DATA(base, *ptr++);
71 
72   return count;
73 }
74 
75 #else /* !ALTERA_AVALON_JTAG_UART_SMALL */
76 
77 /* ----------------------------------------------------------- */
78 /* ------------------------- FAST DRIVER --------------------- */
79 /* ----------------------------------------------------------- */
80 
81 int
altera_avalon_jtag_uart_write(altera_avalon_jtag_uart_state * sp,const char * ptr,int count,int flags)82 altera_avalon_jtag_uart_write(altera_avalon_jtag_uart_state* sp,
83   const char * ptr, int count, int flags)
84 {
85   /* Remove warning at optimisation level 03 by seting out to 0 */
86   unsigned int in, out=0;
87   unsigned int n;
88   alt_irq_context context;
89 
90   const char * start = ptr;
91 
92   /*
93    * When running in a multi threaded environment, obtain the "write_lock"
94    * semaphore. This ensures that writing to the device is thread-safe.
95    */
96   ALT_SEM_PEND (sp->write_lock, 0);
97 
98   do
99   {
100     /* Copy as much as we can into the transmit buffer */
101     while (count > 0)
102     {
103       /* We need a stable value of the out pointer to calculate the space available */
104       in  = sp->tx_in;
105       out = sp->tx_out;
106 
107       if (in < out)
108         n = out - 1 - in;
109       else if (out > 0)
110         n = ALTERA_AVALON_JTAG_UART_BUF_LEN - in;
111       else
112         n = ALTERA_AVALON_JTAG_UART_BUF_LEN - 1 - in;
113 
114       if (n == 0)
115         break;
116 
117       if (n > count)
118         n = count;
119 
120       memcpy(sp->tx_buf + in, ptr, n);
121       ptr   += n;
122       count -= n;
123 
124       sp->tx_in = (in + n) % ALTERA_AVALON_JTAG_UART_BUF_LEN;
125     }
126 
127     /*
128      * If interrupts are disabled then we could transmit here, we only need
129      * to enable interrupts if there is no space left in the FIFO
130      *
131      * For now kick the interrupt routine every time to make it transmit
132      * the data
133      */
134     context = alt_irq_disable_all();
135     sp->irq_enable |= ALTERA_AVALON_JTAG_UART_CONTROL_WE_MSK;
136     IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(sp->base, sp->irq_enable);
137     alt_irq_enable_all(context);
138 
139     /*
140      * If there is any data left then either return now or block until
141      * some has been sent
142      */
143     /* consider: test whether there is anything there while doing this and delay for at most 2s. */
144     if (count > 0)
145     {
146       if (flags & O_NONBLOCK)
147         break;
148 
149 #ifdef __ucosii__
150       /* OS Present: Pend on a flag if the OS is running, otherwise spin */
151       if(OSRunning == OS_TRUE) {
152         /*
153          * When running in a multi-threaded mode, we pend on the write event
154          * flag set or the timeout flag in the isr. This avoids wasting CPU
155          * cycles waiting in this thread, when we could be doing something
156          * more profitable elsewhere.
157          */
158 #ifdef ALTERA_AVALON_JTAG_UART_IGNORE_FIFO_FULL_ERROR
159         if(!sp->host_inactive)
160 #endif
161         ALT_FLAG_PEND (sp->events,
162                        ALT_JTAG_UART_WRITE_RDY | ALT_JTAG_UART_TIMEOUT,
163                        OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME,
164                        0);
165       }
166       else {
167         /*
168          * OS not running: Wait for data to be removed from buffer.
169          * Once the interrupt routine has removed some data then we
170          * will be able to insert some more.
171          */
172         while (out == sp->tx_out && sp->host_inactive < sp->timeout)
173           ;
174       }
175 #else
176       /*
177        * No OS present: Always wait for data to be removed from buffer.  Once
178        * the interrupt routine has removed some data then we will be able to
179        * insert some more.
180        */
181       while (out == sp->tx_out && sp->host_inactive < sp->timeout)
182         ;
183 #endif /* __ucosii__ */
184 
185       if  (sp->host_inactive)
186          break;
187     }
188   }
189   while (count > 0);
190 
191   /*
192    * Now that access to the circular buffer is complete, release the write
193    * semaphore so that other threads can access the buffer.
194    */
195   ALT_SEM_POST (sp->write_lock);
196 
197   if (ptr != start)
198     return ptr - start;
199   else if (flags & O_NONBLOCK)
200     return -EWOULDBLOCK;
201 #ifdef ALTERA_AVALON_JTAG_UART_IGNORE_FIFO_FULL_ERROR
202   else if (sp->host_inactive >= sp->timeout) {
203     /*
204      * Reset the software FIFO, hardware FIFO could not be reset.
205      * Just throw away characters without reporting error.
206      */
207     sp->tx_out = sp->tx_in = 0;
208     return ptr - start + count;
209   }
210 #endif
211   else
212     return -EIO; /* Host not connected */
213 }
214 
215 #endif /* ALTERA_AVALON_JTAG_UART_SMALL */
216