summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/backlight.c5
-rw-r--r--firmware/buffer.c4
-rw-r--r--firmware/common/dircache.c4
-rw-r--r--firmware/drivers/ata.c5
-rw-r--r--firmware/drivers/ata_mmc.c4
-rw-r--r--firmware/drivers/button.c2
-rw-r--r--firmware/drivers/fmradio_i2c.c6
-rw-r--r--firmware/drivers/i2c.c6
-rw-r--r--firmware/drivers/lcd-16bit.c2
-rw-r--r--firmware/drivers/lcd-2bit-horz.c2
-rw-r--r--firmware/drivers/lcd-h100-remote.c7
-rw-r--r--firmware/drivers/lcd-h100.c4
-rw-r--r--firmware/drivers/lcd-player.c2
-rw-r--r--firmware/drivers/lcd-recorder.c4
-rwxr-xr-xfirmware/drivers/lcd-remote-2bit-vi.c7
-rw-r--r--firmware/export/config.h8
-rw-r--r--firmware/export/kernel.h4
-rw-r--r--firmware/export/thread.h88
-rw-r--r--firmware/kernel.c65
-rw-r--r--firmware/mpeg.c14
-rw-r--r--firmware/pcm_record.c28
-rw-r--r--firmware/powermgmt.c2
-rw-r--r--firmware/thread.c485
-rw-r--r--firmware/usb.c5
24 files changed, 555 insertions, 208 deletions
diff --git a/firmware/backlight.c b/firmware/backlight.c
index bf88cbe9bc..4e76072822 100644
--- a/firmware/backlight.c
+++ b/firmware/backlight.c
@@ -618,12 +618,13 @@ static void backlight_tick(void)
618 618
619void backlight_init(void) 619void backlight_init(void)
620{ 620{
621 queue_init(&backlight_queue); 621 queue_init(&backlight_queue, true);
622#ifdef X5_BACKLIGHT_SHUTDOWN 622#ifdef X5_BACKLIGHT_SHUTDOWN
623 backlight_thread_id = 623 backlight_thread_id =
624#endif 624#endif
625 create_thread(backlight_thread, backlight_stack, 625 create_thread(backlight_thread, backlight_stack,
626 sizeof(backlight_stack), backlight_thread_name); 626 sizeof(backlight_stack), backlight_thread_name
627 IF_PRIO(, PRIORITY_SYSTEM));
627 tick_add_task(backlight_tick); 628 tick_add_task(backlight_tick);
628#ifdef SIMULATOR 629#ifdef SIMULATOR
629 /* do nothing */ 630 /* do nothing */
diff --git a/firmware/buffer.c b/firmware/buffer.c
index 1eaff33de1..6af8eb9432 100644
--- a/firmware/buffer.c
+++ b/firmware/buffer.c
@@ -40,7 +40,9 @@ void *buffer_alloc(size_t size)
40 void *retval = audiobuf; 40 void *retval = audiobuf;
41 41
42 audiobuf += size; 42 audiobuf += size;
43 /* 32-bit aligned */; 43 /* 32-bit aligned */
44 audiobuf = (void *)(((unsigned long)audiobuf + 3) & ~3); 44 audiobuf = (void *)(((unsigned long)audiobuf + 3) & ~3);
45
45 return retval; 46 return retval;
46} 47}
48
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c
index 17033e1827..0bdd0657bd 100644
--- a/firmware/common/dircache.c
+++ b/firmware/common/dircache.c
@@ -690,9 +690,9 @@ void dircache_init(void)
690 opendirs[i].secondary_entry.d_name = buffer_alloc(MAX_PATH); 690 opendirs[i].secondary_entry.d_name = buffer_alloc(MAX_PATH);
691 } 691 }
692 692
693 queue_init(&dircache_queue); 693 queue_init(&dircache_queue, true);
694 create_thread(dircache_thread, dircache_stack, 694 create_thread(dircache_thread, dircache_stack,
695 sizeof(dircache_stack), dircache_thread_name); 695 sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND));
696} 696}
697 697
698/** 698/**
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 8593eebea1..f57088504b 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -1932,11 +1932,12 @@ int ata_init(void)
1932 if (rc) 1932 if (rc)
1933 return -60 + rc; 1933 return -60 + rc;
1934 1934
1935 queue_init(&ata_queue); 1935 queue_init(&ata_queue, true);
1936 1936
1937 last_disk_activity = current_tick; 1937 last_disk_activity = current_tick;
1938 create_thread(ata_thread, ata_stack, 1938 create_thread(ata_thread, ata_stack,
1939 sizeof(ata_stack), ata_thread_name); 1939 sizeof(ata_stack), ata_thread_name
1940 IF_PRIO(, PRIORITY_SYSTEM));
1940 initialized = true; 1941 initialized = true;
1941 1942
1942 } 1943 }
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c
index b2e79c419a..6303ca2851 100644
--- a/firmware/drivers/ata_mmc.c
+++ b/firmware/drivers/ata_mmc.c
@@ -1182,9 +1182,9 @@ int ata_init(void)
1182 if (!last_mmc_status) 1182 if (!last_mmc_status)
1183 mmc_status = MMC_UNTOUCHED; 1183 mmc_status = MMC_UNTOUCHED;
1184#ifdef HAVE_HOTSWAP 1184#ifdef HAVE_HOTSWAP
1185 queue_init(&mmc_queue); 1185 queue_init(&mmc_queue, true);
1186 create_thread(mmc_thread, mmc_stack, 1186 create_thread(mmc_thread, mmc_stack,
1187 sizeof(mmc_stack), mmc_thread_name); 1187 sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM));
1188#endif 1188#endif
1189 tick_add_task(mmc_tick); 1189 tick_add_task(mmc_tick);
1190 initialized = true; 1190 initialized = true;
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
index daad4f17de..6536a34037 100644
--- a/firmware/drivers/button.c
+++ b/firmware/drivers/button.c
@@ -674,7 +674,7 @@ void button_init(void)
674 GPIOA_INT_CLR = GPIOA_INT_STAT; 674 GPIOA_INT_CLR = GPIOA_INT_STAT;
675 GPIOA_INT_EN = 0xff; 675 GPIOA_INT_EN = 0xff;
676#endif /* CONFIG_KEYPAD */ 676#endif /* CONFIG_KEYPAD */
677 queue_init(&button_queue); 677 queue_init(&button_queue, true);
678 button_read(); 678 button_read();
679 lastbtn = button_read(); 679 lastbtn = button_read();
680 tick_add_task(button_tick); 680 tick_add_task(button_tick);
diff --git a/firmware/drivers/fmradio_i2c.c b/firmware/drivers/fmradio_i2c.c
index 6f87e15b3e..62761b3aa7 100644
--- a/firmware/drivers/fmradio_i2c.c
+++ b/firmware/drivers/fmradio_i2c.c
@@ -317,8 +317,7 @@ static void fmradio_i2c_ack(int bit)
317 317
318 SCL_INPUT; /* Set the clock to input */ 318 SCL_INPUT; /* Set the clock to input */
319 while(!SCL) /* and wait for the slave to release it */ 319 while(!SCL) /* and wait for the slave to release it */
320 sleep_thread(); 320 sleep_thread(0);
321 wake_up_thread();
322 321
323 DELAY; 322 DELAY;
324 SCL_OUTPUT; 323 SCL_OUTPUT;
@@ -337,8 +336,7 @@ static int fmradio_i2c_getack(void)
337 SDA_INPUT; /* And set to input */ 336 SDA_INPUT; /* And set to input */
338 SCL_INPUT; /* Set the clock to input */ 337 SCL_INPUT; /* Set the clock to input */
339 while(!SCL) /* and wait for the slave to release it */ 338 while(!SCL) /* and wait for the slave to release it */
340 sleep_thread(); 339 sleep_thread(0);
341 wake_up_thread();
342 340
343 if (SDA) 341 if (SDA)
344 /* ack failed */ 342 /* ack failed */
diff --git a/firmware/drivers/i2c.c b/firmware/drivers/i2c.c
index 71cb9cf8b0..2b439c23ad 100644
--- a/firmware/drivers/i2c.c
+++ b/firmware/drivers/i2c.c
@@ -145,8 +145,7 @@ void i2c_ack(int bit)
145 145
146 SCL_INPUT; /* Set the clock to input */ 146 SCL_INPUT; /* Set the clock to input */
147 while(!SCL) /* and wait for the MAS to release it */ 147 while(!SCL) /* and wait for the MAS to release it */
148 sleep_thread(); 148 sleep_thread(1);
149 wake_up_thread();
150 149
151 DELAY; 150 DELAY;
152 SCL_OUTPUT; 151 SCL_OUTPUT;
@@ -168,8 +167,7 @@ int i2c_getack(void)
168 SDA_INPUT; /* And set to input */ 167 SDA_INPUT; /* And set to input */
169 SCL_INPUT; /* Set the clock to input */ 168 SCL_INPUT; /* Set the clock to input */
170 while(!SCL) /* and wait for the MAS to release it */ 169 while(!SCL) /* and wait for the MAS to release it */
171 sleep_thread(); 170 sleep_thread(1);
172 wake_up_thread();
173 171
174 if (SDA) 172 if (SDA)
175 /* ack failed */ 173 /* ack failed */
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index e6ae28bc19..47c02ea7b7 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -79,7 +79,7 @@ void lcd_init(void)
79 /* Call device specific init */ 79 /* Call device specific init */
80 lcd_init_device(); 80 lcd_init_device();
81 create_thread(scroll_thread, scroll_stack, 81 create_thread(scroll_thread, scroll_stack,
82 sizeof(scroll_stack), scroll_name); 82 sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
83} 83}
84 84
85/*** parameter handling ***/ 85/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c
index 33f483d38d..dc49a37c8a 100644
--- a/firmware/drivers/lcd-2bit-horz.c
+++ b/firmware/drivers/lcd-2bit-horz.c
@@ -76,7 +76,7 @@ void lcd_init(void)
76 /* Call device specific init */ 76 /* Call device specific init */
77 lcd_init_device(); 77 lcd_init_device();
78 create_thread(scroll_thread, scroll_stack, 78 create_thread(scroll_thread, scroll_stack,
79 sizeof(scroll_stack), scroll_name); 79 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
80} 80}
81 81
82/*** parameter handling ***/ 82/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-h100-remote.c b/firmware/drivers/lcd-h100-remote.c
index ed5816cebf..5db6d548ff 100644
--- a/firmware/drivers/lcd-h100-remote.c
+++ b/firmware/drivers/lcd-h100-remote.c
@@ -573,7 +573,7 @@ static void remote_tick(void)
573void lcd_remote_init(void) 573void lcd_remote_init(void)
574{ 574{
575 create_thread(scroll_thread, scroll_stack, 575 create_thread(scroll_thread, scroll_stack,
576 sizeof(scroll_stack), scroll_name); 576 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
577} 577}
578#else /* !SIMULATOR */ 578#else /* !SIMULATOR */
579 579
@@ -601,10 +601,11 @@ void lcd_remote_init(void)
601#endif 601#endif
602 lcd_remote_clear_display(); 602 lcd_remote_clear_display();
603 603
604 queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */ 604 /* private queue */
605 queue_init(&remote_scroll_queue, false);
605 tick_add_task(remote_tick); 606 tick_add_task(remote_tick);
606 create_thread(scroll_thread, scroll_stack, 607 create_thread(scroll_thread, scroll_stack,
607 sizeof(scroll_stack), scroll_name); 608 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
608} 609}
609 610
610/*** update functions ***/ 611/*** update functions ***/
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index 8407876d34..ada6f29216 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -144,7 +144,7 @@ void lcd_set_flip(bool yesno)
144void lcd_init(void) 144void lcd_init(void)
145{ 145{
146 create_thread(scroll_thread, scroll_stack, 146 create_thread(scroll_thread, scroll_stack,
147 sizeof(scroll_stack), scroll_name); 147 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
148} 148}
149#else 149#else
150 150
@@ -193,7 +193,7 @@ void lcd_init(void)
193 lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */ 193 lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */
194 194
195 create_thread(scroll_thread, scroll_stack, 195 create_thread(scroll_thread, scroll_stack,
196 sizeof(scroll_stack), scroll_name); 196 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
197} 197}
198 198
199/*** update functions ***/ 199/*** update functions ***/
diff --git a/firmware/drivers/lcd-player.c b/firmware/drivers/lcd-player.c
index 16012470fa..050258d1f8 100644
--- a/firmware/drivers/lcd-player.c
+++ b/firmware/drivers/lcd-player.c
@@ -610,7 +610,7 @@ void lcd_init (void)
610 lcd_set_contrast(lcd_default_contrast()); 610 lcd_set_contrast(lcd_default_contrast());
611 611
612 create_thread(scroll_thread, scroll_stack, 612 create_thread(scroll_thread, scroll_stack,
613 sizeof(scroll_stack), scroll_name); 613 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
614} 614}
615 615
616void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */ 616void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index 1987d9a3ed..e74cad7f03 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -232,7 +232,7 @@ void lcd_set_flip(bool yesno)
232void lcd_init(void) 232void lcd_init(void)
233{ 233{
234 create_thread(scroll_thread, scroll_stack, 234 create_thread(scroll_thread, scroll_stack,
235 sizeof(scroll_stack), scroll_name); 235 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
236} 236}
237#else 237#else
238 238
@@ -278,7 +278,7 @@ void lcd_init(void)
278 lcd_update(); 278 lcd_update();
279 279
280 create_thread(scroll_thread, scroll_stack, 280 create_thread(scroll_thread, scroll_stack,
281 sizeof(scroll_stack), scroll_name); 281 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
282} 282}
283 283
284/*** Update functions ***/ 284/*** Update functions ***/
diff --git a/firmware/drivers/lcd-remote-2bit-vi.c b/firmware/drivers/lcd-remote-2bit-vi.c
index 48f8b8a25f..bae2824050 100755
--- a/firmware/drivers/lcd-remote-2bit-vi.c
+++ b/firmware/drivers/lcd-remote-2bit-vi.c
@@ -1167,7 +1167,7 @@ static void scroll_thread(void)
1167void lcd_remote_init(void) 1167void lcd_remote_init(void)
1168{ 1168{
1169 create_thread(scroll_thread, scroll_stack, 1169 create_thread(scroll_thread, scroll_stack,
1170 sizeof(scroll_stack), scroll_name); 1170 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
1171} 1171}
1172#else 1172#else
1173void lcd_remote_init(void) 1173void lcd_remote_init(void)
@@ -1176,9 +1176,10 @@ void lcd_remote_init(void)
1176 lcd_remote_init_device(); 1176 lcd_remote_init_device();
1177 1177
1178 lcd_remote_clear_display(); 1178 lcd_remote_clear_display();
1179 queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */ 1179 /* private queue */
1180 queue_init(&remote_scroll_queue, false);
1180 tick_add_task(remote_tick); 1181 tick_add_task(remote_tick);
1181 create_thread(scroll_thread, scroll_stack, 1182 create_thread(scroll_thread, scroll_stack,
1182 sizeof(scroll_stack), scroll_name); 1183 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
1183} 1184}
1184#endif 1185#endif
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 18adaeeca2..1b756cc6bd 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -216,8 +216,12 @@
216/* Enable the directory cache and tagcache in RAM if we have 216/* Enable the directory cache and tagcache in RAM if we have
217 * plenty of RAM. Both features can be enabled independently. */ 217 * plenty of RAM. Both features can be enabled independently. */
218#if (MEMORYSIZE > 8 || MEM > 8) && !defined(BOOTLOADER) 218#if (MEMORYSIZE > 8 || MEM > 8) && !defined(BOOTLOADER)
219#define HAVE_DIRCACHE 1 219#define HAVE_DIRCACHE
220#define HAVE_TC_RAMCACHE 1 220#define HAVE_TC_RAMCACHE
221#endif
222
223#if (CONFIG_CODEC == SWCODEC) && !defined(SIMULATOR) && !defined(BOOTLOADER)
224#define HAVE_PRIORITY_SCHEDULING
221#endif 225#endif
222 226
223/* define for all cpus from coldfire family */ 227/* define for all cpus from coldfire family */
diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h
index 26b1cbe2e7..482516b9dc 100644
--- a/firmware/export/kernel.h
+++ b/firmware/export/kernel.h
@@ -56,12 +56,14 @@ struct event
56struct event_queue 56struct event_queue
57{ 57{
58 struct event events[QUEUE_LENGTH]; 58 struct event events[QUEUE_LENGTH];
59 struct thread_entry *thread;
59 unsigned int read; 60 unsigned int read;
60 unsigned int write; 61 unsigned int write;
61}; 62};
62 63
63struct mutex 64struct mutex
64{ 65{
66 struct thread_entry *thread;
65 bool locked; 67 bool locked;
66}; 68};
67 69
@@ -85,7 +87,7 @@ extern void sleep(int ticks);
85int tick_add_task(void (*f)(void)); 87int tick_add_task(void (*f)(void));
86int tick_remove_task(void (*f)(void)); 88int tick_remove_task(void (*f)(void));
87 89
88extern void queue_init(struct event_queue *q); 90extern void queue_init(struct event_queue *q, bool register_queue);
89extern void queue_delete(struct event_queue *q); 91extern void queue_delete(struct event_queue *q);
90extern void queue_wait(struct event_queue *q, struct event *ev); 92extern void queue_wait(struct event_queue *q, struct event *ev);
91extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks); 93extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks);
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index e102997dae..7e053bc507 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -21,8 +21,24 @@
21 21
22#include <stdbool.h> 22#include <stdbool.h>
23 23
24/* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works
25 * by giving high priority threads more CPU time than less priority threads
26 * when they need it.
27 *
28 * If software playback codec pcm buffer is going down to critical, codec
29 * can change it own priority to REALTIME to override user interface and
30 * prevent playback skipping.
31 */
32#define PRIORITY_REALTIME 1
33#define PRIORITY_USER_INTERFACE 4 /* The main thread */
34#define PRIORITY_RECORDING 4 /* Recording thread */
35#define PRIORITY_PLAYBACK 4 /* or REALTIME when needed */
36#define PRIORITY_BUFFERING 4 /* Codec buffering thread */
37#define PRIORITY_SYSTEM 6 /* All other firmware threads */
38#define PRIORITY_BACKGROUND 8 /* Normal application threads */
39
24#if CONFIG_CODEC == SWCODEC 40#if CONFIG_CODEC == SWCODEC
25#define MAXTHREADS 16 41#define MAXTHREADS 15
26#else 42#else
27#define MAXTHREADS 11 43#define MAXTHREADS 11
28#endif 44#endif
@@ -32,7 +48,7 @@
32#ifndef SIMULATOR 48#ifndef SIMULATOR
33/* Need to keep structures inside the header file because debug_menu 49/* Need to keep structures inside the header file because debug_menu
34 * needs them. */ 50 * needs them. */
35#ifdef CPU_COLDFIRE 51# ifdef CPU_COLDFIRE
36struct regs 52struct regs
37{ 53{
38 unsigned int macsr; /* EMAC status register */ 54 unsigned int macsr; /* EMAC status register */
@@ -41,7 +57,7 @@ struct regs
41 void *sp; /* Stack pointer (a7) */ 57 void *sp; /* Stack pointer (a7) */
42 void *start; /* Thread start address, or NULL when started */ 58 void *start; /* Thread start address, or NULL when started */
43}; 59};
44#elif CONFIG_CPU == SH7034 60# elif CONFIG_CPU == SH7034
45struct regs 61struct regs
46{ 62{
47 unsigned int r[7]; /* Registers r8 thru r14 */ 63 unsigned int r[7]; /* Registers r8 thru r14 */
@@ -49,7 +65,7 @@ struct regs
49 void *pr; /* Procedure register */ 65 void *pr; /* Procedure register */
50 void *start; /* Thread start address, or NULL when started */ 66 void *start; /* Thread start address, or NULL when started */
51}; 67};
52#elif defined(CPU_ARM) 68# elif defined(CPU_ARM)
53struct regs 69struct regs
54{ 70{
55 unsigned int r[8]; /* Registers r4-r11 */ 71 unsigned int r[8]; /* Registers r4-r11 */
@@ -57,42 +73,72 @@ struct regs
57 unsigned int lr; /* r14 (lr) */ 73 unsigned int lr; /* r14 (lr) */
58 void *start; /* Thread start address, or NULL when started */ 74 void *start; /* Thread start address, or NULL when started */
59}; 75};
60#elif CONFIG_CPU == TCC730 76# elif CONFIG_CPU == TCC730
61struct regs 77struct regs
62{ 78{
63 void *sp; /* Stack pointer (a15) */ 79 void *sp; /* Stack pointer (a15) */
64 void *start; /* Thread start address */ 80 void *start; /* Thread start address */
65 int started; /* 0 when not started */ 81 int started; /* 0 when not started */
66}; 82};
67#endif 83# endif
84
85#endif /* !SIMULATOR */
86
87#define STATE_RUNNING 0
88#define STATE_BLOCKED 1
89#define STATE_SLEEPING 2
90#define STATE_BLOCKED_W_TMO 3
91
92#define GET_STATE_ARG(state) (state & 0x3FFFFFFF)
93#define GET_STATE(state) ((state >> 30) & 3)
94#define SET_STATE(state,arg) ((state << 30) | (arg))
68 95
69struct thread_entry { 96struct thread_entry {
97#ifndef SIMULATOR
70 struct regs context; 98 struct regs context;
99#endif
71 const char *name; 100 const char *name;
72 void *stack; 101 void *stack;
73 int stack_size; 102 unsigned long statearg;
103 unsigned short stack_size;
104#ifdef HAVE_PRIORITY_SCHEDULING
105 unsigned short priority;
106 long last_run;
107#endif
108 struct thread_entry *next, *prev;
74}; 109};
75 110
76struct core_entry { 111struct core_entry {
77 int num_threads;
78 volatile int num_sleepers;
79 int current_thread;
80 struct thread_entry threads[MAXTHREADS]; 112 struct thread_entry threads[MAXTHREADS];
113 struct thread_entry *running;
114 struct thread_entry *sleeping;
81}; 115};
116
117#ifdef HAVE_PRIORITY_SCHEDULING
118#define IF_PRIO(empty, type) , type
119#else
120#define IF_PRIO(empty, type)
82#endif 121#endif
83 122
84int create_thread(void (*function)(void), void* stack, int stack_size, 123struct thread_entry*
85 const char *name); 124 create_thread(void (*function)(void), void* stack, int stack_size,
86int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, 125 const char *name IF_PRIO(, int priority));
87 const char *name); 126
88void remove_thread(int threadnum); 127struct thread_entry*
89void remove_thread_on_core(unsigned int core, int threadnum); 128 create_thread_on_core(unsigned int core, void (*function)(void),
90void switch_thread(void); 129 void* stack, int stack_size,
91void sleep_thread(void); 130 const char *name
92void wake_up_thread(void); 131 IF_PRIO(, int priority));
132
133void remove_thread(struct thread_entry *thread);
134void switch_thread(bool save_context, struct thread_entry **blocked_list);
135void sleep_thread(int ticks);
136void block_thread(struct thread_entry **thread, int timeout);
137void wakeup_thread(struct thread_entry **thread);
138void thread_set_priority(struct thread_entry *thread, int priority);
93void init_threads(void); 139void init_threads(void);
94int thread_stack_usage(int threadnum); 140int thread_stack_usage(const struct thread_entry *thread);
95int thread_stack_usage_on_core(unsigned int core, int threadnum); 141int thread_get_status(const struct thread_entry *thread);
96#ifdef RB_PROFILE 142#ifdef RB_PROFILE
97void profile_thread(void); 143void profile_thread(void);
98#endif 144#endif
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 889f950252..4a6d61515a 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -35,7 +35,6 @@ static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
35static struct event_queue *all_queues[32]; 35static struct event_queue *all_queues[32];
36static int num_queues; 36static int num_queues;
37 37
38void sleep(int ticks) ICODE_ATTR;
39void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR; 38void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR;
40 39
41/**************************************************************************** 40/****************************************************************************
@@ -71,13 +70,7 @@ void sleep(int ticks)
71 } while(counter > 0); 70 } while(counter > 0);
72 71
73#else 72#else
74 /* Always sleep at least 1 tick */ 73 sleep_thread(ticks);
75 int timeout = current_tick + ticks + 1;
76
77 while (TIME_BEFORE( current_tick, timeout )) {
78 sleep_thread();
79 }
80 wake_up_thread();
81#endif 74#endif
82} 75}
83 76
@@ -86,21 +79,24 @@ void yield(void)
86#if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER)) 79#if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER))
87 /* Some targets don't like yielding in the bootloader */ 80 /* Some targets don't like yielding in the bootloader */
88#else 81#else
89 switch_thread(); 82 switch_thread(true, NULL);
90 wake_up_thread();
91#endif 83#endif
92} 84}
93 85
94/**************************************************************************** 86/****************************************************************************
95 * Queue handling stuff 87 * Queue handling stuff
96 ****************************************************************************/ 88 ****************************************************************************/
97void queue_init(struct event_queue *q) 89void queue_init(struct event_queue *q, bool register_queue)
98{ 90{
99 q->read = 0; 91 q->read = 0;
100 q->write = 0; 92 q->write = 0;
101 93 q->thread = NULL;
102 /* Add it to the all_queues array */ 94
103 all_queues[num_queues++] = q; 95 if (register_queue)
96 {
97 /* Add it to the all_queues array */
98 all_queues[num_queues++] = q;
99 }
104} 100}
105 101
106void queue_delete(struct event_queue *q) 102void queue_delete(struct event_queue *q)
@@ -108,6 +104,8 @@ void queue_delete(struct event_queue *q)
108 int i; 104 int i;
109 bool found = false; 105 bool found = false;
110 106
107 wakeup_thread(&q->thread);
108
111 /* Find the queue to be deleted */ 109 /* Find the queue to be deleted */
112 for(i = 0;i < num_queues;i++) 110 for(i = 0;i < num_queues;i++)
113 { 111 {
@@ -132,26 +130,22 @@ void queue_delete(struct event_queue *q)
132 130
133void queue_wait(struct event_queue *q, struct event *ev) 131void queue_wait(struct event_queue *q, struct event *ev)
134{ 132{
135 while(q->read == q->write) 133 if (q->read == q->write)
136 { 134 {
137 sleep_thread(); 135 block_thread(&q->thread, 0);
138 } 136 }
139 wake_up_thread();
140 137
141 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; 138 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
142} 139}
143 140
144void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) 141void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
145{ 142{
146 unsigned int timeout = current_tick + ticks; 143 if (q->read == q->write && ticks > 0)
147
148 while(q->read == q->write && TIME_BEFORE( current_tick, timeout ))
149 { 144 {
150 sleep_thread(); 145 block_thread(&q->thread, ticks);
151 } 146 }
152 wake_up_thread();
153 147
154 if(q->read != q->write) 148 if (q->read != q->write)
155 { 149 {
156 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; 150 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
157 } 151 }
@@ -171,6 +165,9 @@ void queue_post(struct event_queue *q, long id, void *data)
171 165
172 q->events[wr].id = id; 166 q->events[wr].id = id;
173 q->events[wr].data = data; 167 q->events[wr].data = data;
168
169 wakeup_thread(&q->thread);
170
174 set_irq_level(oldlevel); 171 set_irq_level(oldlevel);
175} 172}
176 173
@@ -250,7 +247,6 @@ void IMIA0(void)
250 } 247 }
251 248
252 current_tick++; 249 current_tick++;
253 wake_up_thread();
254 250
255 TSR0 &= ~0x01; 251 TSR0 &= ~0x01;
256} 252}
@@ -301,7 +297,6 @@ void TIMER0(void)
301 } 297 }
302 298
303 current_tick++; 299 current_tick++;
304 wake_up_thread();
305 300
306 TER0 = 0xff; /* Clear all events */ 301 TER0 = 0xff; /* Clear all events */
307} 302}
@@ -330,7 +325,6 @@ void TIMER0(void)
330 } 325 }
331 326
332 current_tick++; 327 current_tick++;
333 wake_up_thread();
334 328
335 /* re-enable timer by clearing the counter */ 329 /* re-enable timer by clearing the counter */
336 TACON |= 0x80; 330 TACON |= 0x80;
@@ -382,7 +376,6 @@ void TIMER1(void)
382 } 376 }
383 377
384 current_tick++; 378 current_tick++;
385 wake_up_thread();
386} 379}
387#endif 380#endif
388 381
@@ -415,7 +408,6 @@ void timer_handler(void)
415 } 408 }
416 409
417 current_tick++; 410 current_tick++;
418 wake_up_thread();
419 411
420 TIMERR0C = 1; 412 TIMERR0C = 1;
421} 413}
@@ -513,22 +505,27 @@ int tick_remove_task(void (*f)(void))
513void mutex_init(struct mutex *m) 505void mutex_init(struct mutex *m)
514{ 506{
515 m->locked = false; 507 m->locked = false;
508 m->thread = NULL;
516} 509}
517 510
518void mutex_lock(struct mutex *m) 511void mutex_lock(struct mutex *m)
519{ 512{
520 /* Wait until the lock is open... */ 513 if (m->locked)
521 while(m->locked) 514 {
522 sleep_thread(); 515 /* Wait until the lock is open... */
523 wake_up_thread(); 516 block_thread(&m->thread, 0);
524 517 }
518
525 /* ...and lock it */ 519 /* ...and lock it */
526 m->locked = true; 520 m->locked = true;
527} 521}
528 522
529void mutex_unlock(struct mutex *m) 523void mutex_unlock(struct mutex *m)
530{ 524{
531 m->locked = false; 525 if (m->thread == NULL)
526 m->locked = false;
527 else
528 wakeup_thread(&m->thread);
532} 529}
533 530
534#endif 531#endif
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index df0cbbad12..61b0a22d87 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -761,7 +761,6 @@ void rec_tick(void)
761 { 761 {
762 prerecord_timeout = current_tick + HZ; 762 prerecord_timeout = current_tick + HZ;
763 queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0); 763 queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0);
764 wake_up_thread();
765 } 764 }
766 } 765 }
767 else 766 else
@@ -773,7 +772,6 @@ void rec_tick(void)
773 { 772 {
774 saving_status = BUFFER_FULL; 773 saving_status = BUFFER_FULL;
775 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); 774 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
776 wake_up_thread();
777 } 775 }
778 } 776 }
779 } 777 }
@@ -894,8 +892,6 @@ static void transfer_end(unsigned char** ppbuf, int* psize)
894 *psize = 0; /* no more transfer */ 892 *psize = 0; /* no more transfer */
895 } 893 }
896 } 894 }
897
898 wake_up_thread();
899} 895}
900 896
901static struct trackdata *add_track_to_tag_list(const char *filename) 897static struct trackdata *add_track_to_tag_list(const char *filename)
@@ -2119,8 +2115,7 @@ void audio_init_playback(void)
2119 queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL); 2115 queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL);
2120 2116
2121 while(!init_playback_done) 2117 while(!init_playback_done)
2122 sleep_thread(); 2118 sleep_thread(1);
2123 wake_up_thread();
2124} 2119}
2125 2120
2126 2121
@@ -2134,8 +2129,7 @@ void audio_init_recording(unsigned int buffer_offset)
2134 queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL); 2129 queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
2135 2130
2136 while(!init_recording_done) 2131 while(!init_recording_done)
2137 sleep_thread(); 2132 sleep_thread(1);
2138 wake_up_thread();
2139} 2133}
2140 2134
2141static void init_recording(void) 2135static void init_recording(void)
@@ -2886,10 +2880,10 @@ void audio_init(void)
2886 2880
2887#ifndef SIMULATOR 2881#ifndef SIMULATOR
2888 audiobuflen = audiobufend - audiobuf; 2882 audiobuflen = audiobufend - audiobuf;
2889 queue_init(&mpeg_queue); 2883 queue_init(&mpeg_queue, true);
2890#endif /* !SIMULATOR */ 2884#endif /* !SIMULATOR */
2891 create_thread(mpeg_thread, mpeg_stack, 2885 create_thread(mpeg_thread, mpeg_stack,
2892 sizeof(mpeg_stack), mpeg_thread_name); 2886 sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM));
2893 2887
2894 memset(trackdata, sizeof(trackdata), 0); 2888 memset(trackdata, sizeof(trackdata), 0);
2895 2889
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c
index 68fc22b937..bce6fb5f25 100644
--- a/firmware/pcm_record.c
+++ b/firmware/pcm_record.c
@@ -172,9 +172,9 @@ static void close_wave(void);
172/* Creates pcmrec_thread */ 172/* Creates pcmrec_thread */
173void pcm_rec_init(void) 173void pcm_rec_init(void)
174{ 174{
175 queue_init(&pcmrec_queue); 175 queue_init(&pcmrec_queue, true);
176 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), 176 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack),
177 pcmrec_thread_name); 177 pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING));
178} 178}
179 179
180 180
@@ -196,8 +196,7 @@ void audio_init_recording(unsigned int buffer_offset)
196 queue_post(&pcmrec_queue, PCMREC_INIT, 0); 196 queue_post(&pcmrec_queue, PCMREC_INIT, 0);
197 197
198 while(!init_done) 198 while(!init_done)
199 sleep_thread(); 199 sleep_thread(1);
200 wake_up_thread();
201} 200}
202 201
203void audio_close_recording(void) 202void audio_close_recording(void)
@@ -206,8 +205,7 @@ void audio_close_recording(void)
206 queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); 205 queue_post(&pcmrec_queue, PCMREC_CLOSE, 0);
207 206
208 while(!close_done) 207 while(!close_done)
209 sleep_thread(); 208 sleep_thread(1);
210 wake_up_thread();
211 209
212 audio_remove_encoder(); 210 audio_remove_encoder();
213} 211}
@@ -421,8 +419,7 @@ void audio_record(const char *filename)
421 queue_post(&pcmrec_queue, PCMREC_START, 0); 419 queue_post(&pcmrec_queue, PCMREC_START, 0);
422 420
423 while(!record_done) 421 while(!record_done)
424 sleep_thread(); 422 sleep_thread(1);
425 wake_up_thread();
426} 423}
427 424
428 425
@@ -438,8 +435,7 @@ void audio_new_file(const char *filename)
438 queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0); 435 queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0);
439 436
440 while(!new_file_done) 437 while(!new_file_done)
441 sleep_thread(); 438 sleep_thread(1);
442 wake_up_thread();
443 439
444 logf("pcm_new_file done"); 440 logf("pcm_new_file done");
445} 441}
@@ -459,8 +455,7 @@ void audio_stop_recording(void)
459 queue_post(&pcmrec_queue, PCMREC_STOP, 0); 455 queue_post(&pcmrec_queue, PCMREC_STOP, 0);
460 456
461 while(!stop_done) 457 while(!stop_done)
462 sleep_thread(); 458 sleep_thread(1);
463 wake_up_thread();
464 459
465 logf("pcm_stop done"); 460 logf("pcm_stop done");
466} 461}
@@ -482,8 +477,7 @@ void audio_pause_recording(void)
482 queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); 477 queue_post(&pcmrec_queue, PCMREC_PAUSE, 0);
483 478
484 while(!pause_done) 479 while(!pause_done)
485 sleep_thread(); 480 sleep_thread(1);
486 wake_up_thread();
487} 481}
488 482
489void audio_resume_recording(void) 483void audio_resume_recording(void)
@@ -498,8 +492,7 @@ void audio_resume_recording(void)
498 queue_post(&pcmrec_queue, PCMREC_RESUME, 0); 492 queue_post(&pcmrec_queue, PCMREC_RESUME, 0);
499 493
500 while(!resume_done) 494 while(!resume_done)
501 sleep_thread(); 495 sleep_thread(1);
502 wake_up_thread();
503} 496}
504 497
505/* return peaks as int, so convert from short first 498/* return peaks as int, so convert from short first
@@ -817,9 +810,8 @@ static void pcmrec_stop(void)
817 /* wait for encoding finish */ 810 /* wait for encoding finish */
818 is_paused = true; 811 is_paused = true;
819 while(!wav_queue_empty) 812 while(!wav_queue_empty)
820 sleep_thread(); 813 sleep_thread(1);
821 814
822 wake_up_thread();
823 is_recording = false; 815 is_recording = false;
824 816
825 /* Flush buffers to file */ 817 /* Flush buffers to file */
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index 8f832964b5..f1e1aac57f 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -998,7 +998,7 @@ void powermgmt_init(void)
998 memset(power_history, 0x00, sizeof(power_history)); 998 memset(power_history, 0x00, sizeof(power_history));
999 999
1000 create_thread(power_thread, power_stack, sizeof(power_stack), 1000 create_thread(power_thread, power_stack, sizeof(power_stack),
1001 power_thread_name); 1001 power_thread_name IF_PRIO(, PRIORITY_SYSTEM));
1002} 1002}
1003 1003
1004#endif /* SIMULATOR */ 1004#endif /* SIMULATOR */
diff --git a/firmware/thread.c b/firmware/thread.c
index eb39c7ad32..e4dcbbcf9a 100644
--- a/firmware/thread.c
+++ b/firmware/thread.c
@@ -23,12 +23,18 @@
23#include "system.h" 23#include "system.h"
24#include "kernel.h" 24#include "kernel.h"
25#include "cpu.h" 25#include "cpu.h"
26 26#include "string.h"
27 27
28#define DEADBEEF ((unsigned int)0xdeadbeef) 28#define DEADBEEF ((unsigned int)0xdeadbeef)
29/* Cast to the the machine int type, whose size could be < 4. */ 29/* Cast to the the machine int type, whose size could be < 4. */
30 30
31struct core_entry cores[NUM_CORES] IBSS_ATTR; 31struct core_entry cores[NUM_CORES] IBSS_ATTR;
32#ifdef HAVE_PRIORITY_SCHEDULING
33static unsigned short highest_priority IBSS_ATTR;
34#endif
35
36/* Define to enable additional checks for blocking violations etc. */
37// #define THREAD_EXTRA_CHECKS
32 38
33static const char main_thread_name[] = "main"; 39static const char main_thread_name[] = "main";
34 40
@@ -48,7 +54,16 @@ int *cop_stackend = stackend;
48#endif 54#endif
49#endif 55#endif
50 56
51void switch_thread(void) ICODE_ATTR; 57/* Conserve IRAM
58static void add_to_list(struct thread_entry **list,
59 struct thread_entry *thread) ICODE_ATTR;
60static void remove_from_list(struct thread_entry **list,
61 struct thread_entry *thread) ICODE_ATTR;
62*/
63
64void switch_thread(bool save_context, struct thread_entry **blocked_list)
65 ICODE_ATTR;
66
52static inline void store_context(void* addr) __attribute__ ((always_inline)); 67static inline void store_context(void* addr) __attribute__ ((always_inline));
53static inline void load_context(const void* addr) __attribute__ ((always_inline)); 68static inline void load_context(const void* addr) __attribute__ ((always_inline));
54 69
@@ -219,24 +234,109 @@ static inline void load_context(const void* addr)
219 234
220#endif 235#endif
221 236
222/*--------------------------------------------------------------------------- 237static void add_to_list(struct thread_entry **list,
223 * Switch thread in round robin fashion. 238 struct thread_entry *thread)
224 *---------------------------------------------------------------------------
225 */
226void switch_thread(void)
227{ 239{
228#ifdef RB_PROFILE 240 if (*list == NULL)
229 profile_thread_stopped(cores[CURRENT_CORE].current_thread); 241 {
230#endif 242 thread->next = thread;
231 int current; 243 thread->prev = thread;
232 unsigned int *stackptr; 244 *list = thread;
245 }
246 else
247 {
248 /* Insert last */
249 thread->next = *list;
250 thread->prev = (*list)->prev;
251 thread->prev->next = thread;
252 (*list)->prev = thread;
253
254 /* Insert next
255 thread->next = (*list)->next;
256 thread->prev = *list;
257 thread->next->prev = thread;
258 (*list)->next = thread;
259 */
260 }
261}
233 262
234#ifdef SIMULATOR 263static void remove_from_list(struct thread_entry **list,
235 /* Do nothing */ 264 struct thread_entry *thread)
236#else 265{
237 while (cores[CURRENT_CORE].num_sleepers == cores[CURRENT_CORE].num_threads) 266 if (list != NULL)
267 {
268 if (thread == thread->next)
269 {
270 *list = NULL;
271 return;
272 }
273
274 if (thread == *list)
275 *list = thread->next;
276 }
277
278 /* Fix links to jump over the removed entry. */
279 thread->prev->next = thread->next;
280 thread->next->prev = thread->prev;
281}
282
283/* Compiler trick: Don't declare as static to prevent putting
284 * function in IRAM. */
285void check_sleepers(void)
286{
287 struct thread_entry *current, *next;
288
289 /* Check sleeping threads. */
290 current = cores[CURRENT_CORE].sleeping;
291 if (current == NULL)
292 return ;
293
294 for (;;)
295 {
296 next = current->next;
297
298 if ((unsigned)current_tick >= GET_STATE_ARG(current->statearg))
299 {
300 /* Sleep timeout has been reached so bring the thread
301 * back to life again. */
302 remove_from_list(&cores[CURRENT_CORE].sleeping, current);
303 add_to_list(&cores[CURRENT_CORE].running, current);
304
305 /* If there is no more processes in the list, break the loop. */
306 if (cores[CURRENT_CORE].sleeping == NULL)
307 break;
308
309 current = next;
310 continue;
311 }
312
313 current = next;
314
315 /* Break the loop once we have walked through the list of all
316 * sleeping processes. */
317 if (current == cores[CURRENT_CORE].sleeping)
318 break;
319 }
320}
321
322static inline void sleep_core(void)
323{
324 static long last_tick = 0;
325
326 for (;;)
238 { 327 {
239 /* Enter sleep mode, woken up on interrupt */ 328 if (last_tick != current_tick)
329 {
330 check_sleepers();
331 last_tick = current_tick;
332 }
333
334 /* We must sleep until there is at least one process in the list
335 * of running processes. */
336 if (cores[CURRENT_CORE].running != NULL)
337 break;
338
339 /* Enter sleep mode to reduce power usage, woken up on interrupt */
240#ifdef CPU_COLDFIRE 340#ifdef CPU_COLDFIRE
241 asm volatile ("stop #0x2000"); 341 asm volatile ("stop #0x2000");
242#elif CONFIG_CPU == SH7034 342#elif CONFIG_CPU == SH7034
@@ -257,49 +357,232 @@ void switch_thread(void)
257 CLKCON |= 2; 357 CLKCON |= 2;
258#endif 358#endif
259 } 359 }
260#endif 360}
261 current = cores[CURRENT_CORE].current_thread; 361
262 store_context(&cores[CURRENT_CORE].threads[current].context); 362#ifdef RB_PROFILE
263 363static int get_threadnum(struct thread_entry *thread)
264#if CONFIG_CPU != TCC730 364{
265 /* Check if the current thread stack is overflown */ 365 int i;
266 stackptr = cores[CURRENT_CORE].threads[current].stack; 366
267 if(stackptr[0] != DEADBEEF) 367 for (i = 0; i < MAXTHREADS; i++)
268 panicf("Stkov %s", cores[CURRENT_CORE].threads[current].name); 368 {
369 if (&cores[CURRENT_CORE].threads[i] == thread)
370 return i;
371 }
372
373 return -1;
374}
269#endif 375#endif
270 376
271 if (++current >= cores[CURRENT_CORE].num_threads) 377/* Compiler trick: Don't declare as static to prevent putting
272 current = 0; 378 * function in IRAM. */
379void change_thread_state(struct thread_entry **blocked_list)
380{
381 struct thread_entry *old;
382
383 /* Remove the thread from the list of running threads. */
384 old = cores[CURRENT_CORE].running;
385 remove_from_list(&cores[CURRENT_CORE].running, old);
386
387 /* And put the thread into a new list of inactive threads. */
388 if (GET_STATE(old->statearg) == STATE_BLOCKED)
389 add_to_list(blocked_list, old);
390 else
391 add_to_list(&cores[CURRENT_CORE].sleeping, old);
392
393#ifdef HAVE_PRIORITY_SCHEDULING
394 /* Reset priorities */
395 if (old->priority == highest_priority)
396 highest_priority = 100;
397#endif
398}
273 399
274 cores[CURRENT_CORE].current_thread = current; 400/*---------------------------------------------------------------------------
275 load_context(&cores[CURRENT_CORE].threads[current].context); 401 * Switch thread in round robin fashion.
402 *---------------------------------------------------------------------------
403 */
404void switch_thread(bool save_context, struct thread_entry **blocked_list)
405{
276#ifdef RB_PROFILE 406#ifdef RB_PROFILE
277 profile_thread_started(cores[CURRENT_CORE].current_thread); 407 profile_thread_stopped(get_threadnum(cores[CURRENT_CORE].running));
408#endif
409 unsigned int *stackptr;
410
411#ifdef SIMULATOR
412 /* Do nothing */
413#else
414
415 /* Begin task switching by saving our current context so that we can
416 * restore the state of the current thread later to the point prior
417 * to this call. */
418 if (save_context)
419 {
420 store_context(&cores[CURRENT_CORE].running->context);
421
422# if CONFIG_CPU != TCC730
423 /* Check if the current thread stack is overflown */
424 stackptr = cores[CURRENT_CORE].running->stack;
425 if(stackptr[0] != DEADBEEF)
426 panicf("Stkov %s", cores[CURRENT_CORE].running->name);
427# endif
428
429 /* Check if a thread state change has been requested. */
430 if (cores[CURRENT_CORE].running->statearg)
431 {
432 /* Change running thread state and switch to next thread. */
433 change_thread_state(blocked_list);
434 }
435 else
436 {
437 /* Switch to the next running thread. */
438 cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next;
439 }
440 }
441
442 /* Go through the list of sleeping task to check if we need to wake up
443 * any of them due to timeout. Also puts core into sleep state until
444 * there is at least one running process again. */
445 sleep_core();
446
447#ifdef HAVE_PRIORITY_SCHEDULING
448 /* Select the new task based on priorities and the last time a process
449 * got CPU time. */
450 for (;;)
451 {
452 int priority = cores[CURRENT_CORE].running->priority;
453
454 if (priority < highest_priority)
455 highest_priority = priority;
456
457 if (priority == highest_priority || (current_tick
458 - cores[CURRENT_CORE].running->last_run > priority * 8))
459 {
460 break;
461 }
462 cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next;
463 }
464
465 /* Reset the value of thread's last running time to the current time. */
466 cores[CURRENT_CORE].running->last_run = current_tick;
467#endif
468
469#endif
470 /* And finally give control to the next thread. */
471 load_context(&cores[CURRENT_CORE].running->context);
472
473#ifdef RB_PROFILE
474 profile_thread_started(get_threadnum(cores[CURRENT_CORE].running));
278#endif 475#endif
279} 476}
280 477
281void sleep_thread(void) 478void sleep_thread(int ticks)
282{ 479{
283 ++cores[CURRENT_CORE].num_sleepers; 480 /* Set the thread's new state and timeout and finally force a task switch
284 switch_thread(); 481 * so that scheduler removes thread from the list of running processes
482 * and puts it in list of sleeping tasks. */
483 cores[CURRENT_CORE].running->statearg =
484 SET_STATE(STATE_SLEEPING, current_tick + ticks + 1);
485 switch_thread(true, NULL);
486
487 /* Clear all flags to indicate we are up and running again. */
488 cores[CURRENT_CORE].running->statearg = 0;
285} 489}
286 490
287void wake_up_thread(void) 491void block_thread(struct thread_entry **list, int timeout)
288{ 492{
289 cores[CURRENT_CORE].num_sleepers = 0; 493 struct thread_entry *current;
494
495 /* Get the entry for the current running thread. */
496 current = cores[CURRENT_CORE].running;
497
498 /* At next task switch scheduler will immediately change the thread
499 * state (and we also force the task switch to happen). */
500 if (timeout)
501 {
502#ifdef THREAD_EXTRA_CHECKS
503 /* We can store only one thread to the "list" if thread is used
504 * in other list (such as core's list for sleeping tasks). */
505 if (*list)
506 panicf("Blocking violation T->*B");
507#endif
508
509 current->statearg =
510 SET_STATE(STATE_BLOCKED_W_TMO, current_tick + timeout);
511 *list = current;
512
513 /* Now force a task switch and block until we have been woken up
514 * by another thread or timeout is reached. */
515 switch_thread(true, NULL);
516
517 /* If timeout is reached, we must set list back to NULL here. */
518 *list = NULL;
519 }
520 else
521 {
522#ifdef THREAD_EXTRA_CHECKS
523 /* We are not allowed to mix blocking types in one queue. */
524 if (*list && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO)
525 panicf("Blocking violation B->*T");
526#endif
527
528 current->statearg = SET_STATE(STATE_BLOCKED, 0);
529
530 /* Now force a task switch and block until we have been woken up
531 * by another thread or timeout is reached. */
532 switch_thread(true, list);
533 }
534
535 /* Clear all flags to indicate we are up and running again. */
536 current->statearg = 0;
290} 537}
291 538
539void wakeup_thread(struct thread_entry **list)
540{
541 struct thread_entry *thread;
542
543 /* Check if there is a blocked thread at all. */
544 if (*list == NULL)
545 return ;
546
547 /* Wake up the last thread first. */
548 thread = *list;
549
550 /* Determine thread's current state. */
551 switch (GET_STATE(thread->statearg))
552 {
553 case STATE_BLOCKED:
554 /* Remove thread from the list of blocked threads and add it
555 * to the scheduler's list of running processes. */
556 remove_from_list(list, thread);
557 add_to_list(&cores[CURRENT_CORE].running, thread);
558 thread->statearg = 0;
559 break;
560
561 case STATE_BLOCKED_W_TMO:
562 /* Just remove the timeout to cause scheduler to immediately
563 * wake up the thread. */
564 thread->statearg &= 0xC0000000;
565 *list = NULL;
566 break;
567
568 default:
569 /* Nothing to do. Thread has already been woken up
570 * or it's state is not blocked or blocked with timeout. */
571 return ;
572 }
573}
292 574
293/*--------------------------------------------------------------------------- 575/*---------------------------------------------------------------------------
294 * Create thread on the current core. 576 * Create thread on the current core.
295 * Return ID if context area could be allocated, else -1. 577 * Return ID if context area could be allocated, else -1.
296 *--------------------------------------------------------------------------- 578 *---------------------------------------------------------------------------
297 */ 579 */
298int create_thread(void (*function)(void), void* stack, int stack_size, 580struct thread_entry*
299 const char *name) 581 create_thread(void (*function)(void), void* stack, int stack_size,
582 const char *name IF_PRIO(, int priority))
300{ 583{
301 return create_thread_on_core(CURRENT_CORE, function, stack, stack_size, 584 return create_thread_on_core(CURRENT_CORE, function, stack, stack_size,
302 name); 585 name IF_PRIO(, priority));
303} 586}
304 587
305/*--------------------------------------------------------------------------- 588/*---------------------------------------------------------------------------
@@ -307,18 +590,28 @@ int create_thread(void (*function)(void), void* stack, int stack_size,
307 * Return ID if context area could be allocated, else -1. 590 * Return ID if context area could be allocated, else -1.
308 *--------------------------------------------------------------------------- 591 *---------------------------------------------------------------------------
309 */ 592 */
310int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, 593struct thread_entry*
311 const char *name) 594 create_thread_on_core(unsigned int core, void (*function)(void),
595 void* stack, int stack_size,
596 const char *name IF_PRIO(, int priority))
312{ 597{
313 unsigned int i; 598 unsigned int i;
314 unsigned int stacklen; 599 unsigned int stacklen;
315 unsigned int *stackptr; 600 unsigned int *stackptr;
601 int n;
316 struct regs *regs; 602 struct regs *regs;
317 struct thread_entry *thread; 603 struct thread_entry *thread;
318 604
319 if (cores[core].num_threads >= MAXTHREADS) 605 for (n = 0; n < MAXTHREADS; n++)
320 return -1; 606 {
321 607 if (cores[core].threads[n].name == NULL)
608 break;
609 }
610
611 if (n == MAXTHREADS)
612 return NULL;
613
614
322 /* Munge the stack to make it easy to spot stack overflows */ 615 /* Munge the stack to make it easy to spot stack overflows */
323 stacklen = stack_size / sizeof(int); 616 stacklen = stack_size / sizeof(int);
324 stackptr = stack; 617 stackptr = stack;
@@ -328,10 +621,17 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack
328 } 621 }
329 622
330 /* Store interesting information */ 623 /* Store interesting information */
331 thread = &cores[core].threads[cores[core].num_threads]; 624 thread = &cores[core].threads[n];
332 thread->name = name; 625 thread->name = name;
333 thread->stack = stack; 626 thread->stack = stack;
334 thread->stack_size = stack_size; 627 thread->stack_size = stack_size;
628 thread->statearg = 0;
629#ifdef HAVE_PRIORITY_SCHEDULING
630 thread->priority = priority;
631 highest_priority = 100;
632#endif
633 add_to_list(&cores[core].running, thread);
634
335 regs = &thread->context; 635 regs = &thread->context;
336#if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM) 636#if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM)
337 /* Align stack to an even 32 bit boundary */ 637 /* Align stack to an even 32 bit boundary */
@@ -343,8 +643,7 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack
343#endif 643#endif
344 regs->start = (void*)function; 644 regs->start = (void*)function;
345 645
346 wake_up_thread(); 646 return thread;
347 return cores[core].num_threads++; /* return the current ID, e.g for remove_thread() */
348} 647}
349 648
350/*--------------------------------------------------------------------------- 649/*---------------------------------------------------------------------------
@@ -352,44 +651,58 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack
352 * Parameter is the ID as returned from create_thread(). 651 * Parameter is the ID as returned from create_thread().
353 *--------------------------------------------------------------------------- 652 *---------------------------------------------------------------------------
354 */ 653 */
355void remove_thread(int threadnum) 654void remove_thread(struct thread_entry *thread)
356{ 655{
357 remove_thread_on_core(CURRENT_CORE, threadnum); 656 if (thread == NULL)
657 thread = cores[CURRENT_CORE].running;
658
659 /* Free the entry by removing thread name. */
660 thread->name = NULL;
661#ifdef HAVE_PRIORITY_SCHEDULING
662 highest_priority = 100;
663#endif
664
665 if (thread == cores[CURRENT_CORE].running)
666 {
667 remove_from_list(&cores[CURRENT_CORE].running, thread);
668 switch_thread(false, NULL);
669 return ;
670 }
671
672 if (thread == cores[CURRENT_CORE].sleeping)
673 remove_from_list(&cores[CURRENT_CORE].sleeping, thread);
674
675 remove_from_list(NULL, thread);
358} 676}
359 677
360/*--------------------------------------------------------------------------- 678#ifdef HAVE_PRIORITY_SCHEDULING
361 * Remove a thread on the specified core from the scheduler. 679void thread_set_priority(struct thread_entry *thread, int priority)
362 * Parameters are the core and the ID as returned from create_thread().
363 *---------------------------------------------------------------------------
364 */
365void remove_thread_on_core(unsigned int core, int threadnum)
366{ 680{
367 int i; 681 if (thread == NULL)
368 682 thread = cores[CURRENT_CORE].running;
369 if (threadnum >= cores[core].num_threads) 683
370 return; 684 thread->priority = priority;
371 685 highest_priority = 100;
372 cores[core].num_threads--;
373 for (i=threadnum; i<cores[core].num_threads-1; i++)
374 { /* move all entries which are behind */
375 cores[core].threads[i] = cores[core].threads[i+1];
376 }
377
378 if (cores[core].current_thread == threadnum) /* deleting the current one? */
379 cores[core].current_thread = cores[core].num_threads; /* set beyond last, avoid store harm */
380 else if (cores[core].current_thread > threadnum) /* within the moved positions? */
381 cores[core].current_thread--; /* adjust it, point to same context again */
382} 686}
687#endif
383 688
384void init_threads(void) 689void init_threads(void)
385{ 690{
386 unsigned int core = CURRENT_CORE; 691 unsigned int core = CURRENT_CORE;
387 692
388 cores[core].num_threads = 1; /* We have 1 thread to begin with */ 693 memset(cores, 0, sizeof cores);
389 cores[core].current_thread = 0; /* The current thread is number 0 */ 694 cores[core].sleeping = NULL;
695 cores[core].running = NULL;
390 cores[core].threads[0].name = main_thread_name; 696 cores[core].threads[0].name = main_thread_name;
391/* In multiple core setups, each core has a different stack. There is probably 697 cores[core].threads[0].statearg = 0;
392 a much better way to do this. */ 698#ifdef HAVE_PRIORITY_SCHEDULING
699 cores[core].threads[0].priority = PRIORITY_USER_INTERFACE;
700 highest_priority = 100;
701#endif
702 add_to_list(&cores[core].running, &cores[core].threads[0]);
703
704 /* In multiple core setups, each core has a different stack. There is probably
705 a much better way to do this. */
393 if (core == CPU) 706 if (core == CPU)
394 { 707 {
395 cores[CPU].threads[0].stack = stackbegin; 708 cores[CPU].threads[0].stack = stackbegin;
@@ -405,28 +718,24 @@ void init_threads(void)
405#else 718#else
406 cores[core].threads[0].context.start = 0; /* thread 0 already running */ 719 cores[core].threads[0].context.start = 0; /* thread 0 already running */
407#endif 720#endif
408 cores[core].num_sleepers = 0;
409}
410
411int thread_stack_usage(int threadnum)
412{
413 return thread_stack_usage_on_core(CURRENT_CORE, threadnum);
414} 721}
415 722
416int thread_stack_usage_on_core(unsigned int core, int threadnum) 723int thread_stack_usage(const struct thread_entry *thread)
417{ 724{
418 unsigned int i; 725 unsigned int i;
419 unsigned int *stackptr = cores[core].threads[threadnum].stack; 726 unsigned int *stackptr = thread->stack;
420
421 if (threadnum >= cores[core].num_threads)
422 return -1;
423 727
424 for (i = 0;i < cores[core].threads[threadnum].stack_size/sizeof(int);i++) 728 for (i = 0;i < thread->stack_size/sizeof(int);i++)
425 { 729 {
426 if (stackptr[i] != DEADBEEF) 730 if (stackptr[i] != DEADBEEF)
427 break; 731 break;
428 } 732 }
429 733
430 return ((cores[core].threads[threadnum].stack_size - i * sizeof(int)) * 100) / 734 return ((thread->stack_size - i * sizeof(int)) * 100) /
431 cores[core].threads[threadnum].stack_size; 735 thread->stack_size;
736}
737
738int thread_get_status(const struct thread_entry *thread)
739{
740 return GET_STATE(thread->statearg);
432} 741}
diff --git a/firmware/usb.c b/firmware/usb.c
index 6be5fda093..0be6c4011e 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -558,8 +558,9 @@ void usb_init(void)
558 last_usb_status = false; 558 last_usb_status = false;
559 559
560#ifndef BOOTLOADER 560#ifndef BOOTLOADER
561 queue_init(&usb_queue); 561 queue_init(&usb_queue, true);
562 create_thread(usb_thread, usb_stack, sizeof(usb_stack), usb_thread_name); 562 create_thread(usb_thread, usb_stack, sizeof(usb_stack),
563 usb_thread_name IF_PRIO(, PRIORITY_SYSTEM));
563 564
564 tick_add_task(usb_tick); 565 tick_add_task(usb_tick);
565#endif 566#endif