]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/ColdFire/__sys_arch.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / Common / ethernet / lwIP_130 / contrib / port / FreeRTOS / ColdFire / __sys_arch.c
1 /*\r
2  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
3  * Modifications Copyright (c) 2006 Christian Walter <wolti@sil.at>\r
4  * All rights reserved.\r
5  *\r
6  * Redistribution and use in source and binary forms, with or without modification,\r
7  * are permitted provided that the following conditions are met:\r
8  *\r
9  * 1. Redistributions of source code must retain the above copyright notice,\r
10  *    this list of conditions and the following disclaimer.\r
11  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
12  *    this list of conditions and the following disclaimer in the documentation\r
13  *    and/or other materials provided with the distribution.\r
14  * 3. The name of the author may not be used to endorse or promote products\r
15  *    derived from this software without specific prior written permission.\r
16  *\r
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
20  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
22  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
26  * OF SUCH DAMAGE.\r
27  *\r
28  * This file is part of the lwIP TCP/IP stack.\r
29  *\r
30  * Author: Adam Dunkels <adam@sics.se>\r
31  * Modifcations: Christian Walter <wolti@sil.at>\r
32  *\r
33  * $Id: sys_arch.c,v 1.1 2008/08/05 00:10:49 b06862 Exp $\r
34  */\r
35 \r
36 /* ------------------------ System includes ------------------------------- */\r
37 \r
38 #include "stdlib.h"\r
39 \r
40 /* ------------------------ FreeRTOS includes ----------------------------- */\r
41 #include "FreeRTOS.h"\r
42 #include "task.h"\r
43 #include "semphr.h"\r
44 \r
45 /* ------------------------ lwIP includes --------------------------------- */\r
46 #include "lwip/debug.h"\r
47 #include "lwip/def.h"\r
48 #include "lwip/sys.h"\r
49 #include "lwip/mem.h"\r
50 #include "lwip/sio.h"\r
51 #include "lwip/stats.h"\r
52 \r
53 /* ------------------------ Project includes ------------------------------ */\r
54 \r
55 /* ------------------------ Defines --------------------------------------- */\r
56 /* This is the number of threads that can be started with sys_thead_new() */\r
57 #define SYS_MBOX_SIZE               ( 16 )\r
58 #define MS_TO_TICKS( ms )           \\r
59     ( portTickType )( ( portTickType ) ( ms ) / portTICK_RATE_MS )\r
60 #define TICKS_TO_MS( ticks )        \\r
61     ( unsigned long )( ( portTickType ) ( ticks ) * portTICK_RATE_MS )\r
62 #define THREAD_STACK_SIZE           ( 256 /*FSL:1024*/ )\r
63 #define THREAD_NAME                 "lwIP"\r
64 \r
65 #define THREAD_INIT( tcb ) \\r
66     do { \\r
67         tcb->next = NULL; \\r
68         tcb->pid = ( xTaskHandle )0; \\r
69         tcb->timeouts.next = NULL; \\r
70     } while( 0 )\r
71 \r
72 /* ------------------------ Type definitions ------------------------------ */\r
73 typedef struct sys_tcb\r
74 {\r
75     struct sys_tcb *next;\r
76     struct sys_timeouts timeouts;\r
77     xTaskHandle     pid;\r
78 } sys_tcb_t;\r
79 \r
80 /* ------------------------ Prototypes ------------------------------------ */\r
81 \r
82 /* ------------------------ Static functions ------------------------------ */\r
83 sys_tcb_t      *sys_thread_current( void );\r
84 \r
85 /* ------------------------ Static variables ------------------------------ */\r
86 static sys_tcb_t *tasks = NULL;\r
87 \r
88 /* ------------------------ Start implementation -------------------------- */\r
89 void\r
90 sys_init( void )\r
91 {\r
92     LWIP_ASSERT( "sys_init: not called first", tasks == NULL );\r
93     tasks = NULL;\r
94 }\r
95 \r
96 /*\r
97  * This optional function does a "fast" critical region protection and returns\r
98  * the previous protection level. This function is only called during very short\r
99  * critical regions. An embedded system which supports ISR-based drivers might\r
100  * want to implement this function by disabling interrupts. Task-based systems\r
101  * might want to implement this by using a mutex or disabling tasking. This\r
102  * function should support recursive calls from the same task or interrupt. In\r
103  * other words, sys_arch_protect() could be called while already protected. In\r
104  * that case the return value indicates that it is already protected.\r
105  *\r
106  * sys_arch_protect() is only required if your port is supporting an operating\r
107  * system.\r
108  */\r
109 sys_prot_t\r
110 sys_arch_protect( void )\r
111 {\r
112     vPortEnterCritical(  );\r
113     return 1;\r
114 }\r
115 \r
116 /*\r
117  * This optional function does a "fast" set of critical region protection to the\r
118  * value specified by pval. See the documentation for sys_arch_protect() for\r
119  * more information. This function is only required if your port is supporting\r
120  * an operating system.\r
121  */\r
122 void\r
123 sys_arch_unprotect( sys_prot_t pval )\r
124 {\r
125     ( void )pval;\r
126     vPortExitCritical(  );\r
127 }\r
128 \r
129 /*\r
130  * Prints an assertion messages and aborts execution.\r
131  */\r
132 void\r
133 sys_assert( const char *msg )\r
134 {       \r
135         /*FSL:only needed for debugging\r
136         printf(msg);\r
137         printf("\n\r");\r
138         */\r
139     vPortEnterCritical(  );\r
140     for(;;)\r
141     ;\r
142 }\r
143 \r
144 void\r
145 sys_debug( const char *const fmt, ... )\r
146 {\r
147         /*FSL: same implementation as printf*/\r
148 \r
149     /*FSL: removed due to lack of space*/\r
150     //printf(fmt);\r
151 }\r
152 \r
153 /* ------------------------ Start implementation ( Threads ) -------------- */\r
154 \r
155 /*\r
156  * Starts a new thread with priority "prio" that will begin its execution in the\r
157  * function "thread()". The "arg" argument will be passed as an argument to the\r
158  * thread() function. The argument "ssize" is the requested stack size for the\r
159  * new thread. The id of the new thread is returned. Both the id and the\r
160  * priority are system dependent.\r
161  */\r
162 sys_thread_t\r
163 sys_thread_new(char *name, void ( *thread ) ( void *arg ), void *arg, int /*size_t*/ stacksize, int prio )\r
164 {\r
165     sys_thread_t    thread_hdl = SYS_THREAD_NULL;\r
166     int             i;\r
167     sys_tcb_t      *p;\r
168 \r
169     /* We disable the FreeRTOS scheduler because it might be the case that the new\r
170      * tasks gets scheduled inside the xTaskCreate function. To prevent this we\r
171      * disable the scheduling. Note that this can happen although we have interrupts\r
172      * disabled because xTaskCreate contains a call to taskYIELD( ).\r
173      */\r
174     vPortEnterCritical(  );\r
175 \r
176     p = tasks;\r
177     i = 0;\r
178     /* We are called the first time. Initialize it. */\r
179     if( p == NULL )\r
180     {\r
181         p = (sys_tcb_t *)pvPortMalloc( sizeof( sys_tcb_t ) );\r
182         if( p != NULL )\r
183         {\r
184             tasks = p;\r
185         }\r
186     }\r
187     else\r
188     {\r
189         /* First task already counter. */\r
190         i++;\r
191         /* Cycle to the end of the list. */\r
192         while( p->next != NULL )\r
193         {\r
194             i++;\r
195             p = p->next;\r
196         }\r
197         p->next = (sys_tcb_t *)pvPortMalloc( sizeof( sys_tcb_t ) );\r
198         p = p->next;\r
199     }\r
200 \r
201     if( p != NULL )\r
202     {\r
203         /* Memory allocated. Initialize the data structure. */\r
204         THREAD_INIT( p );\r
205 \r
206         /* Now q points to a free element in the list. */\r
207         if( xTaskCreate( thread, (const signed char *const)name, stacksize, arg, prio, &p->pid ) == pdPASS )\r
208         {\r
209             thread_hdl = p;\r
210         }\r
211         else\r
212         {\r
213             vPortFree( p );\r
214         }\r
215     }\r
216 \r
217     vPortExitCritical(  );\r
218     return thread_hdl;\r
219 }\r
220 \r
221 void\r
222 sys_arch_thread_remove( sys_thread_t hdl )\r
223 {\r
224     sys_tcb_t      *current = tasks, *prev;\r
225     sys_tcb_t      *toremove = hdl;\r
226     xTaskHandle     pid = ( xTaskHandle ) 0;\r
227 \r
228     LWIP_ASSERT( "sys_arch_thread_remove: assertion hdl != NULL failed!", hdl != NULL );\r
229 \r
230     /* If we have to remove the first task we must update the global "tasks"\r
231      * variable. */\r
232     vPortEnterCritical(  );\r
233     if( hdl != NULL )\r
234     {\r
235         prev = NULL;\r
236         while( ( current != NULL ) && ( current != toremove ) )\r
237         {\r
238             prev = current;\r
239             current = current->next;\r
240         }\r
241         /* Found it. */\r
242         if( current == toremove )\r
243         {\r
244             /* Not the first entry in the list. */\r
245             if( prev != NULL )\r
246             {\r
247                 prev->next = toremove->next;\r
248             }\r
249             else\r
250             {\r
251                 tasks = toremove->next;\r
252             }\r
253             LWIP_ASSERT( "sys_arch_thread_remove: can't remove thread with timeouts!",\r
254                          toremove->timeouts.next == NULL );\r
255             pid = toremove->pid;\r
256             THREAD_INIT( toremove );\r
257             vPortFree( toremove );\r
258         }\r
259     }\r
260     /* We are done with accessing the shared datastructure. Release the \r
261      * resources.\r
262      */\r
263     vPortExitCritical(  );\r
264     if( pid != ( xTaskHandle ) 0 )\r
265     {\r
266         vTaskDelete( pid );\r
267         /* not reached. */\r
268     }\r
269 }\r
270 \r
271 /*\r
272  * Returns the thread control block for the currently active task. In case\r
273  * of an error the functions returns NULL.\r
274  */\r
275 sys_thread_t\r
276 sys_arch_thread_current( void )\r
277 {\r
278     sys_tcb_t      *p = tasks;\r
279     xTaskHandle     pid = xTaskGetCurrentTaskHandle(  );\r
280 \r
281     vPortEnterCritical(  );\r
282     while( ( p != NULL ) && ( p->pid != pid ) )\r
283     {\r
284         p = p->next;\r
285     }\r
286     vPortExitCritical(  );\r
287     return p;\r
288 }\r
289 \r
290 /*\r
291  * Returns a pointer to the per-thread sys_timeouts structure. In lwIP,\r
292  * each thread has a list of timeouts which is represented as a linked\r
293  * list of sys_timeout structures. The sys_timeouts structure holds a\r
294  * pointer to a linked list of timeouts. This function is called by\r
295  * the lwIP timeout scheduler and must not return a NULL value.\r
296  *\r
297  * In a single threaded sys_arch implementation, this function will\r
298  * simply return a pointer to a global sys_timeouts variable stored in\r
299  * the sys_arch module.\r
300  */\r
301 struct sys_timeouts *\r
302 sys_arch_timeouts( void )\r
303 {\r
304     sys_tcb_t      *ptask;\r
305 \r
306     ptask = sys_arch_thread_current(  );\r
307     LWIP_ASSERT( "sys_arch_timeouts: ptask != NULL", ptask != NULL );\r
308     return ptask != NULL ? &( ptask->timeouts ) : NULL;\r
309 }\r
310 \r
311 /* ------------------------ Start implementation ( Semaphores ) ----------- */\r
312 \r
313 /* Creates and returns a new semaphore. The "count" argument specifies\r
314  * the initial state of the semaphore.\r
315  */\r
316 sys_sem_t\r
317 sys_sem_new( u8_t count )\r
318 {\r
319     xSemaphoreHandle xSemaphore;\r
320 \r
321     vSemaphoreCreateBinary( xSemaphore );\r
322     if( xSemaphore != SYS_SEM_NULL )\r
323     {\r
324         if( count == 0 )\r
325         {\r
326             xSemaphoreTake( xSemaphore, 1 );\r
327         }\r
328 #if SYS_STATS == 1\r
329         vPortEnterCritical(  );\r
330         lwip_stats.sys.sem.used++;\r
331         if( lwip_stats.sys.sem.used > lwip_stats.sys.sem.max )\r
332         {\r
333             lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;\r
334         }\r
335         vPortExitCritical(  );\r
336 #endif\r
337     }\r
338     else\r
339     {\r
340         LWIP_ASSERT( "sys_sem_new: xSemaphore == SYS_SEM_NULL", xSemaphore != SYS_SEM_NULL );\r
341     }\r
342 \r
343     return xSemaphore;\r
344 }\r
345 \r
346 /* Deallocates a semaphore */\r
347 void\r
348 sys_sem_free( sys_sem_t sem )\r
349 {\r
350     LWIP_ASSERT( "sys_sem_free: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );\r
351     if( sem != SYS_SEM_NULL )\r
352     {\r
353 #if SYS_STATS == 1\r
354         vPortEnterCritical(  );\r
355         lwip_stats.sys.sem.used--;\r
356         vPortExitCritical(  );\r
357 #endif\r
358         vQueueDelete( sem );\r
359     }\r
360 }\r
361 \r
362 /* Signals a semaphore */\r
363 void\r
364 sys_sem_signal( sys_sem_t sem )\r
365 {\r
366     LWIP_ASSERT( "sys_sem_signal: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );\r
367     xSemaphoreGive( sem );\r
368 }\r
369 \r
370 /*\r
371  * Blocks the thread while waiting for the semaphore to be\r
372  * signaled. If the "timeout" argument is non-zero, the thread should\r
373  * only be blocked for the specified time (measured in\r
374  * milliseconds).\r
375  *\r
376  * If the timeout argument is non-zero, the return value is the number of\r
377  * milliseconds spent waiting for the semaphore to be signaled. If the\r
378  * semaphore wasn't signaled within the specified time, the return value is\r
379  * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore\r
380  * (i.e., it was already signaled), the function may return zero.\r
381  *\r
382  * Notice that lwIP implements a function with a similar name,\r
383  * sys_sem_wait(), that uses the sys_arch_sem_wait() function.\r
384  */\r
385 u32_t\r
386 sys_arch_sem_wait( sys_sem_t sem, u32_t timeout )\r
387 {\r
388     portBASE_TYPE   xStatus;\r
389     portTickType    xTicksStart, xTicksEnd, xTicksElapsed;\r
390     u32_t           timespent;\r
391 \r
392     LWIP_ASSERT( "sys_arch_sem_wait: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );\r
393     xTicksStart = xTaskGetTickCount(  );\r
394     if( timeout == 0 )\r
395     {\r
396         do\r
397         {\r
398             xStatus = xSemaphoreTake( sem, MS_TO_TICKS( 100 ) );\r
399         }\r
400         while( xStatus != pdTRUE );\r
401     }\r
402     else\r
403     {\r
404         xStatus = xSemaphoreTake( sem, MS_TO_TICKS( timeout ) );\r
405     }\r
406 \r
407     /* Semaphore was signaled. */\r
408     if( xStatus == pdTRUE )\r
409     {\r
410         xTicksEnd = xTaskGetTickCount(  );\r
411         xTicksElapsed = xTicksEnd - xTicksStart;\r
412         timespent = TICKS_TO_MS( xTicksElapsed );\r
413     }\r
414     else\r
415     {\r
416         timespent = SYS_ARCH_TIMEOUT;\r
417     }\r
418     return timespent;\r
419 }\r
420 \r
421 \r
422 /* ------------------------ Start implementation ( Mailboxes ) ------------ */\r
423 \r
424 /* Creates an empty mailbox. */\r
425 sys_mbox_t\r
426 sys_mbox_new( /*paolo:void*/int size )\r
427 {\r
428     xQueueHandle    mbox;\r
429 \r
430     mbox = xQueueCreate( SYS_MBOX_SIZE/*size*/, sizeof( void * ) );\r
431     if( mbox != SYS_MBOX_NULL )\r
432     {\r
433 #if SYS_STATS == 1\r
434         vPortEnterCritical(  );\r
435         lwip_stats.sys.mbox.used++;\r
436         if( lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max )\r
437         {\r
438             lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;\r
439         }\r
440         vPortExitCritical(  );\r
441 #endif\r
442     }\r
443     return mbox;\r
444 }\r
445 \r
446 /*\r
447   Deallocates a mailbox. If there are messages still present in the\r
448   mailbox when the mailbox is deallocated, it is an indication of a\r
449   programming error in lwIP and the developer should be notified.\r
450 */\r
451 void\r
452 sys_mbox_free( sys_mbox_t mbox )\r
453 {\r
454     void           *msg;\r
455 \r
456     LWIP_ASSERT( "sys_mbox_free: mbox != SYS_MBOX_NULL", mbox != SYS_MBOX_NULL );\r
457     if( mbox != SYS_MBOX_NULL )\r
458     {\r
459         while( uxQueueMessagesWaiting( mbox ) != 0 )\r
460         {\r
461             if( sys_arch_mbox_fetch( mbox, &msg, 1 ) != SYS_ARCH_TIMEOUT )\r
462             {\r
463                 LWIP_ASSERT( "sys_mbox_free: memory leak (msg != NULL)", msg == NULL );\r
464             }\r
465         }\r
466         vQueueDelete( mbox );\r
467 #if SYS_STATS == 1\r
468         vPortEnterCritical(  );\r
469         lwip_stats.sys.mbox.used--;\r
470         vPortExitCritical(  );\r
471 #endif\r
472     }\r
473 }\r
474 \r
475 /*\r
476  * This function sends a message to a mailbox. It is unusual in that no error\r
477  * return is made. This is because the caller is responsible for ensuring that\r
478  * the mailbox queue will not fail. The caller does this by limiting the number\r
479  * of msg structures which exist for a given mailbox.\r
480  */\r
481 void\r
482 sys_mbox_post( sys_mbox_t mbox, void *data )\r
483 {\r
484     portBASE_TYPE   xQueueSent;\r
485 \r
486     /* Queue must not be full - Otherwise it is an error. */\r
487     xQueueSent = xQueueSend( mbox, &data, 0 );\r
488     LWIP_ASSERT( "sys_mbox_post: xQueueSent == pdPASS", xQueueSent == pdPASS );\r
489 }\r
490 \r
491 /*FSL*/\r
492 /*  \r
493  *Try to post the "msg" to the mailbox. Returns ERR_MEM if this one\r
494  *is full, else, ERR_OK if the "msg" is posted.\r
495  */\r
496 err_t\r
497 sys_mbox_trypost( sys_mbox_t mbox, void *data )\r
498 {\r
499     /* Queue must not be full - Otherwise it is an error. */\r
500     if(xQueueSend( mbox, &data, 0 ) == pdPASS)\r
501     {\r
502         return ERR_OK;\r
503     }\r
504     else\r
505     {\r
506         return ERR_MEM;\r
507     }\r
508 }\r
509 \r
510 /*\r
511  * Blocks the thread until a message arrives in the mailbox, but does\r
512  * not block the thread longer than "timeout" milliseconds (similar to\r
513  * the sys_arch_sem_wait() function). The "msg" argument is a result\r
514  * parameter that is set by the function (i.e., by doing "*msg =\r
515  * ptr"). The "msg" parameter maybe NULL to indicate that the message\r
516  * should be dropped.\r
517  *\r
518  * Note that a function with a similar name, sys_mbox_fetch(), is\r
519  * implemented by lwIP.\r
520  */\r
521 u32_t\r
522 sys_arch_mbox_fetch( sys_mbox_t mbox, void **msg, u32_t timeout )\r
523 {\r
524     void           *ret_msg;\r
525     portBASE_TYPE   xStatus;\r
526     portTickType    xTicksStart, xTicksEnd, xTicksElapsed;\r
527     u32_t           timespent;\r
528 \r
529     LWIP_ASSERT( "sys_arch_mbox_fetch: mbox != SYS_MBOX_NULL", mbox != SYS_MBOX_NULL );\r
530     xTicksStart = xTaskGetTickCount(  );\r
531     if( timeout == 0 )\r
532     {\r
533         do\r
534         {\r
535             xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( 100 ) );\r
536         }\r
537         while( xStatus != pdTRUE );\r
538     }\r
539     else\r
540     {\r
541         xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( timeout ) );\r
542     }\r
543 \r
544     if( xStatus == pdTRUE )\r
545     {\r
546         if( msg )\r
547         {\r
548             *msg = ret_msg;\r
549         }\r
550         xTicksEnd = xTaskGetTickCount(  );\r
551         xTicksElapsed = xTicksEnd - xTicksStart;\r
552         timespent = TICKS_TO_MS( xTicksElapsed );\r
553     }\r
554     else\r
555     {\r
556         if( msg )\r
557         {\r
558             *msg = NULL;\r
559         }\r
560         timespent = SYS_ARCH_TIMEOUT;\r
561     }\r
562     return timespent;\r
563 }\r
564 \r
565 u32_t\r
566 sys_jiffies( void )\r
567 {\r
568     portTickType    xTicks = xTaskGetTickCount(  );\r
569 \r
570     return ( u32_t )TICKS_TO_MS( xTicks );\r
571 }\r