diff options
29 files changed, 4585 insertions, 72 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index adc3041119..2503fa500a 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -11156,3 +11156,73 @@ | |||
11156 | recording: "" | 11156 | recording: "" |
11157 | </voice> | 11157 | </voice> |
11158 | </phrase> | 11158 | </phrase> |
11159 | <phrase> | ||
11160 | id: LANG_USBSTACK | ||
11161 | desc: in settings_menu | ||
11162 | user: | ||
11163 | <source> | ||
11164 | *: "USB Stack" | ||
11165 | </source> | ||
11166 | <dest> | ||
11167 | *: "USB Stack" | ||
11168 | </dest> | ||
11169 | <voice> | ||
11170 | *: "USB Stack" | ||
11171 | </voice> | ||
11172 | </phrase> | ||
11173 | <phrase> | ||
11174 | id: LANG_USBSTACK_MODE | ||
11175 | desc: in usbstack settings | ||
11176 | user: | ||
11177 | <source> | ||
11178 | *: "USB Stack Mode" | ||
11179 | </source> | ||
11180 | <dest> | ||
11181 | *: "USB Stack Mode" | ||
11182 | </dest> | ||
11183 | <voice> | ||
11184 | *: "USB Stack Mode" | ||
11185 | </voice> | ||
11186 | </phrase> | ||
11187 | <phrase> | ||
11188 | id: LANG_USBSTACK_DEVICE | ||
11189 | desc: in usbstack settings | ||
11190 | user: | ||
11191 | <source> | ||
11192 | *: "Device" | ||
11193 | </source> | ||
11194 | <dest> | ||
11195 | *: "Device" | ||
11196 | </dest> | ||
11197 | <voice> | ||
11198 | *: "Device" | ||
11199 | </voice> | ||
11200 | </phrase> | ||
11201 | <phrase> | ||
11202 | id: LANG_USBSTACK_HOST | ||
11203 | desc: in usbstack settings | ||
11204 | user: | ||
11205 | <source> | ||
11206 | *: "Host" | ||
11207 | </source> | ||
11208 | <dest> | ||
11209 | *: "Host" | ||
11210 | </dest> | ||
11211 | <voice> | ||
11212 | *: "Host" | ||
11213 | </voice> | ||
11214 | </phrase> | ||
11215 | <phrase> | ||
11216 | id: LANG_USBSTACK_DEVICE_DRIVER | ||
11217 | desc: in usbstack settings | ||
11218 | user: | ||
11219 | <source> | ||
11220 | *: "Device Driver" | ||
11221 | </source> | ||
11222 | <dest> | ||
11223 | *: "Device Driver" | ||
11224 | </dest> | ||
11225 | <voice> | ||
11226 | *: "Device Driver" | ||
11227 | </voice> | ||
11228 | </phrase> \ No newline at end of file | ||
diff --git a/apps/main.c b/apps/main.c index df250843e5..54787d6e9e 100644 --- a/apps/main.c +++ b/apps/main.c | |||
@@ -99,6 +99,10 @@ | |||
99 | #include "lcd-remote.h" | 99 | #include "lcd-remote.h" |
100 | #endif | 100 | #endif |
101 | 101 | ||
102 | #ifdef HAVE_USBSTACK | ||
103 | #include "usbstack.h" | ||
104 | #endif | ||
105 | |||
102 | #if CONFIG_USBOTG == USBOTG_ISP1362 | 106 | #if CONFIG_USBOTG == USBOTG_ISP1362 |
103 | #include "isp1362.h" | 107 | #include "isp1362.h" |
104 | #endif | 108 | #endif |
@@ -373,7 +377,10 @@ static void init(void) | |||
373 | #endif | 377 | #endif |
374 | 378 | ||
375 | adc_init(); | 379 | adc_init(); |
376 | 380 | ||
381 | #ifdef HAVE_USBSTACK | ||
382 | usb_stack_init(); | ||
383 | #endif | ||
377 | usb_init(); | 384 | usb_init(); |
378 | #if CONFIG_USBOTG == USBOTG_ISP1362 | 385 | #if CONFIG_USBOTG == USBOTG_ISP1362 |
379 | isp1362_init(); | 386 | isp1362_init(); |
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index 039949835b..5c97ac21db 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c | |||
@@ -42,6 +42,13 @@ | |||
42 | #include "radio.h" | 42 | #include "radio.h" |
43 | #endif | 43 | #endif |
44 | 44 | ||
45 | #ifdef HAVE_USBSTACK | ||
46 | #include "list.h" | ||
47 | #include "usbstack.h" | ||
48 | #include "statusbar.h" | ||
49 | #include "misc.h" | ||
50 | #endif | ||
51 | |||
45 | /***********************************/ | 52 | /***********************************/ |
46 | /* TAGCACHE MENU */ | 53 | /* TAGCACHE MENU */ |
47 | #ifdef HAVE_TAGCACHE | 54 | #ifdef HAVE_TAGCACHE |
@@ -442,6 +449,82 @@ MAKE_MENU(voice_settings_menu, ID2P(LANG_VOICE), 0, Icon_Voice, | |||
442 | /* VOICE MENU */ | 449 | /* VOICE MENU */ |
443 | /***********************************/ | 450 | /***********************************/ |
444 | 451 | ||
452 | #ifdef HAVE_USBSTACK | ||
453 | /***********************************/ | ||
454 | /* USB STACK MENU */ | ||
455 | char drivers[16][32]; | ||
456 | static char* usb_menu_getname(int item, void * data, char *buffer) | ||
457 | { | ||
458 | (void)data; (void)buffer; | ||
459 | return drivers[item]; | ||
460 | } | ||
461 | int usbdriver_menuitem(void) | ||
462 | { | ||
463 | struct gui_synclist lists; | ||
464 | int action, count = 0; | ||
465 | char *s = device_driver_names, *e; | ||
466 | do { | ||
467 | e = strchr(s, ','); | ||
468 | if (e) | ||
469 | { | ||
470 | strncpy(drivers[count++], s, e-s); | ||
471 | s = e+1; | ||
472 | } | ||
473 | } while (e && count < 16); | ||
474 | if (count < 16) | ||
475 | strcpy(drivers[count++], s); | ||
476 | for (action=0; action<count; action++) | ||
477 | { | ||
478 | if (!strcmp(drivers[action], | ||
479 | global_settings.usb_stack_device_driver)) | ||
480 | break; | ||
481 | } | ||
482 | |||
483 | gui_synclist_init(&lists, usb_menu_getname, drivers, false, 1); | ||
484 | gui_synclist_set_title(&lists, str(LANG_USBSTACK_DEVICE_DRIVER), NOICON); | ||
485 | gui_synclist_set_icon_callback(&lists, NULL); | ||
486 | gui_synclist_set_nb_items(&lists, count); | ||
487 | gui_synclist_select_item(&lists, action==count?0:action); | ||
488 | gui_synclist_draw(&lists); | ||
489 | |||
490 | while(1) | ||
491 | { | ||
492 | gui_syncstatusbar_draw(&statusbars, true); | ||
493 | action = get_action(CONTEXT_STD, HZ/5); | ||
494 | if (gui_synclist_do_button(&lists, action, LIST_WRAP_UNLESS_HELD)) | ||
495 | continue; | ||
496 | if (action == ACTION_STD_CANCEL) | ||
497 | { | ||
498 | // setting was canceled | ||
499 | break; | ||
500 | } | ||
501 | else if (action == ACTION_STD_OK) | ||
502 | { | ||
503 | // setting was accepted... save | ||
504 | strcpy(global_settings.usb_stack_device_driver, | ||
505 | drivers[gui_synclist_get_sel_pos(&lists)]); | ||
506 | break; | ||
507 | } | ||
508 | else if (action == ACTION_REDRAW) | ||
509 | gui_synclist_draw(&lists); | ||
510 | else if(default_event_handler(action) == SYS_USB_CONNECTED) | ||
511 | return true; | ||
512 | } | ||
513 | return false; | ||
514 | } | ||
515 | |||
516 | MENUITEM_SETTING(usbstack_mode, &global_settings.usb_stack_mode, NULL); | ||
517 | MENUITEM_FUNCTION(usbdriver, 0, ID2P(LANG_USBSTACK_DEVICE_DRIVER), | ||
518 | usbdriver_menuitem, 0, NULL, Icon_NOICON); | ||
519 | |||
520 | MAKE_MENU(usbstack_menu, ID2P(LANG_USBSTACK), 0, Icon_NOICON, | ||
521 | &usbstack_mode, &usbdriver); | ||
522 | /* USB STACK MENU */ | ||
523 | /***********************************/ | ||
524 | #endif | ||
525 | |||
526 | /***********************************/ | ||
527 | |||
445 | /***********************************/ | 528 | /***********************************/ |
446 | /* SETTINGS MENU */ | 529 | /* SETTINGS MENU */ |
447 | static int language_browse(void) | 530 | static int language_browse(void) |
@@ -458,6 +541,10 @@ MAKE_MENU(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS), 0, | |||
458 | &tagcache_menu, | 541 | &tagcache_menu, |
459 | #endif | 542 | #endif |
460 | &display_menu, &system_menu, | 543 | &display_menu, &system_menu, |
461 | &bookmark_settings_menu, &browse_langs, &voice_settings_menu ); | 544 | &bookmark_settings_menu, &browse_langs, &voice_settings_menu |
545 | #ifdef HAVE_USBSTACK | ||
546 | , &usbstack_menu | ||
547 | #endif | ||
548 | ); | ||
462 | /* SETTINGS MENU */ | 549 | /* SETTINGS MENU */ |
463 | /***********************************/ | 550 | /***********************************/ |
diff --git a/apps/settings.c b/apps/settings.c index cd1c252426..c7c8772975 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -98,6 +98,10 @@ struct system_status global_status; | |||
98 | #include "lcd-remote.h" | 98 | #include "lcd-remote.h" |
99 | #endif | 99 | #endif |
100 | 100 | ||
101 | #ifdef HAVE_USBSTACK | ||
102 | #include "usbstack.h" | ||
103 | #endif | ||
104 | |||
101 | long lasttime = 0; | 105 | long lasttime = 0; |
102 | 106 | ||
103 | /** NVRAM stuff, if the target doesnt have NVRAM it is saved in ROCKBOX_DIR /nvram.bin **/ | 107 | /** NVRAM stuff, if the target doesnt have NVRAM it is saved in ROCKBOX_DIR /nvram.bin **/ |
@@ -875,11 +879,13 @@ void settings_apply(void) | |||
875 | read_color_theme_file(); | 879 | read_color_theme_file(); |
876 | #endif | 880 | #endif |
877 | 881 | ||
882 | #ifdef HAVE_USBSTACK | ||
883 | usb_controller_select(global_settings.usb_stack_mode); | ||
884 | usb_device_driver_bind(global_settings.usb_stack_device_driver); | ||
885 | #endif | ||
878 | } | 886 | } |
879 | 887 | ||
880 | 888 | ||
881 | |||
882 | |||
883 | /* | 889 | /* |
884 | * reset all settings to their default value | 890 | * reset all settings to their default value |
885 | */ | 891 | */ |
diff --git a/apps/settings.h b/apps/settings.h index 987709ce72..c4cb917c1f 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -748,6 +748,10 @@ struct user_settings | |||
748 | int list_accel_start_delay; /* ms before we start increaseing step size */ | 748 | int list_accel_start_delay; /* ms before we start increaseing step size */ |
749 | int list_accel_wait; /* ms between increases */ | 749 | int list_accel_wait; /* ms between increases */ |
750 | #endif | 750 | #endif |
751 | #ifdef HAVE_USBSTACK | ||
752 | int usb_stack_mode; /* device or host */ | ||
753 | unsigned char usb_stack_device_driver[32]; /* usb device driver to load */ | ||
754 | #endif | ||
751 | }; | 755 | }; |
752 | 756 | ||
753 | /** global variables **/ | 757 | /** global variables **/ |
diff --git a/apps/settings_list.c b/apps/settings_list.c index 16c3222b5e..1218dbf3e4 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c | |||
@@ -47,6 +47,9 @@ | |||
47 | #include "radio.h" | 47 | #include "radio.h" |
48 | #endif | 48 | #endif |
49 | 49 | ||
50 | #ifdef HAVE_USBSTACK | ||
51 | #include "usbstack.h" | ||
52 | #endif | ||
50 | 53 | ||
51 | #define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT) | 54 | #define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT) |
52 | /** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h | 55 | /** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h |
@@ -1260,6 +1263,14 @@ const struct settings_list settings[] = { | |||
1260 | 3, "list_accel_wait", UNIT_SEC, 1, 10, 1, | 1263 | 3, "list_accel_wait", UNIT_SEC, 1, 10, 1, |
1261 | scanaccel_formatter, scanaccel_getlang, NULL), | 1264 | scanaccel_formatter, scanaccel_getlang, NULL), |
1262 | #endif /* HAVE_SCROLLWHEEL */ | 1265 | #endif /* HAVE_SCROLLWHEEL */ |
1266 | #ifdef HAVE_USBSTACK | ||
1267 | CHOICE_SETTING(0, usb_stack_mode, LANG_USBSTACK_MODE, 0, "usb mode", | ||
1268 | "device,host", | ||
1269 | usb_controller_select, | ||
1270 | 2, ID2P(LANG_USBSTACK_DEVICE), ID2P(LANG_USBSTACK_HOST)), | ||
1271 | FILENAME_SETTING(0, usb_stack_device_driver, "usb device driver", | ||
1272 | "storage", NULL, NULL, 32), | ||
1273 | #endif /* HAVE_USBSTACK */ | ||
1263 | }; | 1274 | }; |
1264 | 1275 | ||
1265 | const int nb_settings = sizeof(settings)/sizeof(*settings); | 1276 | const int nb_settings = sizeof(settings)/sizeof(*settings); |
diff --git a/firmware/SOURCES b/firmware/SOURCES index cd628fb683..c704bee0e7 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -101,6 +101,7 @@ drivers/dac.c | |||
101 | drivers/serial.c | 101 | drivers/serial.c |
102 | #endif /* SIMULATOR */ | 102 | #endif /* SIMULATOR */ |
103 | 103 | ||
104 | |||
104 | /* Storage */ | 105 | /* Storage */ |
105 | #ifndef SIMULATOR | 106 | #ifndef SIMULATOR |
106 | #ifdef HAVE_MMC | 107 | #ifdef HAVE_MMC |
@@ -221,6 +222,18 @@ drivers/audio/mas35xx.c | |||
221 | #endif /* defined(HAVE_*) */ | 222 | #endif /* defined(HAVE_*) */ |
222 | #endif /* SIMULATOR */ | 223 | #endif /* SIMULATOR */ |
223 | 224 | ||
225 | /* USB Stack */ | ||
226 | #if !defined(SIMULATOR) | ||
227 | #ifdef HAVE_USBSTACK | ||
228 | usbstack/core/core.c | ||
229 | usbstack/core/epsetup.c | ||
230 | usbstack/core/utils.c | ||
231 | usbstack/core/config.c | ||
232 | usbstack/drivers/device/usb_serial.c | ||
233 | usbstack/drivers/device/usb_storage.c | ||
234 | #endif | ||
235 | #endif | ||
236 | |||
224 | /* USBOTG */ | 237 | /* USBOTG */ |
225 | #if !defined(SIMULATOR) | 238 | #if !defined(SIMULATOR) |
226 | #if CONFIG_USBOTG == USBOTG_ISP1362 | 239 | #if CONFIG_USBOTG == USBOTG_ISP1362 |
@@ -230,7 +243,7 @@ drivers/isp1362.c | |||
230 | #if CONFIG_USBOTG == USBOTG_M5636 | 243 | #if CONFIG_USBOTG == USBOTG_M5636 |
231 | drivers/m5636.c | 244 | drivers/m5636.c |
232 | #elif CONFIG_USBOTG == USBOTG_ARC | 245 | #elif CONFIG_USBOTG == USBOTG_ARC |
233 | drivers/arcotg_udc.c | 246 | drivers/usb/arcotg_dcd.c |
234 | #endif /* CONFIG_USBOTG */ | 247 | #endif /* CONFIG_USBOTG */ |
235 | #endif /* !defined(BOOTLOADER) */ | 248 | #endif /* !defined(BOOTLOADER) */ |
236 | #endif /* !defined(SIMULATOR) */ | 249 | #endif /* !defined(SIMULATOR) */ |
diff --git a/firmware/drivers/usb/arcotg_dcd.c b/firmware/drivers/usb/arcotg_dcd.c new file mode 100644 index 0000000000..982fdfb9eb --- /dev/null +++ b/firmware/drivers/usb/arcotg_dcd.c | |||
@@ -0,0 +1,983 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * Based on code from the Linux Target Image Builder from Freescale | ||
13 | * available at http://www.bitshrine.org/ and | ||
14 | * http://www.bitshrine.org/gpp/linux-2.6.16-mx31-usb-2.patch | ||
15 | * Adapted for Rockbox in January 2007 | ||
16 | * Original file: drivers/usb/gadget/arcotg_udc.c | ||
17 | * | ||
18 | * USB Device Controller Driver | ||
19 | * Driver for ARC OTG USB module in the i.MX31 platform, etc. | ||
20 | * | ||
21 | * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. | ||
22 | * | ||
23 | * Based on mpc-udc.h | ||
24 | * Author: Li Yang (leoli@freescale.com) | ||
25 | * Jiang Bo (Tanya.jiang@freescale.com) | ||
26 | * | ||
27 | * All files in this archive are subject to the GNU General Public License. | ||
28 | * See the file COPYING in the source tree root for full license agreement. | ||
29 | * | ||
30 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
31 | * KIND, either express or implied. | ||
32 | * | ||
33 | ****************************************************************************/ | ||
34 | |||
35 | #include <string.h> | ||
36 | #include "arcotg_dcd.h" | ||
37 | |||
38 | /*-------------------------------------------------------------------------*/ | ||
39 | |||
40 | static struct arcotg_dcd dcd_controller; | ||
41 | struct usb_response res; | ||
42 | |||
43 | /* datastructes to controll transfers */ | ||
44 | struct dtd dev_td[USB_MAX_PIPES] IBSS_ATTR; | ||
45 | struct dqh dev_qh[USB_MAX_PIPES] __attribute((aligned (1 << 11))) IBSS_ATTR; | ||
46 | |||
47 | /* shared memory used by rockbox and dcd to exchange data */ | ||
48 | #define BUFFER_SIZE 512 | ||
49 | unsigned char buffer[BUFFER_SIZE] IBSS_ATTR; | ||
50 | |||
51 | /*-------------------------------------------------------------------------*/ | ||
52 | |||
53 | /* description of our device driver operations */ | ||
54 | struct usb_dcd_controller_ops arotg_dcd_ops = { | ||
55 | .enable = usb_arcotg_dcd_enable, | ||
56 | .disable = NULL, | ||
57 | .set_halt = usb_arcotg_dcd_set_halt, | ||
58 | .send = usb_arcotg_dcd_send, | ||
59 | .receive = usb_arcotg_dcd_receive, | ||
60 | .ep0 = &dcd_controller.endpoints[0], | ||
61 | }; | ||
62 | |||
63 | /* description of our usb controller driver */ | ||
64 | struct usb_controller arcotg_dcd = { | ||
65 | .name = "arcotg_dcd", | ||
66 | .type = DEVICE, | ||
67 | .speed = USB_SPEED_UNKNOWN, | ||
68 | .init = usb_arcotg_dcd_init, | ||
69 | .shutdown = usb_arcotg_dcd_shutdown, | ||
70 | .irq = usb_arcotg_dcd_irq, | ||
71 | .start = usb_arcotg_dcd_start, | ||
72 | .stop = usb_arcotg_dcd_stop, | ||
73 | .controller_ops = (void*)&arotg_dcd_ops, | ||
74 | }; | ||
75 | |||
76 | static struct usb_response response; | ||
77 | |||
78 | /*-------------------------------------------------------------------------*/ | ||
79 | |||
80 | /* TODO hmmm */ | ||
81 | |||
82 | struct timer { | ||
83 | unsigned long s; | ||
84 | unsigned long e; | ||
85 | }; | ||
86 | |||
87 | void | ||
88 | timer_set(struct timer * timer, unsigned long val) | ||
89 | { | ||
90 | timer->s = USEC_TIMER; | ||
91 | timer->e = timer->s + val + 1; | ||
92 | } | ||
93 | |||
94 | int | ||
95 | timer_expired(struct timer * timer) | ||
96 | { | ||
97 | unsigned long val = USEC_TIMER; | ||
98 | |||
99 | if (timer->e > timer->s) { | ||
100 | return !(val >= timer->s && val <= timer->e); | ||
101 | } else { | ||
102 | return (val > timer->e && val < timer->s); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | #define MAX_PACKET_SIZE USB_MAX_CTRL_PAYLOAD | ||
107 | |||
108 | #define ERROR_TIMEOUT (-3) | ||
109 | #define ERROR_UNKNOWN (-7) | ||
110 | |||
111 | #define PRIME_TIMER 100000 | ||
112 | #define TRANSFER_TIMER 1000000 | ||
113 | #define RESET_TIMER 5000000 | ||
114 | #define SETUP_TIMER 200000 | ||
115 | |||
116 | /*-------------------------------------------------------------------------*/ | ||
117 | |||
118 | /* gets called by usb_stack_init() to register | ||
119 | * this arcotg device conrtollder driver in the | ||
120 | * stack. */ | ||
121 | void usb_dcd_init(void) { | ||
122 | usb_controller_register(&arcotg_dcd); | ||
123 | } | ||
124 | |||
125 | /*-------------------------------------------------------------------------*/ | ||
126 | |||
127 | void usb_arcotg_dcd_init(void) { | ||
128 | |||
129 | struct timer t; | ||
130 | int i, ep_num = 0; | ||
131 | |||
132 | logf("arcotg_dcd: init"); | ||
133 | memset(&dcd_controller, 0, sizeof(struct arcotg_dcd)); | ||
134 | |||
135 | /* setup list of aviable endpoints */ | ||
136 | INIT_LIST_HEAD(&arcotg_dcd.endpoints.list); | ||
137 | |||
138 | for (i = 0; i < USB_MAX_PIPES; i++) { | ||
139 | |||
140 | dcd_controller.endpoints[i].pipe_num = i; | ||
141 | |||
142 | if (i % 2 == 0) { | ||
143 | dcd_controller.endpoints[i].ep_num = ep_num; | ||
144 | } else { | ||
145 | dcd_controller.endpoints[i].ep_num = ep_num; | ||
146 | ep_num++; | ||
147 | } | ||
148 | |||
149 | logf("pipe %d -> ep %d %s", dcd_controller.endpoints[i].pipe_num, dcd_controller.endpoints[i].ep_num, dcd_controller.endpoints[i].name); | ||
150 | |||
151 | if (ep_name[i] != NULL) { | ||
152 | memcpy(&dcd_controller.endpoints[i].name, ep_name[i], sizeof(dcd_controller.endpoints[i].name)); | ||
153 | |||
154 | if (i != 0) { | ||
155 | /* add to list of configurable endpoints */ | ||
156 | list_add_tail(&dcd_controller.endpoints[i].list, &arcotg_dcd.endpoints.list); | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | /* ep0 is special */ | ||
162 | arcotg_dcd.ep0 = &dcd_controller.endpoints[0]; | ||
163 | arcotg_dcd.ep0->maxpacket = USB_MAX_CTRL_PAYLOAD; | ||
164 | |||
165 | /* stop */ | ||
166 | UDC_USBCMD &= ~USB_CMD_RUN; | ||
167 | |||
168 | udelay(50000); | ||
169 | timer_set(&t, RESET_TIMER); | ||
170 | |||
171 | /* reset */ | ||
172 | UDC_USBCMD |= USB_CMD_CTRL_RESET; | ||
173 | |||
174 | while ((UDC_USBCMD & USB_CMD_CTRL_RESET)) { | ||
175 | if (timer_expired(&t)) { | ||
176 | logf("TIMEOUT->init"); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* put controller in device mode */ | ||
181 | UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE; | ||
182 | |||
183 | /* init queue heads */ | ||
184 | qh_init(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD, 0, 0); | ||
185 | qh_init(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD, 0, 0); | ||
186 | |||
187 | UDC_ENDPOINTLISTADDR = (unsigned int)dev_qh; | ||
188 | } | ||
189 | |||
190 | void usb_arcotg_dcd_shutdown(void) { | ||
191 | |||
192 | } | ||
193 | |||
194 | void usb_arcotg_dcd_start(void) { | ||
195 | |||
196 | logf("start"); | ||
197 | |||
198 | if (arcotg_dcd.device_driver != NULL) { | ||
199 | logf("YEEEEEEESSSSSSS"); | ||
200 | } else { | ||
201 | logf("NOOOOOO"); | ||
202 | } | ||
203 | |||
204 | /* clear stopped bit */ | ||
205 | dcd_controller.stopped = false; | ||
206 | |||
207 | UDC_USBCMD |= USB_CMD_RUN; | ||
208 | } | ||
209 | |||
210 | void usb_arcotg_dcd_stop(void) { | ||
211 | |||
212 | logf("stop"); | ||
213 | |||
214 | /* set stopped bit */ | ||
215 | dcd_controller.stopped = true; | ||
216 | |||
217 | UDC_USBCMD &= ~USB_CMD_RUN; | ||
218 | } | ||
219 | |||
220 | void usb_arcotg_dcd_irq(void) { | ||
221 | |||
222 | int i; | ||
223 | |||
224 | if (dcd_controller.stopped == true) { | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | /* check if we need to wake up from suspend */ | ||
229 | if (!(UDC_USBSTS & USB_STS_SUSPEND) && dcd_controller.resume_state) { | ||
230 | resume_int(); | ||
231 | } | ||
232 | |||
233 | /* USB Interrupt */ | ||
234 | if (UDC_USBSTS & USB_STS_INT) { | ||
235 | |||
236 | /* setup packet, we only support ep0 as control ep */ | ||
237 | if (UDC_ENDPTSETUPSTAT & EP_SETUP_STATUS_EP0) { | ||
238 | /* copy data from queue head to local buffer */ | ||
239 | memcpy(&dcd_controller.local_setup_buff, (uint8_t *) &dev_qh[0].setup_buffer, 8); | ||
240 | /* ack setup packet*/ | ||
241 | UDC_ENDPTSETUPSTAT = UDC_ENDPTSETUPSTAT; | ||
242 | setup_received_int(&dcd_controller.local_setup_buff); | ||
243 | } | ||
244 | |||
245 | if (UDC_ENDPTCOMPLETE) { | ||
246 | UDC_ENDPTCOMPLETE = UDC_ENDPTCOMPLETE; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | if (UDC_USBSTS & USB_STS_PORT_CHANGE) { | ||
251 | port_change_int(); | ||
252 | } | ||
253 | |||
254 | if (UDC_USBSTS & USB_STS_SUSPEND) { | ||
255 | suspend_int(); | ||
256 | } | ||
257 | |||
258 | if (UDC_USBSTS & USB_STS_RESET) { | ||
259 | reset_int(); | ||
260 | } | ||
261 | |||
262 | if (UDC_USBSTS & USB_STS_ERR) { | ||
263 | logf("!!! error !!!"); | ||
264 | } | ||
265 | |||
266 | if (UDC_USBSTS & USB_STS_SYS_ERR) { | ||
267 | logf("!!! sys error !!!"); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | /*-------------------------------------------------------------------------*/ | ||
272 | /* interrupt handlers */ | ||
273 | |||
274 | static void setup_received_int(struct usb_ctrlrequest* request) { | ||
275 | |||
276 | int error = 0; | ||
277 | uint8_t address = 0; | ||
278 | int handled = 0; /* set to zero if we do not handle the message, */ | ||
279 | /* and should pass it to the driver */ | ||
280 | |||
281 | logf("setup_int"); | ||
282 | into_usb_ctrlrequest(request); | ||
283 | |||
284 | /* handle all requests we support */ | ||
285 | switch (request->bRequestType & USB_TYPE_MASK) { | ||
286 | case USB_TYPE_STANDARD: | ||
287 | |||
288 | switch (request->bRequest) { | ||
289 | case USB_REQ_SET_ADDRESS: | ||
290 | |||
291 | /* store address as we need to ack before setting it */ | ||
292 | address = (uint8_t)request->wValue; | ||
293 | |||
294 | handled = 1; | ||
295 | break; | ||
296 | |||
297 | case USB_REQ_GET_STATUS: | ||
298 | |||
299 | logf("sending status.."); | ||
300 | response.buf = &dcd_controller.usb_state; | ||
301 | response.length = 2; | ||
302 | |||
303 | handled = usb_arcotg_dcd_send(NULL, &response); | ||
304 | break; | ||
305 | } | ||
306 | |||
307 | case USB_REQ_CLEAR_FEATURE: | ||
308 | case USB_REQ_SET_FEATURE: | ||
309 | /* we only support set/clear feature for endpoint */ | ||
310 | if (request->bRequestType == USB_RECIP_ENDPOINT) { | ||
311 | int dir = (request->wIndex & 0x0080) ? EP_DIR_IN : EP_DIR_OUT; | ||
312 | int num = (request->wIndex & 0x000f); | ||
313 | struct usb_ep *ep; | ||
314 | |||
315 | if (request->wValue != 0 || request->wLength != 0 || (num * 2 + dir) > USB_MAX_PIPES) { | ||
316 | break; | ||
317 | } | ||
318 | ep = &dcd_controller.endpoints[num * 2 + dir]; | ||
319 | |||
320 | if (request->bRequest == USB_REQ_SET_FEATURE) { | ||
321 | logf("SET_FEATURE doing set_halt"); | ||
322 | handled = usb_arcotg_dcd_set_halt(ep, 1); | ||
323 | } else { | ||
324 | logf("CLEAR_FEATURE doing clear_halt"); | ||
325 | handled = usb_arcotg_dcd_set_halt(ep, 0); | ||
326 | } | ||
327 | |||
328 | if (handled == 0) { | ||
329 | handled = 1; /* dont pass it to driver */ | ||
330 | } | ||
331 | } | ||
332 | #if 0 | ||
333 | if (rc == 0) { | ||
334 | /* send status only if _arcotg_ep_set_halt success */ | ||
335 | if (ep0_prime_status(udc, EP_DIR_IN)) | ||
336 | Ep0Stall(udc); | ||
337 | } | ||
338 | #endif | ||
339 | break; | ||
340 | } | ||
341 | |||
342 | /* if dcd can not handle reqeust, ask driver */ | ||
343 | if (handled == 0) { | ||
344 | if (arcotg_dcd.device_driver != NULL && arcotg_dcd.device_driver->request != NULL) { | ||
345 | handled = arcotg_dcd.device_driver->request(request); | ||
346 | logf("result from driver %d", handled); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | if (handled <= 0) { | ||
351 | error = handled; | ||
352 | } | ||
353 | |||
354 | /* ack transfer */ | ||
355 | usb_ack(request, error); | ||
356 | |||
357 | if (address != 0) { | ||
358 | logf("setting address to %d", address); | ||
359 | UDC_DEVICEADDR = address << 25; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | static void port_change_int(void) { | ||
364 | |||
365 | //logf("port_change_int"); | ||
366 | uint32_t tmp; | ||
367 | enum usb_device_speed speed = USB_SPEED_UNKNOWN; | ||
368 | |||
369 | /* bus resetting is finished */ | ||
370 | if (!(UDC_PORTSC1 & PORTSCX_PORT_RESET)) { | ||
371 | /* Get the speed */ | ||
372 | tmp = (UDC_PORTSC1 & PORTSCX_PORT_SPEED_MASK); | ||
373 | switch (tmp) { | ||
374 | case PORTSCX_PORT_SPEED_HIGH: | ||
375 | speed = USB_SPEED_HIGH; | ||
376 | break; | ||
377 | case PORTSCX_PORT_SPEED_FULL: | ||
378 | speed = USB_SPEED_FULL; | ||
379 | break; | ||
380 | case PORTSCX_PORT_SPEED_LOW: | ||
381 | speed = USB_SPEED_LOW; | ||
382 | break; | ||
383 | default: | ||
384 | speed = USB_SPEED_UNKNOWN; | ||
385 | break; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | /* update speed */ | ||
390 | arcotg_dcd.speed = speed; | ||
391 | |||
392 | /* update USB state */ | ||
393 | if (!dcd_controller.resume_state) { | ||
394 | dcd_controller.usb_state = USB_STATE_DEFAULT; | ||
395 | } | ||
396 | |||
397 | /* inform device driver */ | ||
398 | if (arcotg_dcd.device_driver != NULL && arcotg_dcd.device_driver->speed != NULL) { | ||
399 | arcotg_dcd.device_driver->speed(speed); | ||
400 | } | ||
401 | } | ||
402 | |||
403 | static void suspend_int(void) { | ||
404 | |||
405 | //logf("suspend_int"); | ||
406 | dcd_controller.resume_state = dcd_controller.usb_state; | ||
407 | dcd_controller.usb_state = USB_STATE_SUSPENDED; | ||
408 | |||
409 | /* report suspend to the driver */ | ||
410 | if (arcotg_dcd.device_driver != NULL && arcotg_dcd.device_driver->suspend != NULL) { | ||
411 | arcotg_dcd.device_driver->suspend(); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | static void resume_int(void) { | ||
416 | |||
417 | //logf("resume_int"); | ||
418 | dcd_controller.usb_state = dcd_controller.resume_state; | ||
419 | dcd_controller.resume_state = USB_STATE_NOTATTACHED; | ||
420 | |||
421 | /* report resume to the driver */ | ||
422 | if (arcotg_dcd.device_driver != NULL && arcotg_dcd.device_driver->resume != NULL) { | ||
423 | arcotg_dcd.device_driver->resume(); | ||
424 | } | ||
425 | } | ||
426 | |||
427 | static void reset_int(void) { | ||
428 | |||
429 | //logf("reset_int"); | ||
430 | struct timer t; | ||
431 | |||
432 | timer_set(&t, RESET_TIMER); | ||
433 | |||
434 | UDC_ENDPTSETUPSTAT = UDC_ENDPTSETUPSTAT; | ||
435 | UDC_ENDPTCOMPLETE = UDC_ENDPTCOMPLETE; | ||
436 | |||
437 | while (UDC_ENDPTPRIME) { /* prime and flush pending transfers */ | ||
438 | if (timer_expired(&t)) { | ||
439 | logf("TIMEOUT->p&f"); | ||
440 | } | ||
441 | } | ||
442 | |||
443 | UDC_ENDPTFLUSH = ~0; | ||
444 | |||
445 | if ((UDC_PORTSC1 & (1 << 8)) == 0) { | ||
446 | logf("TIMEOUT->port"); | ||
447 | } | ||
448 | |||
449 | UDC_USBSTS = (1 << 6); | ||
450 | |||
451 | while ((UDC_USBSTS & (1 << 2)) == 0) { /* wait for port change */ | ||
452 | if (timer_expired(&t)) { | ||
453 | logf("TIMEOUT->portchange"); | ||
454 | } | ||
455 | } | ||
456 | |||
457 | UDC_USBSTS = (1 << 2); | ||
458 | } | ||
459 | |||
460 | |||
461 | /*-------------------------------------------------------------------------*/ | ||
462 | /* usb controller ops */ | ||
463 | |||
464 | int usb_arcotg_dcd_enable(struct usb_ep* ep) { | ||
465 | |||
466 | unsigned short max = 0; | ||
467 | unsigned char mult = 0, zlt = 0; | ||
468 | int retval = 0; | ||
469 | char *val = NULL; /* for debug */ | ||
470 | |||
471 | /* catch bogus parameter */ | ||
472 | if (!ep) { | ||
473 | return -EINVAL; | ||
474 | } | ||
475 | |||
476 | logf("ahhh %d", ep->desc->wMaxPacketSize); | ||
477 | max = ep->desc->wMaxPacketSize; | ||
478 | retval = -EINVAL; | ||
479 | |||
480 | /* check the max package size validate for this endpoint */ | ||
481 | /* Refer to USB2.0 spec table 9-13, | ||
482 | */ | ||
483 | switch (ep->desc->bmAttributes & 0x03) { | ||
484 | case USB_ENDPOINT_XFER_BULK: | ||
485 | zlt = 1; | ||
486 | break; | ||
487 | |||
488 | case USB_ENDPOINT_XFER_INT: | ||
489 | zlt = 1; | ||
490 | break; | ||
491 | |||
492 | case USB_ENDPOINT_XFER_ISOC: | ||
493 | break; | ||
494 | |||
495 | case USB_ENDPOINT_XFER_CONTROL: | ||
496 | break; | ||
497 | } | ||
498 | |||
499 | #if 0 | ||
500 | switch (ep->desc->bmAttributes & 0x03) { | ||
501 | case USB_ENDPOINT_XFER_BULK: | ||
502 | if (strstr(ep->ep.name, "-iso") || strstr(ep->ep.name, "-int")) { | ||
503 | goto en_done; | ||
504 | } | ||
505 | mult = 0; | ||
506 | zlt = 1; | ||
507 | |||
508 | switch (arcotg_dcd.speed) { | ||
509 | case USB_SPEED_HIGH: | ||
510 | if ((max == 128) || (max == 256) || (max == 512)) { | ||
511 | break; | ||
512 | } | ||
513 | default: | ||
514 | switch (max) { | ||
515 | case 4: | ||
516 | case 8: | ||
517 | case 16: | ||
518 | case 32: | ||
519 | case 64: | ||
520 | break; | ||
521 | default: | ||
522 | + case USB_SPEED_LOW: | ||
523 | + goto en_done; | ||
524 | + } | ||
525 | + } | ||
526 | + break; | ||
527 | + case USB_ENDPOINT_XFER_INT: | ||
528 | + if (strstr(ep->ep.name, "-iso")) /* bulk is ok */ | ||
529 | + goto en_done; | ||
530 | + mult = 0; | ||
531 | + zlt = 1; | ||
532 | + switch (udc->gadget.speed) { | ||
533 | + case USB_SPEED_HIGH: | ||
534 | + if (max <= 1024) | ||
535 | + break; | ||
536 | + case USB_SPEED_FULL: | ||
537 | + if (max <= 64) | ||
538 | + break; | ||
539 | + default: | ||
540 | + if (max <= 8) | ||
541 | + break; | ||
542 | + goto en_done; | ||
543 | + } | ||
544 | + break; | ||
545 | + case USB_ENDPOINT_XFER_ISOC: | ||
546 | + if (strstr(ep->ep.name, "-bulk") || strstr(ep->ep.name, "-int")) | ||
547 | + goto en_done; | ||
548 | + mult = (unsigned char) | ||
549 | + (1 + ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 0x03)); | ||
550 | + zlt = 0; | ||
551 | + switch (udc->gadget.speed) { | ||
552 | + case USB_SPEED_HIGH: | ||
553 | + if (max <= 1024) | ||
554 | + break; | ||
555 | + case USB_SPEED_FULL: | ||
556 | + if (max <= 1023) | ||
557 | + break; | ||
558 | + default: | ||
559 | + goto en_done; | ||
560 | + } | ||
561 | + break; | ||
562 | + case USB_ENDPOINT_XFER_CONTROL: | ||
563 | + if (strstr(ep->ep.name, "-iso") || strstr(ep->ep.name, "-int")) | ||
564 | + goto en_done; | ||
565 | + mult = 0; | ||
566 | + zlt = 1; | ||
567 | + switch (udc->gadget.speed) { | ||
568 | + case USB_SPEED_HIGH: | ||
569 | + case USB_SPEED_FULL: | ||
570 | + switch (max) { | ||
571 | + case 1: | ||
572 | + case 2: | ||
573 | + case 4: | ||
574 | + case 8: | ||
575 | + case 16: | ||
576 | + case 32: | ||
577 | + case 64: | ||
578 | + break; | ||
579 | + default: | ||
580 | + goto en_done; | ||
581 | + } | ||
582 | + case USB_SPEED_LOW: | ||
583 | + switch (max) { | ||
584 | + case 1: | ||
585 | + case 2: | ||
586 | + case 4: | ||
587 | + case 8: | ||
588 | + break; | ||
589 | + default: | ||
590 | + goto en_done; | ||
591 | + } | ||
592 | + default: | ||
593 | + goto en_done; | ||
594 | + } | ||
595 | + break; | ||
596 | + | ||
597 | + default: | ||
598 | + goto en_done; | ||
599 | + } | ||
600 | #endif | ||
601 | |||
602 | /* here initialize variable of ep */ | ||
603 | ep->maxpacket = max; | ||
604 | |||
605 | /* hardware special operation */ | ||
606 | |||
607 | /* Init EPx Queue Head (Ep Capabilites field in QH | ||
608 | * according to max, zlt, mult) */ | ||
609 | qh_init(ep->ep_num, | ||
610 | (ep->desc->bEndpointAddress & USB_DIR_IN) ? USB_RECV : USB_SEND, | ||
611 | (unsigned char) (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK), | ||
612 | max, zlt, mult); | ||
613 | |||
614 | /* Init endpoint x at here */ | ||
615 | ep_setup(ep->ep_num, | ||
616 | (unsigned char)((ep->desc->bEndpointAddress & USB_DIR_IN) ? USB_RECV : USB_SEND), | ||
617 | (unsigned char)(ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)); | ||
618 | |||
619 | /* Now HW will be NAKing transfers to that EP, | ||
620 | * until a buffer is queued to it. */ | ||
621 | |||
622 | retval = 0; | ||
623 | switch (ep->desc->bmAttributes & 0x03) { | ||
624 | case USB_ENDPOINT_XFER_BULK: | ||
625 | val = "bulk"; | ||
626 | break; | ||
627 | case USB_ENDPOINT_XFER_ISOC: | ||
628 | val = "iso"; | ||
629 | break; | ||
630 | case USB_ENDPOINT_XFER_INT: | ||
631 | val = "intr"; | ||
632 | break; | ||
633 | default: | ||
634 | val = "ctrl"; | ||
635 | break; | ||
636 | } | ||
637 | |||
638 | logf("ep num %d", (int)ep->ep_num); | ||
639 | |||
640 | logf("enabled %s (ep%d%s-%s)", ep->name, | ||
641 | ep->desc->bEndpointAddress & 0x0f, | ||
642 | (ep->desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", val); | ||
643 | logf(" maxpacket %d", max); | ||
644 | |||
645 | return retval; | ||
646 | } | ||
647 | |||
648 | int usb_arcotg_dcd_set_halt(struct usb_ep* ep, bool halt) { | ||
649 | |||
650 | int status = -EOPNOTSUPP; /* operation not supported */ | ||
651 | unsigned char dir = 0; | ||
652 | unsigned int tmp_epctrl = 0; | ||
653 | |||
654 | if (!ep) { | ||
655 | status = -EINVAL; | ||
656 | goto out; | ||
657 | } | ||
658 | |||
659 | if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { | ||
660 | status = -EOPNOTSUPP; | ||
661 | goto out; | ||
662 | } | ||
663 | |||
664 | status = 0; | ||
665 | dir = ep_is_in(ep) ? USB_SEND : USB_RECV; | ||
666 | |||
667 | tmp_epctrl = UDC_ENDPTCTRL(ep->ep_num); | ||
668 | |||
669 | if (halt) { | ||
670 | /* set the stall bit */ | ||
671 | if (dir) { | ||
672 | tmp_epctrl |= EPCTRL_TX_EP_STALL; | ||
673 | } else { | ||
674 | tmp_epctrl |= EPCTRL_RX_EP_STALL; | ||
675 | } | ||
676 | } else { | ||
677 | /* clear the stall bit and reset data toggle */ | ||
678 | if (dir) { | ||
679 | tmp_epctrl &= ~EPCTRL_TX_EP_STALL; | ||
680 | tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; | ||
681 | } else { | ||
682 | tmp_epctrl &= ~EPCTRL_RX_EP_STALL; | ||
683 | tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; | ||
684 | } | ||
685 | } | ||
686 | UDC_ENDPTCTRL(ep->ep_num) = tmp_epctrl; | ||
687 | |||
688 | out: | ||
689 | logf(" %s %s halt rc=%d", ep->name, halt ? "set" : "clear", status); | ||
690 | return status; | ||
691 | } | ||
692 | |||
693 | int usb_arcotg_dcd_send(struct usb_ep* ep, struct usb_response* res) { | ||
694 | |||
695 | char* ptr; | ||
696 | int todo, error, size, done = 0; | ||
697 | int index = 1; /* use as default ep0 tx qh and td */ | ||
698 | struct dtd* td; | ||
699 | struct dqh* qh; | ||
700 | unsigned int mask; | ||
701 | |||
702 | if (res == NULL) { | ||
703 | logf("invalid input"); | ||
704 | return -EINVAL; | ||
705 | } | ||
706 | |||
707 | if (ep != NULL) { | ||
708 | index = ep->pipe_num; | ||
709 | } | ||
710 | |||
711 | logf("buff: %x", res->buf); | ||
712 | logf("len: %d", res->length); | ||
713 | |||
714 | ptr = res->buf; | ||
715 | size = res->length; | ||
716 | |||
717 | td = &dev_td[index]; | ||
718 | qh = &dev_qh[index]; | ||
719 | mask = 1 << (15 + index); | ||
720 | logf("sending mask: %x", mask); | ||
721 | |||
722 | do { | ||
723 | /* calculate how much to copy and send */ | ||
724 | todo = MIN(size, BUFFER_SIZE); | ||
725 | |||
726 | /* copy data to shared memory area */ | ||
727 | memcpy(buffer, ptr, todo); | ||
728 | |||
729 | /* init transfer descriptor */ | ||
730 | td_init(td, buffer, todo); | ||
731 | |||
732 | /* start transfer*/ | ||
733 | error = td_enqueue(td, qh, mask); | ||
734 | |||
735 | if (error == 0) { | ||
736 | /* waiting for finished transfer */ | ||
737 | error = td_wait(td, mask); | ||
738 | } | ||
739 | |||
740 | if (error) { | ||
741 | done = error; | ||
742 | break; | ||
743 | } | ||
744 | |||
745 | size -= todo; | ||
746 | ptr += todo; | ||
747 | done += todo; | ||
748 | |||
749 | } while (size > 0); | ||
750 | |||
751 | logf("usb_send done %d",done); | ||
752 | return done; | ||
753 | } | ||
754 | |||
755 | int usb_arcotg_dcd_receive(struct usb_ep* ep, struct usb_response* res) { | ||
756 | |||
757 | char* ptr; | ||
758 | int todo, error, size, done = 0; | ||
759 | int index = 0; /* use as default ep0 rx qh and td */ | ||
760 | struct dtd* td; | ||
761 | struct dqh* qh; | ||
762 | unsigned int mask; | ||
763 | |||
764 | if (res == NULL) { | ||
765 | logf("invalid input"); | ||
766 | return -EINVAL; | ||
767 | } | ||
768 | |||
769 | if (ep != NULL) { | ||
770 | index = ep->pipe_num; | ||
771 | } | ||
772 | |||
773 | ptr = res->buf; | ||
774 | size = res->length; | ||
775 | |||
776 | td = &dev_td[index]; | ||
777 | qh = &dev_qh[index]; | ||
778 | mask = 1 << index; | ||
779 | |||
780 | do { | ||
781 | /* calculate how much to receive in one step */ | ||
782 | todo = MIN(size, BUFFER_SIZE); | ||
783 | |||
784 | /* init transfer descritpor */ | ||
785 | td_init(td, buffer, size); | ||
786 | |||
787 | /* start transfer */ | ||
788 | error = td_enqueue(td, qh, mask); | ||
789 | |||
790 | if (error == 0) { | ||
791 | /* wait until transfer is finished */ | ||
792 | error = td_wait(td, mask); | ||
793 | } | ||
794 | |||
795 | if (error) { | ||
796 | done = error; | ||
797 | break; | ||
798 | } | ||
799 | |||
800 | /* copy receive data to buffer */ | ||
801 | memcpy(ptr, buffer, todo); | ||
802 | |||
803 | size -= todo; | ||
804 | ptr += todo; | ||
805 | done += todo; | ||
806 | |||
807 | } while (size > 0); | ||
808 | |||
809 | logf("usb_recive done %d",done); | ||
810 | return done; | ||
811 | } | ||
812 | |||
813 | /*-------------------------------------------------------------------------*/ | ||
814 | /* lifecylce */ | ||
815 | |||
816 | static void qh_init(unsigned char ep_num, unsigned char dir, unsigned char ep_type, | ||
817 | unsigned int max_pkt_len, unsigned int zlt, unsigned char mult) { | ||
818 | |||
819 | struct dqh *qh = &dev_qh[2 * ep_num + dir]; | ||
820 | uint32_t tmp = 0; | ||
821 | memset(qh, 0, sizeof(struct dqh)); | ||
822 | |||
823 | /* set the Endpoint Capabilites Reg of QH */ | ||
824 | switch (ep_type) { | ||
825 | case USB_ENDPOINT_XFER_CONTROL: | ||
826 | /* Interrupt On Setup (IOS). for control ep */ | ||
827 | tmp = (max_pkt_len << LENGTH_BIT_POS) | INTERRUPT_ON_COMPLETE; | ||
828 | break; | ||
829 | case USB_ENDPOINT_XFER_ISOC: | ||
830 | tmp = (max_pkt_len << LENGTH_BIT_POS) | (mult << EP_QUEUE_HEAD_MULT_POS); | ||
831 | break; | ||
832 | case USB_ENDPOINT_XFER_BULK: | ||
833 | case USB_ENDPOINT_XFER_INT: | ||
834 | tmp = max_pkt_len << LENGTH_BIT_POS; | ||
835 | if (zlt) { | ||
836 | tmp |= EP_QUEUE_HEAD_ZLT_SEL; | ||
837 | } | ||
838 | break; | ||
839 | default: | ||
840 | logf("error ep type is %d", ep_type); | ||
841 | return; | ||
842 | } | ||
843 | |||
844 | /* see 32.14.4.1 Queue Head Initialization */ | ||
845 | |||
846 | /* write the wMaxPacketSize field as required by the USB Chapter9 or application specific portocol */ | ||
847 | qh->endpt_cap = tmp; | ||
848 | |||
849 | /* write the next dTD Terminate bit fild to 1 */ | ||
850 | qh->dtd_ovrl.next_dtd = 1; | ||
851 | |||
852 | /* write the Active bit in the status field to 0 */ | ||
853 | qh->dtd_ovrl.dtd_token &= ~STATUS_ACTIVE; | ||
854 | |||
855 | /* write the Hald bit in the status field to 0 */ | ||
856 | qh->dtd_ovrl.dtd_token &= ~STATUS_HALTED; | ||
857 | |||
858 | logf("qh: init %d", (2 * ep_num + dir)); | ||
859 | } | ||
860 | |||
861 | static void td_init(struct dtd* td, void* buffer, uint32_t todo) { | ||
862 | |||
863 | /* see 32.14.5.2 Building a Transfer Descriptor */ | ||
864 | |||
865 | /* init first 7 dwords with 0 */ | ||
866 | memset(td, 0, sizeof(struct dtd)); /* set set all to 0 */ | ||
867 | |||
868 | /* set terminate bit to 1*/ | ||
869 | td->next_dtd = 1; | ||
870 | |||
871 | /* fill in total bytes with transfer size */ | ||
872 | td->dtd_token = (todo << 16); | ||
873 | |||
874 | /* set interrupt on compilte if desierd */ | ||
875 | td->dtd_token |= INTERRUPT_ON_COMPLETE; | ||
876 | |||
877 | /* initialize the status field with the active bit set to 1 and all remaining status bits to 0 */ | ||
878 | td->dtd_token |= STATUS_ACTIVE; | ||
879 | |||
880 | td->buf_ptr0 = (uint32_t)buffer; | ||
881 | } | ||
882 | |||
883 | static void ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type) { | ||
884 | |||
885 | unsigned int tmp_epctrl = 0; | ||
886 | struct timer t; | ||
887 | |||
888 | tmp_epctrl = UDC_ENDPTCTRL(ep_num); | ||
889 | if (dir) { | ||
890 | if (ep_num) { | ||
891 | tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; | ||
892 | } | ||
893 | logf("tx enablde"); | ||
894 | tmp_epctrl |= EPCTRL_TX_ENABLE; | ||
895 | tmp_epctrl |= ((unsigned int)(ep_type) << EPCTRL_TX_EP_TYPE_SHIFT); | ||
896 | } else { | ||
897 | if (ep_num) { | ||
898 | tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; | ||
899 | } | ||
900 | logf("rx enablde"); | ||
901 | tmp_epctrl |= EPCTRL_RX_ENABLE; | ||
902 | tmp_epctrl |= ((unsigned int)(ep_type) << EPCTRL_RX_EP_TYPE_SHIFT); | ||
903 | } | ||
904 | |||
905 | UDC_ENDPTCTRL(ep_num) = tmp_epctrl; | ||
906 | |||
907 | /* wait for the write reg to finish */ | ||
908 | |||
909 | timer_set(&t, SETUP_TIMER); | ||
910 | while (!(UDC_ENDPTCTRL(ep_num) & (tmp_epctrl & (EPCTRL_TX_ENABLE | EPCTRL_RX_ENABLE)))) { | ||
911 | if (timer_expired(&t)) { | ||
912 | logf("TIMEOUT: enable ep"); | ||
913 | return; | ||
914 | } | ||
915 | } | ||
916 | } | ||
917 | |||
918 | /*-------------------------------------------------------------------------*/ | ||
919 | /* helpers for sending/receiving */ | ||
920 | |||
921 | static int td_enqueue(struct dtd* td, struct dqh* qh, unsigned int mask) { | ||
922 | |||
923 | struct timer t; | ||
924 | |||
925 | qh->dtd_ovrl.next_dtd = (unsigned int)td; | ||
926 | qh->dtd_ovrl.dtd_token &= ~0xc0; | ||
927 | |||
928 | timer_set(&t, PRIME_TIMER); | ||
929 | UDC_ENDPTPRIME |= mask; | ||
930 | |||
931 | while ((UDC_ENDPTPRIME & mask)) { | ||
932 | if (timer_expired(&t)) { | ||
933 | logf("timeout->prime"); | ||
934 | } | ||
935 | } | ||
936 | |||
937 | if ((UDC_ENDPTSTAT & mask) == 0) { | ||
938 | logf("Endptstat 0x%x", UDC_ENDPTSTAT); | ||
939 | logf("HW_ERROR"); | ||
940 | } | ||
941 | |||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | static int td_wait(struct dtd* td, unsigned int mask) { | ||
946 | |||
947 | struct timer t; | ||
948 | timer_set(&t, TRANSFER_TIMER); | ||
949 | |||
950 | for (;;) { | ||
951 | if ((UDC_ENDPTCOMPLETE & mask) != 0) { | ||
952 | UDC_ENDPTCOMPLETE |= mask; | ||
953 | } | ||
954 | |||
955 | if ((td->dtd_token & (1 << 7)) == 0) { | ||
956 | return 0; | ||
957 | } | ||
958 | |||
959 | if (timer_expired(&t)) { | ||
960 | return ERROR_TIMEOUT; | ||
961 | } | ||
962 | } | ||
963 | } | ||
964 | |||
965 | static int usb_ack(struct usb_ctrlrequest * s, int error) { | ||
966 | |||
967 | if (error) { | ||
968 | logf("STALLing ep0"); | ||
969 | UDC_ENDPTCTRL0 |= 1 << 16; /* stall */ | ||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | res.buf = NULL; | ||
974 | res.length = 0; | ||
975 | |||
976 | if (s->bRequestType & 0x80) { | ||
977 | logf("ack in"); | ||
978 | return usb_arcotg_dcd_receive(NULL, &res); | ||
979 | } else { | ||
980 | logf("ack out"); | ||
981 | return usb_arcotg_dcd_send(NULL, &res); | ||
982 | } | ||
983 | } | ||
diff --git a/firmware/drivers/usb/arcotg_dcd.h b/firmware/drivers/usb/arcotg_dcd.h new file mode 100644 index 0000000000..127ee43efa --- /dev/null +++ b/firmware/drivers/usb/arcotg_dcd.h | |||
@@ -0,0 +1,173 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * Based on code from the Linux Target Image Builder from Freescale | ||
13 | * available at http://www.bitshrine.org/ and | ||
14 | * http://www.bitshrine.org/gpp/linux-2.6.16-mx31-usb-2.patch | ||
15 | * Adapted for Rockbox in January 2007 | ||
16 | * Original file: drivers/usb/gadget/arcotg_udc.c | ||
17 | * | ||
18 | * USB Device Controller Driver | ||
19 | * Driver for ARC OTG USB module in the i.MX31 platform, etc. | ||
20 | * | ||
21 | * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. | ||
22 | * | ||
23 | * Based on mpc-udc.h | ||
24 | * Author: Li Yang (leoli@freescale.com) | ||
25 | * Jiang Bo (Tanya.jiang@freescale.com) | ||
26 | * | ||
27 | * All files in this archive are subject to the GNU General Public License. | ||
28 | * See the file COPYING in the source tree root for full license agreement. | ||
29 | * | ||
30 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
31 | * KIND, either express or implied. | ||
32 | * | ||
33 | ****************************************************************************/ | ||
34 | |||
35 | #ifndef _ARCOTG_DCD_H_ | ||
36 | #define _ARCOTG_DCD_H_ | ||
37 | |||
38 | #include "usbstack/core.h" | ||
39 | #include "arcotg_udc.h" | ||
40 | |||
41 | /*-------------------------------------------------------------------------*/ | ||
42 | |||
43 | #define ep_is_in(EP) (((EP)->desc->bEndpointAddress & USB_DIR_IN)==USB_DIR_IN) | ||
44 | |||
45 | #define EP_DIR_IN 1 | ||
46 | #define EP_DIR_OUT 0 | ||
47 | |||
48 | /*-------------------------------------------------------------------------*/ | ||
49 | |||
50 | /* pipe direction macro from device view */ | ||
51 | #define USB_RECV (0) /* OUT EP */ | ||
52 | #define USB_SEND (1) /* IN EP */ | ||
53 | |||
54 | /* Shared Bit Masks for Endpoint Queue Head and Endpoint Transfer Descriptor */ | ||
55 | #define TERMINATE (1 << 0) | ||
56 | #define STATUS_ACTIVE (1 << 7) | ||
57 | #define STATUS_HALTED (1 << 6) | ||
58 | #define STATUS_DATA_BUFF_ERR (1 << 5) | ||
59 | #define STATUS_TRANSACTION_ERR (1 << 4) | ||
60 | #define INTERRUPT_ON_COMPLETE (1 << 15) | ||
61 | #define LENGTH_BIT_POS (16) | ||
62 | #define ADDRESS_MASK (0xFFFFFFE0) | ||
63 | #define ERROR_MASK (DTD_STATUS_HALTED | \ | ||
64 | DTD_STATUS_DATA_BUFF_ERR | \ | ||
65 | DTD_STATUS_TRANSACTION_ERR) | ||
66 | |||
67 | #define RESERVED_FIELDS ((1 << 0) | (1 << 2) | (1 << 4) | \ | ||
68 | (1 << 8) | (1 << 9) | (1 << 12)| \ | ||
69 | (1 << 13)| (1 << 14)| (1 << 31)) | ||
70 | |||
71 | /* Endpoint Queue Head Bit Masks */ | ||
72 | #define EP_QUEUE_HEAD_MULT_POS (30) | ||
73 | #define EP_QUEUE_HEAD_ZLT_SEL (0x20000000) | ||
74 | #define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff) | ||
75 | #define EP_QUEUE_HEAD_MULTO (0x00000C00) | ||
76 | #define EP_QUEUE_CURRENT_OFFSET_MASK (0x00000FFF) | ||
77 | #define EP_QUEUE_FRINDEX_MASK (0x000007FF) | ||
78 | #define EP_MAX_LENGTH_TRANSFER (0x4000) | ||
79 | |||
80 | /*-------------------------------------------------------------------------*/ | ||
81 | |||
82 | /* ep name is important, it should obey the convention of ep_match() */ | ||
83 | /* even numbered EPs are OUT or setup, odd are IN/INTERRUPT */ | ||
84 | static const char* ep_name[] = { | ||
85 | "ep0-control", NULL, /* everyone has ep0 */ | ||
86 | /* 7 configurable endpoints */ | ||
87 | "ep1out", | ||
88 | "ep1in", | ||
89 | "ep2out", | ||
90 | "ep2in", | ||
91 | "ep3out", | ||
92 | "ep3in", | ||
93 | "ep4out", | ||
94 | "ep4in", | ||
95 | "ep5out", | ||
96 | "ep5in", | ||
97 | "ep6out", | ||
98 | "ep6in", | ||
99 | "ep7out", | ||
100 | "ep7in" | ||
101 | }; | ||
102 | |||
103 | /*-------------------------------------------------------------------------*/ | ||
104 | |||
105 | /* Endpoint Transfer Descriptor data struct */ | ||
106 | struct dtd { | ||
107 | uint32_t next_dtd; /* Next TD pointer(31-5), T(0) set indicate invalid */ | ||
108 | uint32_t dtd_token; /* Total bytes (30-16), IOC (15), MultO(11-10), STS (7-0) */ | ||
109 | uint32_t buf_ptr0; /* Buffer pointer Page 0 */ | ||
110 | uint32_t buf_ptr1; /* Buffer pointer Page 1 */ | ||
111 | uint32_t buf_ptr2; /* Buffer pointer Page 2 */ | ||
112 | uint32_t buf_ptr3; /* Buffer pointer Page 3 */ | ||
113 | uint32_t buf_ptr4; /* Buffer pointer Page 4 */ | ||
114 | uint32_t res; /* make it an even 8 words */ | ||
115 | } __attribute((packed)); | ||
116 | |||
117 | /* Endpoint Queue Head*/ | ||
118 | struct dqh { | ||
119 | uint32_t endpt_cap; /* Mult(31-30) , Zlt(29) , Max Pkt len | ||
120 | * and IOS(15) */ | ||
121 | uint32_t cur_dtd; /* Current dTD Pointer(31-5) */ | ||
122 | struct dtd dtd_ovrl; /* Transfer descriptor */ | ||
123 | uint32_t setup_buffer[2]; /* Setup data 8 bytes */ | ||
124 | uint32_t res2[4]; /* pad out to 64 bytes */ | ||
125 | } __attribute((packed)); | ||
126 | |||
127 | #define RESPONSE_SIZE 30 | ||
128 | |||
129 | /* our controller struct */ | ||
130 | struct arcotg_dcd { | ||
131 | struct usb_ctrlrequest local_setup_buff; | ||
132 | struct usb_ep endpoints[USB_MAX_PIPES]; | ||
133 | struct usb_response response[RESPONSE_SIZE]; | ||
134 | enum usb_device_state usb_state; | ||
135 | enum usb_device_state resume_state; | ||
136 | bool stopped; | ||
137 | }; | ||
138 | |||
139 | /*-------------------------------------------------------------------------*/ | ||
140 | |||
141 | /* usb_controller functions */ | ||
142 | void usb_arcotg_dcd_init(void); | ||
143 | void usb_arcotg_dcd_shutdown(void); | ||
144 | void usb_arcotg_dcd_irq(void); | ||
145 | void usb_arcotg_dcd_start(void); | ||
146 | void usb_arcotg_dcd_stop(void); | ||
147 | |||
148 | /* usb controller ops */ | ||
149 | int usb_arcotg_dcd_enable(struct usb_ep* ep); | ||
150 | int usb_arcotg_dcd_disable(struct usb_ep* ep); | ||
151 | int usb_arcotg_dcd_set_halt(struct usb_ep* ep, bool halt); | ||
152 | int usb_arcotg_dcd_send(struct usb_ep* ep, struct usb_response* request); | ||
153 | int usb_arcotg_dcd_receive(struct usb_ep* ep, struct usb_response* res); | ||
154 | |||
155 | /* interrupt handlers */ | ||
156 | static void setup_received_int(struct usb_ctrlrequest* request); | ||
157 | static void port_change_int(void); | ||
158 | static void reset_int(void); | ||
159 | static void suspend_int(void); | ||
160 | static void resume_int(void); | ||
161 | |||
162 | /* life cycle */ | ||
163 | static void qh_init(unsigned char ep_num, unsigned char dir, unsigned char ep_type, | ||
164 | unsigned int max_pkt_len, unsigned int zlt, unsigned char mult); | ||
165 | static void td_init(struct dtd* td, void* buffer, uint32_t todo); | ||
166 | static void ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type); | ||
167 | |||
168 | /* helpers for tx/rx */ | ||
169 | static int td_enqueue(struct dtd* td, struct dqh* qh, unsigned int mask); | ||
170 | static int td_wait(struct dtd* td, unsigned int mask); | ||
171 | static int usb_ack(struct usb_ctrlrequest * s, int error); | ||
172 | |||
173 | #endif /*_ARCOTG_DCD_H_*/ | ||
diff --git a/firmware/export/arcotg_udc.h b/firmware/export/arcotg_udc.h index e3bf93a52e..e016321b37 100644 --- a/firmware/export/arcotg_udc.h +++ b/firmware/export/arcotg_udc.h | |||
@@ -37,8 +37,6 @@ | |||
37 | 37 | ||
38 | #include "cpu.h" | 38 | #include "cpu.h" |
39 | 39 | ||
40 | #define ETIMEDOUT 1 | ||
41 | |||
42 | #define USB_MAX_ENDPOINTS 8 | 40 | #define USB_MAX_ENDPOINTS 8 |
43 | #define USB_MAX_PIPES (USB_MAX_ENDPOINTS*2) | 41 | #define USB_MAX_PIPES (USB_MAX_ENDPOINTS*2) |
44 | #define USB_MAX_CTRL_PAYLOAD 64 | 42 | #define USB_MAX_CTRL_PAYLOAD 64 |
@@ -99,7 +97,7 @@ | |||
99 | #define USB_FRINDEX_MASKS (0x3fff) | 97 | #define USB_FRINDEX_MASKS (0x3fff) |
100 | 98 | ||
101 | /* USB CMD Register Bit Masks */ | 99 | /* USB CMD Register Bit Masks */ |
102 | #define USB_CMD_RUN_STOP (0x00000001) | 100 | #define USB_CMD_RUN (0x00000001) |
103 | #define USB_CMD_CTRL_RESET (0x00000002) | 101 | #define USB_CMD_CTRL_RESET (0x00000002) |
104 | #define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010) | 102 | #define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010) |
105 | #define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020) | 103 | #define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020) |
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h index 5a23b276eb..453faf5b33 100644 --- a/firmware/export/config-e200.h +++ b/firmware/export/config-e200.h | |||
@@ -148,6 +148,8 @@ | |||
148 | #define FIRMWARE_OFFSET_FILE_DATA 0x8 | 148 | #define FIRMWARE_OFFSET_FILE_DATA 0x8 |
149 | 149 | ||
150 | /* #define USB_IPODSTYLE */ | 150 | /* #define USB_IPODSTYLE */ |
151 | #define HAVE_USBSTACK | ||
152 | #define USBSTACK_CAPS CONTROLLER_DEVICE | ||
151 | 153 | ||
152 | /* USB On-the-go */ | 154 | /* USB On-the-go */ |
153 | #define CONFIG_USBOTG USBOTG_ARC | 155 | #define CONFIG_USBOTG USBOTG_ARC |
diff --git a/firmware/export/linkedlist.h b/firmware/export/linkedlist.h new file mode 100644 index 0000000000..299c2f2c85 --- /dev/null +++ b/firmware/export/linkedlist.h | |||
@@ -0,0 +1,710 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: adc.h 13174 2007-04-15 23:35:56Z amiconn $ | ||
9 | * | ||
10 | * Copyright (C) by Linux Kernel Developers | ||
11 | * | ||
12 | * Original source can be found in linux kernel: <kernel>/include/list.h | ||
13 | * | ||
14 | * All files in this archive are subject to the GNU General Public License. | ||
15 | * See the file COPYING in the source tree root for full license agreement. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef _LINKED_LIST_H_ | ||
23 | #define _LINKED_LIST_H_ | ||
24 | |||
25 | #include <stddef.h> /* used for offsetof */ | ||
26 | |||
27 | static inline void prefetch(const void *x) { (void)x; } | ||
28 | |||
29 | /* | ||
30 | * Simple doubly linked list implementation. | ||
31 | * | ||
32 | * Some of the internal functions ("__xxx") are useful when | ||
33 | * manipulating whole lists rather than single entries, as | ||
34 | * sometimes we already know the next/prev entries and we can | ||
35 | * generate better code by using them directly rather than | ||
36 | * using the generic single-entry routines. | ||
37 | */ | ||
38 | |||
39 | /* TODO move this macro? */ | ||
40 | /* more about this macro: http://www.kroah.com/log/linux/container_of.html */ | ||
41 | #define container_of(ptr, type, member) ({ \ | ||
42 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | ||
43 | (type *)( (char *)__mptr - offsetof(type,member) );}) | ||
44 | |||
45 | /* | ||
46 | * These are non-NULL pointers that will result in page faults | ||
47 | * under normal circumstances, used to verify that nobody uses | ||
48 | * non-initialized list entries. | ||
49 | */ | ||
50 | #define LIST_POISON1 ((void *) 0x00100100) | ||
51 | #define LIST_POISON2 ((void *) 0x00200200) | ||
52 | |||
53 | struct list_head { | ||
54 | struct list_head *next, *prev; | ||
55 | }; | ||
56 | |||
57 | #define LIST_HEAD_INIT(name) { &(name), &(name) } | ||
58 | |||
59 | #define LIST_HEAD(name) \ | ||
60 | struct list_head name = LIST_HEAD_INIT(name) | ||
61 | |||
62 | static inline void INIT_LIST_HEAD(struct list_head *list) | ||
63 | { | ||
64 | list->next = list; | ||
65 | list->prev = list; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Insert a new entry between two known consecutive entries. | ||
70 | * | ||
71 | * This is only for internal list manipulation where we know | ||
72 | * the prev/next entries already! | ||
73 | */ | ||
74 | static inline void __list_add(struct list_head *new, | ||
75 | struct list_head *prev, | ||
76 | struct list_head *next) | ||
77 | { | ||
78 | next->prev = new; | ||
79 | new->next = next; | ||
80 | new->prev = prev; | ||
81 | prev->next = new; | ||
82 | } | ||
83 | |||
84 | |||
85 | /** | ||
86 | * list_add - add a new entry | ||
87 | * @new: new entry to be added | ||
88 | * @head: list head to add it after | ||
89 | * | ||
90 | * Insert a new entry after the specified head. | ||
91 | * This is good for implementing stacks. | ||
92 | */ | ||
93 | static inline void list_add(struct list_head *new, struct list_head *head) | ||
94 | { | ||
95 | __list_add(new, head, head->next); | ||
96 | } | ||
97 | |||
98 | |||
99 | /** | ||
100 | * list_add_tail - add a new entry | ||
101 | * @new: new entry to be added | ||
102 | * @head: list head to add it before | ||
103 | * | ||
104 | * Insert a new entry before the specified head. | ||
105 | * This is useful for implementing queues. | ||
106 | */ | ||
107 | static inline void list_add_tail(struct list_head *new, struct list_head *head) | ||
108 | { | ||
109 | __list_add(new, head->prev, head); | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Delete a list entry by making the prev/next entries | ||
114 | * point to each other. | ||
115 | * | ||
116 | * This is only for internal list manipulation where we know | ||
117 | * the prev/next entries already! | ||
118 | */ | ||
119 | static inline void __list_del(struct list_head * prev, struct list_head * next) | ||
120 | { | ||
121 | next->prev = prev; | ||
122 | prev->next = next; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * list_del - deletes entry from list. | ||
127 | * @entry: the element to delete from the list. | ||
128 | * Note: list_empty() on entry does not return true after this, the entry is | ||
129 | * in an undefined state. | ||
130 | */ | ||
131 | static inline void list_del(struct list_head *entry) | ||
132 | { | ||
133 | __list_del(entry->prev, entry->next); | ||
134 | entry->next = LIST_POISON1; | ||
135 | entry->prev = LIST_POISON2; | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * list_replace - replace old entry by new one | ||
140 | * @old : the element to be replaced | ||
141 | * @new : the new element to insert | ||
142 | * | ||
143 | * If @old was empty, it will be overwritten. | ||
144 | */ | ||
145 | static inline void list_replace(struct list_head *old, | ||
146 | struct list_head *new) | ||
147 | { | ||
148 | new->next = old->next; | ||
149 | new->next->prev = new; | ||
150 | new->prev = old->prev; | ||
151 | new->prev->next = new; | ||
152 | } | ||
153 | |||
154 | static inline void list_replace_init(struct list_head *old, | ||
155 | struct list_head *new) | ||
156 | { | ||
157 | list_replace(old, new); | ||
158 | INIT_LIST_HEAD(old); | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * list_del_init - deletes entry from list and reinitialize it. | ||
163 | * @entry: the element to delete from the list. | ||
164 | */ | ||
165 | static inline void list_del_init(struct list_head *entry) | ||
166 | { | ||
167 | __list_del(entry->prev, entry->next); | ||
168 | INIT_LIST_HEAD(entry); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * list_move - delete from one list and add as another's head | ||
173 | * @list: the entry to move | ||
174 | * @head: the head that will precede our entry | ||
175 | */ | ||
176 | static inline void list_move(struct list_head *list, struct list_head *head) | ||
177 | { | ||
178 | __list_del(list->prev, list->next); | ||
179 | list_add(list, head); | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * list_move_tail - delete from one list and add as another's tail | ||
184 | * @list: the entry to move | ||
185 | * @head: the head that will follow our entry | ||
186 | */ | ||
187 | static inline void list_move_tail(struct list_head *list, | ||
188 | struct list_head *head) | ||
189 | { | ||
190 | __list_del(list->prev, list->next); | ||
191 | list_add_tail(list, head); | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * list_is_last - tests whether @list is the last entry in list @head | ||
196 | * @list: the entry to test | ||
197 | * @head: the head of the list | ||
198 | */ | ||
199 | static inline int list_is_last(const struct list_head *list, | ||
200 | const struct list_head *head) | ||
201 | { | ||
202 | return list->next == head; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * list_empty - tests whether a list is empty | ||
207 | * @head: the list to test. | ||
208 | */ | ||
209 | static inline int list_empty(const struct list_head *head) | ||
210 | { | ||
211 | return head->next == head; | ||
212 | } | ||
213 | |||
214 | static inline void __list_splice(struct list_head *list, | ||
215 | struct list_head *head) | ||
216 | { | ||
217 | struct list_head *first = list->next; | ||
218 | struct list_head *last = list->prev; | ||
219 | struct list_head *at = head->next; | ||
220 | |||
221 | first->prev = head; | ||
222 | head->next = first; | ||
223 | |||
224 | last->next = at; | ||
225 | at->prev = last; | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * list_splice - join two lists | ||
230 | * @list: the new list to add. | ||
231 | * @head: the place to add it in the first list. | ||
232 | */ | ||
233 | static inline void list_splice(struct list_head *list, struct list_head *head) | ||
234 | { | ||
235 | if (!list_empty(list)) { | ||
236 | __list_splice(list, head); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * list_splice_init - join two lists and reinitialise the emptied list. | ||
242 | * @list: the new list to add. | ||
243 | * @head: the place to add it in the first list. | ||
244 | * | ||
245 | * The list at @list is reinitialised | ||
246 | */ | ||
247 | static inline void list_splice_init(struct list_head *list, | ||
248 | struct list_head *head) | ||
249 | { | ||
250 | if (!list_empty(list)) { | ||
251 | __list_splice(list, head); | ||
252 | INIT_LIST_HEAD(list); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * list_entry - get the struct for this entry | ||
258 | * @ptr: the &struct list_head pointer. | ||
259 | * @type: the type of the struct this is embedded in. | ||
260 | * @member: the name of the list_struct within the struct. | ||
261 | */ | ||
262 | #define list_entry(ptr, type, member) \ | ||
263 | container_of(ptr, type, member) | ||
264 | |||
265 | /** | ||
266 | * list_for_each - iterate over a list | ||
267 | * @pos: the &struct list_head to use as a loop cursor. | ||
268 | * @head: the head for your list. | ||
269 | */ | ||
270 | #define list_for_each(pos, head) \ | ||
271 | for (pos = (head)->next; prefetch(pos->next), pos != (head); \ | ||
272 | pos = pos->next) | ||
273 | |||
274 | /** | ||
275 | * __list_for_each - iterate over a list | ||
276 | * @pos: the &struct list_head to use as a loop cursor. | ||
277 | * @head: the head for your list. | ||
278 | * | ||
279 | * This variant differs from list_for_each() in that it's the | ||
280 | * simplest possible list iteration code, no prefetching is done. | ||
281 | * Use this for code that knows the list to be very short (empty | ||
282 | * or 1 entry) most of the time. | ||
283 | */ | ||
284 | #define __list_for_each(pos, head) \ | ||
285 | for (pos = (head)->next; pos != (head); pos = pos->next) | ||
286 | |||
287 | /** | ||
288 | * list_for_each_prev - iterate over a list backwards | ||
289 | * @pos: the &struct list_head to use as a loop cursor. | ||
290 | * @head: the head for your list. | ||
291 | */ | ||
292 | #define list_for_each_prev(pos, head) \ | ||
293 | for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ | ||
294 | pos = pos->prev) | ||
295 | |||
296 | /** | ||
297 | * list_for_each_entry - iterate over list of given type | ||
298 | * @pos: the type * to use as a loop cursor. | ||
299 | * @head: the head for your list. | ||
300 | * @member: the name of the list_struct within the struct. | ||
301 | */ | ||
302 | #define list_for_each_entry(pos, head, member) \ | ||
303 | for (pos = list_entry((head)->next, typeof(*pos), member); \ | ||
304 | prefetch(pos->member.next), &pos->member != (head); \ | ||
305 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
306 | |||
307 | /** | ||
308 | * list_for_each_entry_reverse - iterate backwards over list of given type. | ||
309 | * @pos: the type * to use as a loop cursor. | ||
310 | * @head: the head for your list. | ||
311 | * @member: the name of the list_struct within the struct. | ||
312 | */ | ||
313 | #define list_for_each_entry_reverse(pos, head, member) \ | ||
314 | for (pos = list_entry((head)->prev, typeof(*pos), member); \ | ||
315 | prefetch(pos->member.prev), &pos->member != (head); \ | ||
316 | pos = list_entry(pos->member.prev, typeof(*pos), member)) | ||
317 | |||
318 | /** | ||
319 | * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() | ||
320 | * @pos: the type * to use as a start point | ||
321 | * @head: the head of the list | ||
322 | * @member: the name of the list_struct within the struct. | ||
323 | * | ||
324 | * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). | ||
325 | */ | ||
326 | #define list_prepare_entry(pos, head, member) \ | ||
327 | ((pos) ? : list_entry(head, typeof(*pos), member)) | ||
328 | |||
329 | /** | ||
330 | * list_for_each_entry_continue - continue iteration over list of given type | ||
331 | * @pos: the type * to use as a loop cursor. | ||
332 | * @head: the head for your list. | ||
333 | * @member: the name of the list_struct within the struct. | ||
334 | * | ||
335 | * Continue to iterate over list of given type, continuing after | ||
336 | * the current position. | ||
337 | */ | ||
338 | #define list_for_each_entry_continue(pos, head, member) \ | ||
339 | for (pos = list_entry(pos->member.next, typeof(*pos), member); \ | ||
340 | prefetch(pos->member.next), &pos->member != (head); \ | ||
341 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
342 | |||
343 | /** | ||
344 | * list_for_each_entry_from - iterate over list of given type from the current point | ||
345 | * @pos: the type * to use as a loop cursor. | ||
346 | * @head: the head for your list. | ||
347 | * @member: the name of the list_struct within the struct. | ||
348 | * | ||
349 | * Iterate over list of given type, continuing from current position. | ||
350 | */ | ||
351 | #define list_for_each_entry_from(pos, head, member) \ | ||
352 | for (; prefetch(pos->member.next), &pos->member != (head); \ | ||
353 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
354 | |||
355 | #endif /*_LINKED_LIST_H_*/ | ||
356 | /*************************************************************************** | ||
357 | * __________ __ ___. | ||
358 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
359 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
360 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
361 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
362 | * \/ \/ \/ \/ \/ | ||
363 | * $Id: adc.h 13174 2007-04-15 23:35:56Z amiconn $ | ||
364 | * | ||
365 | * Copyright (C) by Linux Kernel Developers | ||
366 | * | ||
367 | * Original source can be found in linux kernel: <kernel>/include/list.h | ||
368 | * | ||
369 | * All files in this archive are subject to the GNU General Public License. | ||
370 | * See the file COPYING in the source tree root for full license agreement. | ||
371 | * | ||
372 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
373 | * KIND, either express or implied. | ||
374 | * | ||
375 | ****************************************************************************/ | ||
376 | |||
377 | #ifndef _LINKED_LIST_H_ | ||
378 | #define _LINKED_LIST_H_ | ||
379 | |||
380 | #include <stddef.h> /* used for offsetof */ | ||
381 | |||
382 | static inline void prefetch(const void *x) { (void)x; } | ||
383 | |||
384 | /* | ||
385 | * Simple doubly linked list implementation. | ||
386 | * | ||
387 | * Some of the internal functions ("__xxx") are useful when | ||
388 | * manipulating whole lists rather than single entries, as | ||
389 | * sometimes we already know the next/prev entries and we can | ||
390 | * generate better code by using them directly rather than | ||
391 | * using the generic single-entry routines. | ||
392 | */ | ||
393 | |||
394 | /* TODO move this macro? */ | ||
395 | /* more about this macro: http://www.kroah.com/log/linux/container_of.html */ | ||
396 | #define container_of(ptr, type, member) ({ \ | ||
397 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | ||
398 | (type *)( (char *)__mptr - offsetof(type,member) );}) | ||
399 | |||
400 | /* | ||
401 | * These are non-NULL pointers that will result in page faults | ||
402 | * under normal circumstances, used to verify that nobody uses | ||
403 | * non-initialized list entries. | ||
404 | */ | ||
405 | #define LIST_POISON1 ((void *) 0x00100100) | ||
406 | #define LIST_POISON2 ((void *) 0x00200200) | ||
407 | |||
408 | struct list_head { | ||
409 | struct list_head *next, *prev; | ||
410 | }; | ||
411 | |||
412 | #define LIST_HEAD_INIT(name) { &(name), &(name) } | ||
413 | |||
414 | #define LIST_HEAD(name) \ | ||
415 | struct list_head name = LIST_HEAD_INIT(name) | ||
416 | |||
417 | static inline void INIT_LIST_HEAD(struct list_head *list) | ||
418 | { | ||
419 | list->next = list; | ||
420 | list->prev = list; | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * Insert a new entry between two known consecutive entries. | ||
425 | * | ||
426 | * This is only for internal list manipulation where we know | ||
427 | * the prev/next entries already! | ||
428 | */ | ||
429 | static inline void __list_add(struct list_head *new, | ||
430 | struct list_head *prev, | ||
431 | struct list_head *next) | ||
432 | { | ||
433 | next->prev = new; | ||
434 | new->next = next; | ||
435 | new->prev = prev; | ||
436 | prev->next = new; | ||
437 | } | ||
438 | |||
439 | |||
440 | /** | ||
441 | * list_add - add a new entry | ||
442 | * @new: new entry to be added | ||
443 | * @head: list head to add it after | ||
444 | * | ||
445 | * Insert a new entry after the specified head. | ||
446 | * This is good for implementing stacks. | ||
447 | */ | ||
448 | static inline void list_add(struct list_head *new, struct list_head *head) | ||
449 | { | ||
450 | __list_add(new, head, head->next); | ||
451 | } | ||
452 | |||
453 | |||
454 | /** | ||
455 | * list_add_tail - add a new entry | ||
456 | * @new: new entry to be added | ||
457 | * @head: list head to add it before | ||
458 | * | ||
459 | * Insert a new entry before the specified head. | ||
460 | * This is useful for implementing queues. | ||
461 | */ | ||
462 | static inline void list_add_tail(struct list_head *new, struct list_head *head) | ||
463 | { | ||
464 | __list_add(new, head->prev, head); | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * Delete a list entry by making the prev/next entries | ||
469 | * point to each other. | ||
470 | * | ||
471 | * This is only for internal list manipulation where we know | ||
472 | * the prev/next entries already! | ||
473 | */ | ||
474 | static inline void __list_del(struct list_head * prev, struct list_head * next) | ||
475 | { | ||
476 | next->prev = prev; | ||
477 | prev->next = next; | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * list_del - deletes entry from list. | ||
482 | * @entry: the element to delete from the list. | ||
483 | * Note: list_empty() on entry does not return true after this, the entry is | ||
484 | * in an undefined state. | ||
485 | */ | ||
486 | static inline void list_del(struct list_head *entry) | ||
487 | { | ||
488 | __list_del(entry->prev, entry->next); | ||
489 | entry->next = LIST_POISON1; | ||
490 | entry->prev = LIST_POISON2; | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * list_replace - replace old entry by new one | ||
495 | * @old : the element to be replaced | ||
496 | * @new : the new element to insert | ||
497 | * | ||
498 | * If @old was empty, it will be overwritten. | ||
499 | */ | ||
500 | static inline void list_replace(struct list_head *old, | ||
501 | struct list_head *new) | ||
502 | { | ||
503 | new->next = old->next; | ||
504 | new->next->prev = new; | ||
505 | new->prev = old->prev; | ||
506 | new->prev->next = new; | ||
507 | } | ||
508 | |||
509 | static inline void list_replace_init(struct list_head *old, | ||
510 | struct list_head *new) | ||
511 | { | ||
512 | list_replace(old, new); | ||
513 | INIT_LIST_HEAD(old); | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * list_del_init - deletes entry from list and reinitialize it. | ||
518 | * @entry: the element to delete from the list. | ||
519 | */ | ||
520 | static inline void list_del_init(struct list_head *entry) | ||
521 | { | ||
522 | __list_del(entry->prev, entry->next); | ||
523 | INIT_LIST_HEAD(entry); | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * list_move - delete from one list and add as another's head | ||
528 | * @list: the entry to move | ||
529 | * @head: the head that will precede our entry | ||
530 | */ | ||
531 | static inline void list_move(struct list_head *list, struct list_head *head) | ||
532 | { | ||
533 | __list_del(list->prev, list->next); | ||
534 | list_add(list, head); | ||
535 | } | ||
536 | |||
537 | /** | ||
538 | * list_move_tail - delete from one list and add as another's tail | ||
539 | * @list: the entry to move | ||
540 | * @head: the head that will follow our entry | ||
541 | */ | ||
542 | static inline void list_move_tail(struct list_head *list, | ||
543 | struct list_head *head) | ||
544 | { | ||
545 | __list_del(list->prev, list->next); | ||
546 | list_add_tail(list, head); | ||
547 | } | ||
548 | |||
549 | /** | ||
550 | * list_is_last - tests whether @list is the last entry in list @head | ||
551 | * @list: the entry to test | ||
552 | * @head: the head of the list | ||
553 | */ | ||
554 | static inline int list_is_last(const struct list_head *list, | ||
555 | const struct list_head *head) | ||
556 | { | ||
557 | return list->next == head; | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * list_empty - tests whether a list is empty | ||
562 | * @head: the list to test. | ||
563 | */ | ||
564 | static inline int list_empty(const struct list_head *head) | ||
565 | { | ||
566 | return head->next == head; | ||
567 | } | ||
568 | |||
569 | static inline void __list_splice(struct list_head *list, | ||
570 | struct list_head *head) | ||
571 | { | ||
572 | struct list_head *first = list->next; | ||
573 | struct list_head *last = list->prev; | ||
574 | struct list_head *at = head->next; | ||
575 | |||
576 | first->prev = head; | ||
577 | head->next = first; | ||
578 | |||
579 | last->next = at; | ||
580 | at->prev = last; | ||
581 | } | ||
582 | |||
583 | /** | ||
584 | * list_splice - join two lists | ||
585 | * @list: the new list to add. | ||
586 | * @head: the place to add it in the first list. | ||
587 | */ | ||
588 | static inline void list_splice(struct list_head *list, struct list_head *head) | ||
589 | { | ||
590 | if (!list_empty(list)) { | ||
591 | __list_splice(list, head); | ||
592 | } | ||
593 | } | ||
594 | |||
595 | /** | ||
596 | * list_splice_init - join two lists and reinitialise the emptied list. | ||
597 | * @list: the new list to add. | ||
598 | * @head: the place to add it in the first list. | ||
599 | * | ||
600 | * The list at @list is reinitialised | ||
601 | */ | ||
602 | static inline void list_splice_init(struct list_head *list, | ||
603 | struct list_head *head) | ||
604 | { | ||
605 | if (!list_empty(list)) { | ||
606 | __list_splice(list, head); | ||
607 | INIT_LIST_HEAD(list); | ||
608 | } | ||
609 | } | ||
610 | |||
611 | /** | ||
612 | * list_entry - get the struct for this entry | ||
613 | * @ptr: the &struct list_head pointer. | ||
614 | * @type: the type of the struct this is embedded in. | ||
615 | * @member: the name of the list_struct within the struct. | ||
616 | */ | ||
617 | #define list_entry(ptr, type, member) \ | ||
618 | container_of(ptr, type, member) | ||
619 | |||
620 | /** | ||
621 | * list_for_each - iterate over a list | ||
622 | * @pos: the &struct list_head to use as a loop cursor. | ||
623 | * @head: the head for your list. | ||
624 | */ | ||
625 | #define list_for_each(pos, head) \ | ||
626 | for (pos = (head)->next; prefetch(pos->next), pos != (head); \ | ||
627 | pos = pos->next) | ||
628 | |||
629 | /** | ||
630 | * __list_for_each - iterate over a list | ||
631 | * @pos: the &struct list_head to use as a loop cursor. | ||
632 | * @head: the head for your list. | ||
633 | * | ||
634 | * This variant differs from list_for_each() in that it's the | ||
635 | * simplest possible list iteration code, no prefetching is done. | ||
636 | * Use this for code that knows the list to be very short (empty | ||
637 | * or 1 entry) most of the time. | ||
638 | */ | ||
639 | #define __list_for_each(pos, head) \ | ||
640 | for (pos = (head)->next; pos != (head); pos = pos->next) | ||
641 | |||
642 | /** | ||
643 | * list_for_each_prev - iterate over a list backwards | ||
644 | * @pos: the &struct list_head to use as a loop cursor. | ||
645 | * @head: the head for your list. | ||
646 | */ | ||
647 | #define list_for_each_prev(pos, head) \ | ||
648 | for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ | ||
649 | pos = pos->prev) | ||
650 | |||
651 | /** | ||
652 | * list_for_each_entry - iterate over list of given type | ||
653 | * @pos: the type * to use as a loop cursor. | ||
654 | * @head: the head for your list. | ||
655 | * @member: the name of the list_struct within the struct. | ||
656 | */ | ||
657 | #define list_for_each_entry(pos, head, member) \ | ||
658 | for (pos = list_entry((head)->next, typeof(*pos), member); \ | ||
659 | prefetch(pos->member.next), &pos->member != (head); \ | ||
660 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
661 | |||
662 | /** | ||
663 | * list_for_each_entry_reverse - iterate backwards over list of given type. | ||
664 | * @pos: the type * to use as a loop cursor. | ||
665 | * @head: the head for your list. | ||
666 | * @member: the name of the list_struct within the struct. | ||
667 | */ | ||
668 | #define list_for_each_entry_reverse(pos, head, member) \ | ||
669 | for (pos = list_entry((head)->prev, typeof(*pos), member); \ | ||
670 | prefetch(pos->member.prev), &pos->member != (head); \ | ||
671 | pos = list_entry(pos->member.prev, typeof(*pos), member)) | ||
672 | |||
673 | /** | ||
674 | * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() | ||
675 | * @pos: the type * to use as a start point | ||
676 | * @head: the head of the list | ||
677 | * @member: the name of the list_struct within the struct. | ||
678 | * | ||
679 | * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). | ||
680 | */ | ||
681 | #define list_prepare_entry(pos, head, member) \ | ||
682 | ((pos) ? : list_entry(head, typeof(*pos), member)) | ||
683 | |||
684 | /** | ||
685 | * list_for_each_entry_continue - continue iteration over list of given type | ||
686 | * @pos: the type * to use as a loop cursor. | ||
687 | * @head: the head for your list. | ||
688 | * @member: the name of the list_struct within the struct. | ||
689 | * | ||
690 | * Continue to iterate over list of given type, continuing after | ||
691 | * the current position. | ||
692 | */ | ||
693 | #define list_for_each_entry_continue(pos, head, member) \ | ||
694 | for (pos = list_entry(pos->member.next, typeof(*pos), member); \ | ||
695 | prefetch(pos->member.next), &pos->member != (head); \ | ||
696 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
697 | |||
698 | /** | ||
699 | * list_for_each_entry_from - iterate over list of given type from the current point | ||
700 | * @pos: the type * to use as a loop cursor. | ||
701 | * @head: the head for your list. | ||
702 | * @member: the name of the list_struct within the struct. | ||
703 | * | ||
704 | * Iterate over list of given type, continuing from current position. | ||
705 | */ | ||
706 | #define list_for_each_entry_from(pos, head, member) \ | ||
707 | for (; prefetch(pos->member.next), &pos->member != (head); \ | ||
708 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
709 | |||
710 | #endif /*_LINKED_LIST_H_*/ | ||
diff --git a/firmware/export/usb_ch9.h b/firmware/export/usb_ch9.h new file mode 100644 index 0000000000..5784ff3242 --- /dev/null +++ b/firmware/export/usb_ch9.h | |||
@@ -0,0 +1,762 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) by Linux Kernel Developers | ||
11 | * | ||
12 | * Based on code from the Linux Kernel | ||
13 | * available at http://www.kernel.org | ||
14 | * Original file: <kernel>/include/linux/usb/ch9.h | ||
15 | * | ||
16 | * All files in this archive are subject to the GNU General Public License. | ||
17 | * See the file COPYING in the source tree root for full license agreement. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #ifndef _CH9_H_ | ||
25 | #define _CH9_H_ | ||
26 | |||
27 | #include <inttypes.h> | ||
28 | |||
29 | /* | ||
30 | * USB directions | ||
31 | * | ||
32 | * This bit flag is used in endpoint descriptors' bEndpointAddress field. | ||
33 | * It's also one of three fields in control requests bRequestType. | ||
34 | */ | ||
35 | #define USB_DIR_OUT 0 /* to device */ | ||
36 | #define USB_DIR_IN 0x80 /* to host */ | ||
37 | |||
38 | /* | ||
39 | * USB types, the second of three bRequestType fields | ||
40 | */ | ||
41 | #define USB_TYPE_MASK (0x03 << 5) | ||
42 | #define USB_TYPE_STANDARD (0x00 << 5) | ||
43 | #define USB_TYPE_CLASS (0x01 << 5) | ||
44 | #define USB_TYPE_VENDOR (0x02 << 5) | ||
45 | #define USB_TYPE_RESERVED (0x03 << 5) | ||
46 | |||
47 | /* | ||
48 | * USB recipients, the third of three bRequestType fields | ||
49 | */ | ||
50 | #define USB_RECIP_MASK 0x1f | ||
51 | #define USB_RECIP_DEVICE 0x00 | ||
52 | #define USB_RECIP_INTERFACE 0x01 | ||
53 | #define USB_RECIP_ENDPOINT 0x02 | ||
54 | #define USB_RECIP_OTHER 0x03 | ||
55 | |||
56 | /*-------------------------------------------------------------------------*/ | ||
57 | |||
58 | /** | ||
59 | * struct usb_ctrlrequest - SETUP data for a USB device control request | ||
60 | * @bRequestType: matches the USB bmRequestType field | ||
61 | * @bRequest: matches the USB bRequest field | ||
62 | * @wValue: matches the USB wValue field (le16 byte order) | ||
63 | * @wIndex: matches the USB wIndex field (le16 byte order) | ||
64 | * @wLength: matches the USB wLength field (le16 byte order) | ||
65 | */ | ||
66 | struct usb_ctrlrequest { | ||
67 | uint8_t bRequestType; | ||
68 | uint8_t bRequest; | ||
69 | uint16_t wValue; | ||
70 | uint16_t wIndex; | ||
71 | uint16_t wLength; | ||
72 | } __attribute__ ((packed)); | ||
73 | |||
74 | /* | ||
75 | * Standard requests, for the bRequest field of a SETUP packet. | ||
76 | * | ||
77 | * These are qualified by the bRequestType field, so that for example | ||
78 | * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved | ||
79 | * by a GET_STATUS request. | ||
80 | */ | ||
81 | #define USB_REQ_GET_STATUS 0x00 | ||
82 | #define USB_REQ_CLEAR_FEATURE 0x01 | ||
83 | #define USB_REQ_SET_FEATURE 0x03 | ||
84 | #define USB_REQ_SET_ADDRESS 0x05 | ||
85 | #define USB_REQ_GET_DESCRIPTOR 0x06 | ||
86 | #define USB_REQ_SET_DESCRIPTOR 0x07 | ||
87 | #define USB_REQ_GET_CONFIGURATION 0x08 | ||
88 | #define USB_REQ_SET_CONFIGURATION 0x09 | ||
89 | #define USB_REQ_GET_INTERFACE 0x0A | ||
90 | #define USB_REQ_SET_INTERFACE 0x0B | ||
91 | #define USB_REQ_SYNCH_FRAME 0x0C | ||
92 | |||
93 | /*-------------------------------------------------------------------------*/ | ||
94 | |||
95 | /* | ||
96 | * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or | ||
97 | * (rarely) accepted by SET_DESCRIPTOR. | ||
98 | * | ||
99 | * Note that all multi-byte values here are encoded in little endian | ||
100 | * byte order "on the wire". But when exposed through Linux-USB APIs, | ||
101 | * they've been converted to cpu byte order. | ||
102 | */ | ||
103 | |||
104 | /* | ||
105 | * Descriptor types ... USB 2.0 spec table 9.5 | ||
106 | */ | ||
107 | #define USB_DT_DEVICE 0x01 | ||
108 | #define USB_DT_CONFIG 0x02 | ||
109 | #define USB_DT_STRING 0x03 | ||
110 | #define USB_DT_INTERFACE 0x04 | ||
111 | #define USB_DT_ENDPOINT 0x05 | ||
112 | #define USB_DT_DEVICE_QUALIFIER 0x06 | ||
113 | #define USB_DT_OTHER_SPEED_CONFIG 0x07 | ||
114 | #define USB_DT_INTERFACE_POWER 0x08 | ||
115 | /* these are from a minor usb 2.0 revision (ECN) */ | ||
116 | #define USB_DT_OTG 0x09 | ||
117 | #define USB_DT_DEBUG 0x0a | ||
118 | #define USB_DT_INTERFACE_ASSOCIATION 0x0b | ||
119 | /* these are from the Wireless USB spec */ | ||
120 | #define USB_DT_SECURITY 0x0c | ||
121 | #define USB_DT_KEY 0x0d | ||
122 | #define USB_DT_ENCRYPTION_TYPE 0x0e | ||
123 | #define USB_DT_BOS 0x0f | ||
124 | #define USB_DT_DEVICE_CAPABILITY 0x10 | ||
125 | #define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 | ||
126 | #define USB_DT_WIRE_ADAPTER 0x21 | ||
127 | #define USB_DT_RPIPE 0x22 | ||
128 | |||
129 | /* Conventional codes for class-specific descriptors. The convention is | ||
130 | * defined in the USB "Common Class" Spec (3.11). Individual class specs | ||
131 | * are authoritative for their usage, not the "common class" writeup. | ||
132 | */ | ||
133 | #define USB_DT_CS_DEVICE (USB_TYPE_CLASS | USB_DT_DEVICE) | ||
134 | #define USB_DT_CS_CONFIG (USB_TYPE_CLASS | USB_DT_CONFIG) | ||
135 | #define USB_DT_CS_STRING (USB_TYPE_CLASS | USB_DT_STRING) | ||
136 | #define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE) | ||
137 | #define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT) | ||
138 | |||
139 | /*-------------------------------------------------------------------------*/ | ||
140 | |||
141 | /* USB_DT_DEVICE: Device descriptor */ | ||
142 | struct usb_device_descriptor { | ||
143 | uint8_t bLength; | ||
144 | uint8_t bDescriptorType; | ||
145 | uint16_t bcdUSB; | ||
146 | uint8_t bDeviceClass; | ||
147 | uint8_t bDeviceSubClass; | ||
148 | uint8_t bDeviceProtocol; | ||
149 | uint8_t bMaxPacketSize0; | ||
150 | uint16_t idVendor; | ||
151 | uint16_t idProduct; | ||
152 | uint16_t bcdDevice; | ||
153 | uint8_t iManufacturer; | ||
154 | uint8_t iProduct; | ||
155 | uint8_t iSerialNumber; | ||
156 | uint8_t bNumConfigurations; | ||
157 | } __attribute__ ((packed)); | ||
158 | |||
159 | #define USB_DT_DEVICE_SIZE 18 | ||
160 | |||
161 | /* | ||
162 | * Device and/or Interface Class codes | ||
163 | * as found in bDeviceClass or bInterfaceClass | ||
164 | * and defined by www.usb.org documents | ||
165 | */ | ||
166 | #define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ | ||
167 | #define USB_CLASS_AUDIO 1 | ||
168 | #define USB_CLASS_COMM 2 | ||
169 | #define USB_CLASS_HID 3 | ||
170 | #define USB_CLASS_PHYSICAL 5 | ||
171 | #define USB_CLASS_STILL_IMAGE 6 | ||
172 | #define USB_CLASS_PRINTER 7 | ||
173 | #define USB_CLASS_MASS_STORAGE 8 | ||
174 | #define USB_CLASS_HUB 9 | ||
175 | #define USB_CLASS_CDC_DATA 0x0a | ||
176 | #define USB_CLASS_CSCID 0x0b /* chip+ smart card */ | ||
177 | #define USB_CLASS_CONTENT_SEC 0x0d /* content security */ | ||
178 | #define USB_CLASS_VIDEO 0x0e | ||
179 | #define USB_CLASS_WIRELESS_CONTROLLER 0xe0 | ||
180 | #define USB_CLASS_MISC 0xef | ||
181 | #define USB_CLASS_APP_SPEC 0xfe | ||
182 | #define USB_CLASS_VENDOR_SPEC 0xff | ||
183 | |||
184 | /*-------------------------------------------------------------------------*/ | ||
185 | |||
186 | /* USB_DT_CONFIG: Configuration descriptor information. | ||
187 | * | ||
188 | * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the | ||
189 | * descriptor type is different. Highspeed-capable devices can look | ||
190 | * different depending on what speed they're currently running. Only | ||
191 | * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG | ||
192 | * descriptors. | ||
193 | */ | ||
194 | struct usb_config_descriptor { | ||
195 | uint8_t bLength; | ||
196 | uint8_t bDescriptorType; | ||
197 | uint16_t wTotalLength; | ||
198 | uint8_t bNumInterfaces; | ||
199 | uint8_t bConfigurationValue; | ||
200 | uint8_t iConfiguration; | ||
201 | uint8_t bmAttributes; | ||
202 | uint8_t bMaxPower; | ||
203 | } __attribute__ ((packed)); | ||
204 | |||
205 | #define USB_DT_CONFIG_SIZE 9 | ||
206 | |||
207 | /* from config descriptor bmAttributes */ | ||
208 | #define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ | ||
209 | #define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ | ||
210 | #define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ | ||
211 | #define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */ | ||
212 | |||
213 | /*-------------------------------------------------------------------------*/ | ||
214 | |||
215 | /* USB_DT_STRING: String descriptor */ | ||
216 | struct usb_string_descriptor { | ||
217 | uint8_t bLength; | ||
218 | uint8_t bDescriptorType; | ||
219 | |||
220 | uint16_t wData[1]; /* UTF-16LE encoded */ | ||
221 | } __attribute__ ((packed)); | ||
222 | |||
223 | /* note that "string" zero is special, it holds language codes that | ||
224 | * the device supports, not Unicode characters. | ||
225 | */ | ||
226 | |||
227 | /*-------------------------------------------------------------------------*/ | ||
228 | |||
229 | /* USB_DT_INTERFACE: Interface descriptor */ | ||
230 | struct usb_interface_descriptor { | ||
231 | uint8_t bLength; | ||
232 | uint8_t bDescriptorType; | ||
233 | |||
234 | uint8_t bInterfaceNumber; | ||
235 | uint8_t bAlternateSetting; | ||
236 | uint8_t bNumEndpoints; | ||
237 | uint8_t bInterfaceClass; | ||
238 | uint8_t bInterfaceSubClass; | ||
239 | uint8_t bInterfaceProtocol; | ||
240 | uint8_t iInterface; | ||
241 | } __attribute__ ((packed)); | ||
242 | |||
243 | #define USB_DT_INTERFACE_SIZE 9 | ||
244 | |||
245 | /*-------------------------------------------------------------------------*/ | ||
246 | |||
247 | /* USB_DT_ENDPOINT: Endpoint descriptor */ | ||
248 | struct usb_endpoint_descriptor { | ||
249 | uint8_t bLength; | ||
250 | uint8_t bDescriptorType; | ||
251 | |||
252 | uint8_t bEndpointAddress; | ||
253 | uint8_t bmAttributes; | ||
254 | uint16_t wMaxPacketSize; | ||
255 | uint8_t bInterval; | ||
256 | |||
257 | /* NOTE: these two are _only_ in audio endpoints. */ | ||
258 | /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ | ||
259 | //uint8_t bRefresh; | ||
260 | //uint8_t bSynchAddress; | ||
261 | } __attribute__ ((packed)); | ||
262 | |||
263 | #define USB_DT_ENDPOINT_SIZE 7 | ||
264 | #define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ | ||
265 | |||
266 | /*-------------------------------------------------------------------------*/ | ||
267 | |||
268 | /* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ | ||
269 | struct usb_qualifier_descriptor { | ||
270 | uint8_t bLength; | ||
271 | uint8_t bDescriptorType; | ||
272 | |||
273 | uint16_t bcdUSB; | ||
274 | uint8_t bDeviceClass; | ||
275 | uint8_t bDeviceSubClass; | ||
276 | uint8_t bDeviceProtocol; | ||
277 | uint8_t bMaxPacketSize0; | ||
278 | uint8_t bNumConfigurations; | ||
279 | uint8_t bRESERVED; | ||
280 | } __attribute__ ((packed)); | ||
281 | |||
282 | /*-------------------------------------------------------------------------*/ | ||
283 | |||
284 | /* USB_DT_OTG (from OTG 1.0a supplement) */ | ||
285 | struct usb_otg_descriptor { | ||
286 | uint8_t bLength; | ||
287 | uint8_t bDescriptorType; | ||
288 | |||
289 | uint8_t bmAttributes; /* support for HNP, SRP, etc */ | ||
290 | } __attribute__ ((packed)); | ||
291 | |||
292 | /* from usb_otg_descriptor.bmAttributes */ | ||
293 | #define USB_OTG_SRP (1 << 0) | ||
294 | #define USB_OTG_HNP (1 << 1) /* swap host/device roles */ | ||
295 | |||
296 | /*-------------------------------------------------------------------------*/ | ||
297 | |||
298 | /* USB_DT_DEBUG: for special highspeed devices, replacing serial console */ | ||
299 | struct usb_debug_descriptor { | ||
300 | uint8_t bLength; | ||
301 | uint8_t bDescriptorType; | ||
302 | |||
303 | /* bulk endpoints with 8 byte maxpacket */ | ||
304 | uint8_t bDebugInEndpoint; | ||
305 | uint8_t bDebugOutEndpoint; | ||
306 | }; | ||
307 | |||
308 | /*-------------------------------------------------------------------------*/ | ||
309 | |||
310 | /* | ||
311 | * Endpoints | ||
312 | */ | ||
313 | #define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ | ||
314 | #define USB_ENDPOINT_XFER_CONTROL 0 | ||
315 | #define USB_ENDPOINT_XFER_ISOC 1 | ||
316 | #define USB_ENDPOINT_XFER_BULK 2 | ||
317 | #define USB_ENDPOINT_XFER_INT 3 | ||
318 | |||
319 | enum usb_device_speed { | ||
320 | USB_SPEED_UNKNOWN = 0, /* enumerating */ | ||
321 | USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ | ||
322 | USB_SPEED_HIGH, /* usb 2.0 */ | ||
323 | USB_SPEED_VARIABLE, /* wireless (usb 2.5) */ | ||
324 | }; | ||
325 | |||
326 | enum usb_device_state { | ||
327 | /* NOTATTACHED isn't in the USB spec, and this state acts | ||
328 | * the same as ATTACHED ... but it's clearer this way. | ||
329 | */ | ||
330 | USB_STATE_NOTATTACHED = 0, | ||
331 | |||
332 | /* chapter 9 and authentication (wireless) device states */ | ||
333 | USB_STATE_ATTACHED, | ||
334 | USB_STATE_POWERED, /* wired */ | ||
335 | USB_STATE_UNAUTHENTICATED, /* auth */ | ||
336 | USB_STATE_RECONNECTING, /* auth */ | ||
337 | USB_STATE_DEFAULT, /* limited function */ | ||
338 | USB_STATE_ADDRESS, | ||
339 | USB_STATE_CONFIGURED, /* most functions */ | ||
340 | |||
341 | USB_STATE_SUSPENDED | ||
342 | |||
343 | /* NOTE: there are actually four different SUSPENDED | ||
344 | * states, returning to POWERED, DEFAULT, ADDRESS, or | ||
345 | * CONFIGURED respectively when SOF tokens flow again. | ||
346 | */ | ||
347 | }; | ||
348 | |||
349 | /* All standard descriptors have these 2 fields at the beginning */ | ||
350 | struct usb_descriptor_header { | ||
351 | uint8_t bLength; | ||
352 | uint8_t bDescriptorType; | ||
353 | } __attribute__ ((packed)); | ||
354 | |||
355 | /** | ||
356 | * struct usb_string - wraps a C string and its USB id | ||
357 | * @id:the (nonzero) ID for this string | ||
358 | * @s:the string, in UTF-8 encoding | ||
359 | * | ||
360 | * If you're using usb_gadget_get_string(), use this to wrap a string | ||
361 | * together with its ID. | ||
362 | */ | ||
363 | struct usb_string { | ||
364 | uint8_t id; | ||
365 | const char* s; | ||
366 | }; | ||
367 | |||
368 | /** | ||
369 | * struct usb_gadget_strings - a set of USB strings in a given language | ||
370 | * @language:identifies the strings' language (0x0409 for en-us) | ||
371 | * @strings:array of strings with their ids | ||
372 | * | ||
373 | * If you're using usb_gadget_get_string(), use this to wrap all the | ||
374 | * strings for a given language. | ||
375 | */ | ||
376 | struct usb_gadget_strings { | ||
377 | uint16_t language; /* 0x0409 for en-us */ | ||
378 | struct usb_string* strings; | ||
379 | }; | ||
380 | |||
381 | #endif /*_CH9_H_*/ | ||
382 | /*************************************************************************** | ||
383 | * __________ __ ___. | ||
384 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
385 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
386 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
387 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
388 | * \/ \/ \/ \/ \/ | ||
389 | * $Id: $ | ||
390 | * | ||
391 | * Copyright (C) by Linux Kernel Developers | ||
392 | * | ||
393 | * Based on code from the Linux Kernel | ||
394 | * available at http://www.kernel.org | ||
395 | * Original file: <kernel>/include/linux/usb/ch9.h | ||
396 | * | ||
397 | * All files in this archive are subject to the GNU General Public License. | ||
398 | * See the file COPYING in the source tree root for full license agreement. | ||
399 | * | ||
400 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
401 | * KIND, either express or implied. | ||
402 | * | ||
403 | ****************************************************************************/ | ||
404 | |||
405 | #ifndef _CH9_H_ | ||
406 | #define _CH9_H_ | ||
407 | |||
408 | #include <inttypes.h> | ||
409 | |||
410 | /* | ||
411 | * USB directions | ||
412 | * | ||
413 | * This bit flag is used in endpoint descriptors' bEndpointAddress field. | ||
414 | * It's also one of three fields in control requests bRequestType. | ||
415 | */ | ||
416 | #define USB_DIR_OUT 0 /* to device */ | ||
417 | #define USB_DIR_IN 0x80 /* to host */ | ||
418 | |||
419 | /* | ||
420 | * USB types, the second of three bRequestType fields | ||
421 | */ | ||
422 | #define USB_TYPE_MASK (0x03 << 5) | ||
423 | #define USB_TYPE_STANDARD (0x00 << 5) | ||
424 | #define USB_TYPE_CLASS (0x01 << 5) | ||
425 | #define USB_TYPE_VENDOR (0x02 << 5) | ||
426 | #define USB_TYPE_RESERVED (0x03 << 5) | ||
427 | |||
428 | /* | ||
429 | * USB recipients, the third of three bRequestType fields | ||
430 | */ | ||
431 | #define USB_RECIP_MASK 0x1f | ||
432 | #define USB_RECIP_DEVICE 0x00 | ||
433 | #define USB_RECIP_INTERFACE 0x01 | ||
434 | #define USB_RECIP_ENDPOINT 0x02 | ||
435 | #define USB_RECIP_OTHER 0x03 | ||
436 | |||
437 | /*-------------------------------------------------------------------------*/ | ||
438 | |||
439 | /** | ||
440 | * struct usb_ctrlrequest - SETUP data for a USB device control request | ||
441 | * @bRequestType: matches the USB bmRequestType field | ||
442 | * @bRequest: matches the USB bRequest field | ||
443 | * @wValue: matches the USB wValue field (le16 byte order) | ||
444 | * @wIndex: matches the USB wIndex field (le16 byte order) | ||
445 | * @wLength: matches the USB wLength field (le16 byte order) | ||
446 | */ | ||
447 | struct usb_ctrlrequest { | ||
448 | uint8_t bRequestType; | ||
449 | uint8_t bRequest; | ||
450 | uint16_t wValue; | ||
451 | uint16_t wIndex; | ||
452 | uint16_t wLength; | ||
453 | } __attribute__ ((packed)); | ||
454 | |||
455 | /* | ||
456 | * Standard requests, for the bRequest field of a SETUP packet. | ||
457 | * | ||
458 | * These are qualified by the bRequestType field, so that for example | ||
459 | * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved | ||
460 | * by a GET_STATUS request. | ||
461 | */ | ||
462 | #define USB_REQ_GET_STATUS 0x00 | ||
463 | #define USB_REQ_CLEAR_FEATURE 0x01 | ||
464 | #define USB_REQ_SET_FEATURE 0x03 | ||
465 | #define USB_REQ_SET_ADDRESS 0x05 | ||
466 | #define USB_REQ_GET_DESCRIPTOR 0x06 | ||
467 | #define USB_REQ_SET_DESCRIPTOR 0x07 | ||
468 | #define USB_REQ_GET_CONFIGURATION 0x08 | ||
469 | #define USB_REQ_SET_CONFIGURATION 0x09 | ||
470 | #define USB_REQ_GET_INTERFACE 0x0A | ||
471 | #define USB_REQ_SET_INTERFACE 0x0B | ||
472 | #define USB_REQ_SYNCH_FRAME 0x0C | ||
473 | |||
474 | /*-------------------------------------------------------------------------*/ | ||
475 | |||
476 | /* | ||
477 | * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or | ||
478 | * (rarely) accepted by SET_DESCRIPTOR. | ||
479 | * | ||
480 | * Note that all multi-byte values here are encoded in little endian | ||
481 | * byte order "on the wire". But when exposed through Linux-USB APIs, | ||
482 | * they've been converted to cpu byte order. | ||
483 | */ | ||
484 | |||
485 | /* | ||
486 | * Descriptor types ... USB 2.0 spec table 9.5 | ||
487 | */ | ||
488 | #define USB_DT_DEVICE 0x01 | ||
489 | #define USB_DT_CONFIG 0x02 | ||
490 | #define USB_DT_STRING 0x03 | ||
491 | #define USB_DT_INTERFACE 0x04 | ||
492 | #define USB_DT_ENDPOINT 0x05 | ||
493 | #define USB_DT_DEVICE_QUALIFIER 0x06 | ||
494 | #define USB_DT_OTHER_SPEED_CONFIG 0x07 | ||
495 | #define USB_DT_INTERFACE_POWER 0x08 | ||
496 | /* these are from a minor usb 2.0 revision (ECN) */ | ||
497 | #define USB_DT_OTG 0x09 | ||
498 | #define USB_DT_DEBUG 0x0a | ||
499 | #define USB_DT_INTERFACE_ASSOCIATION 0x0b | ||
500 | /* these are from the Wireless USB spec */ | ||
501 | #define USB_DT_SECURITY 0x0c | ||
502 | #define USB_DT_KEY 0x0d | ||
503 | #define USB_DT_ENCRYPTION_TYPE 0x0e | ||
504 | #define USB_DT_BOS 0x0f | ||
505 | #define USB_DT_DEVICE_CAPABILITY 0x10 | ||
506 | #define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 | ||
507 | #define USB_DT_WIRE_ADAPTER 0x21 | ||
508 | #define USB_DT_RPIPE 0x22 | ||
509 | |||
510 | /* Conventional codes for class-specific descriptors. The convention is | ||
511 | * defined in the USB "Common Class" Spec (3.11). Individual class specs | ||
512 | * are authoritative for their usage, not the "common class" writeup. | ||
513 | */ | ||
514 | #define USB_DT_CS_DEVICE (USB_TYPE_CLASS | USB_DT_DEVICE) | ||
515 | #define USB_DT_CS_CONFIG (USB_TYPE_CLASS | USB_DT_CONFIG) | ||
516 | #define USB_DT_CS_STRING (USB_TYPE_CLASS | USB_DT_STRING) | ||
517 | #define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE) | ||
518 | #define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT) | ||
519 | |||
520 | /*-------------------------------------------------------------------------*/ | ||
521 | |||
522 | /* USB_DT_DEVICE: Device descriptor */ | ||
523 | struct usb_device_descriptor { | ||
524 | uint8_t bLength; | ||
525 | uint8_t bDescriptorType; | ||
526 | uint16_t bcdUSB; | ||
527 | uint8_t bDeviceClass; | ||
528 | uint8_t bDeviceSubClass; | ||
529 | uint8_t bDeviceProtocol; | ||
530 | uint8_t bMaxPacketSize0; | ||
531 | uint16_t idVendor; | ||
532 | uint16_t idProduct; | ||
533 | uint16_t bcdDevice; | ||
534 | uint8_t iManufacturer; | ||
535 | uint8_t iProduct; | ||
536 | uint8_t iSerialNumber; | ||
537 | uint8_t bNumConfigurations; | ||
538 | } __attribute__ ((packed)); | ||
539 | |||
540 | #define USB_DT_DEVICE_SIZE 18 | ||
541 | |||
542 | /* | ||
543 | * Device and/or Interface Class codes | ||
544 | * as found in bDeviceClass or bInterfaceClass | ||
545 | * and defined by www.usb.org documents | ||
546 | */ | ||
547 | #define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ | ||
548 | #define USB_CLASS_AUDIO 1 | ||
549 | #define USB_CLASS_COMM 2 | ||
550 | #define USB_CLASS_HID 3 | ||
551 | #define USB_CLASS_PHYSICAL 5 | ||
552 | #define USB_CLASS_STILL_IMAGE 6 | ||
553 | #define USB_CLASS_PRINTER 7 | ||
554 | #define USB_CLASS_MASS_STORAGE 8 | ||
555 | #define USB_CLASS_HUB 9 | ||
556 | #define USB_CLASS_CDC_DATA 0x0a | ||
557 | #define USB_CLASS_CSCID 0x0b /* chip+ smart card */ | ||
558 | #define USB_CLASS_CONTENT_SEC 0x0d /* content security */ | ||
559 | #define USB_CLASS_VIDEO 0x0e | ||
560 | #define USB_CLASS_WIRELESS_CONTROLLER 0xe0 | ||
561 | #define USB_CLASS_MISC 0xef | ||
562 | #define USB_CLASS_APP_SPEC 0xfe | ||
563 | #define USB_CLASS_VENDOR_SPEC 0xff | ||
564 | |||
565 | /*-------------------------------------------------------------------------*/ | ||
566 | |||
567 | /* USB_DT_CONFIG: Configuration descriptor information. | ||
568 | * | ||
569 | * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the | ||
570 | * descriptor type is different. Highspeed-capable devices can look | ||
571 | * different depending on what speed they're currently running. Only | ||
572 | * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG | ||
573 | * descriptors. | ||
574 | */ | ||
575 | struct usb_config_descriptor { | ||
576 | uint8_t bLength; | ||
577 | uint8_t bDescriptorType; | ||
578 | uint16_t wTotalLength; | ||
579 | uint8_t bNumInterfaces; | ||
580 | uint8_t bConfigurationValue; | ||
581 | uint8_t iConfiguration; | ||
582 | uint8_t bmAttributes; | ||
583 | uint8_t bMaxPower; | ||
584 | } __attribute__ ((packed)); | ||
585 | |||
586 | #define USB_DT_CONFIG_SIZE 9 | ||
587 | |||
588 | /* from config descriptor bmAttributes */ | ||
589 | #define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ | ||
590 | #define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ | ||
591 | #define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ | ||
592 | #define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */ | ||
593 | |||
594 | /*-------------------------------------------------------------------------*/ | ||
595 | |||
596 | /* USB_DT_STRING: String descriptor */ | ||
597 | struct usb_string_descriptor { | ||
598 | uint8_t bLength; | ||
599 | uint8_t bDescriptorType; | ||
600 | |||
601 | uint16_t wData[1]; /* UTF-16LE encoded */ | ||
602 | } __attribute__ ((packed)); | ||
603 | |||
604 | /* note that "string" zero is special, it holds language codes that | ||
605 | * the device supports, not Unicode characters. | ||
606 | */ | ||
607 | |||
608 | /*-------------------------------------------------------------------------*/ | ||
609 | |||
610 | /* USB_DT_INTERFACE: Interface descriptor */ | ||
611 | struct usb_interface_descriptor { | ||
612 | uint8_t bLength; | ||
613 | uint8_t bDescriptorType; | ||
614 | |||
615 | uint8_t bInterfaceNumber; | ||
616 | uint8_t bAlternateSetting; | ||
617 | uint8_t bNumEndpoints; | ||
618 | uint8_t bInterfaceClass; | ||
619 | uint8_t bInterfaceSubClass; | ||
620 | uint8_t bInterfaceProtocol; | ||
621 | uint8_t iInterface; | ||
622 | } __attribute__ ((packed)); | ||
623 | |||
624 | #define USB_DT_INTERFACE_SIZE 9 | ||
625 | |||
626 | /*-------------------------------------------------------------------------*/ | ||
627 | |||
628 | /* USB_DT_ENDPOINT: Endpoint descriptor */ | ||
629 | struct usb_endpoint_descriptor { | ||
630 | uint8_t bLength; | ||
631 | uint8_t bDescriptorType; | ||
632 | |||
633 | uint8_t bEndpointAddress; | ||
634 | uint8_t bmAttributes; | ||
635 | uint16_t wMaxPacketSize; | ||
636 | uint8_t bInterval; | ||
637 | |||
638 | /* NOTE: these two are _only_ in audio endpoints. */ | ||
639 | /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ | ||
640 | //uint8_t bRefresh; | ||
641 | //uint8_t bSynchAddress; | ||
642 | } __attribute__ ((packed)); | ||
643 | |||
644 | #define USB_DT_ENDPOINT_SIZE 7 | ||
645 | #define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ | ||
646 | |||
647 | /*-------------------------------------------------------------------------*/ | ||
648 | |||
649 | /* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ | ||
650 | struct usb_qualifier_descriptor { | ||
651 | uint8_t bLength; | ||
652 | uint8_t bDescriptorType; | ||
653 | |||
654 | uint16_t bcdUSB; | ||
655 | uint8_t bDeviceClass; | ||
656 | uint8_t bDeviceSubClass; | ||
657 | uint8_t bDeviceProtocol; | ||
658 | uint8_t bMaxPacketSize0; | ||
659 | uint8_t bNumConfigurations; | ||
660 | uint8_t bRESERVED; | ||
661 | } __attribute__ ((packed)); | ||
662 | |||
663 | /*-------------------------------------------------------------------------*/ | ||
664 | |||
665 | /* USB_DT_OTG (from OTG 1.0a supplement) */ | ||
666 | struct usb_otg_descriptor { | ||
667 | uint8_t bLength; | ||
668 | uint8_t bDescriptorType; | ||
669 | |||
670 | uint8_t bmAttributes; /* support for HNP, SRP, etc */ | ||
671 | } __attribute__ ((packed)); | ||
672 | |||
673 | /* from usb_otg_descriptor.bmAttributes */ | ||
674 | #define USB_OTG_SRP (1 << 0) | ||
675 | #define USB_OTG_HNP (1 << 1) /* swap host/device roles */ | ||
676 | |||
677 | /*-------------------------------------------------------------------------*/ | ||
678 | |||
679 | /* USB_DT_DEBUG: for special highspeed devices, replacing serial console */ | ||
680 | struct usb_debug_descriptor { | ||
681 | uint8_t bLength; | ||
682 | uint8_t bDescriptorType; | ||
683 | |||
684 | /* bulk endpoints with 8 byte maxpacket */ | ||
685 | uint8_t bDebugInEndpoint; | ||
686 | uint8_t bDebugOutEndpoint; | ||
687 | }; | ||
688 | |||
689 | /*-------------------------------------------------------------------------*/ | ||
690 | |||
691 | /* | ||
692 | * Endpoints | ||
693 | */ | ||
694 | #define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ | ||
695 | #define USB_ENDPOINT_XFER_CONTROL 0 | ||
696 | #define USB_ENDPOINT_XFER_ISOC 1 | ||
697 | #define USB_ENDPOINT_XFER_BULK 2 | ||
698 | #define USB_ENDPOINT_XFER_INT 3 | ||
699 | |||
700 | enum usb_device_speed { | ||
701 | USB_SPEED_UNKNOWN = 0, /* enumerating */ | ||
702 | USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ | ||
703 | USB_SPEED_HIGH, /* usb 2.0 */ | ||
704 | USB_SPEED_VARIABLE, /* wireless (usb 2.5) */ | ||
705 | }; | ||
706 | |||
707 | enum usb_device_state { | ||
708 | /* NOTATTACHED isn't in the USB spec, and this state acts | ||
709 | * the same as ATTACHED ... but it's clearer this way. | ||
710 | */ | ||
711 | USB_STATE_NOTATTACHED = 0, | ||
712 | |||
713 | /* chapter 9 and authentication (wireless) device states */ | ||
714 | USB_STATE_ATTACHED, | ||
715 | USB_STATE_POWERED, /* wired */ | ||
716 | USB_STATE_UNAUTHENTICATED, /* auth */ | ||
717 | USB_STATE_RECONNECTING, /* auth */ | ||
718 | USB_STATE_DEFAULT, /* limited function */ | ||
719 | USB_STATE_ADDRESS, | ||
720 | USB_STATE_CONFIGURED, /* most functions */ | ||
721 | |||
722 | USB_STATE_SUSPENDED | ||
723 | |||
724 | /* NOTE: there are actually four different SUSPENDED | ||
725 | * states, returning to POWERED, DEFAULT, ADDRESS, or | ||
726 | * CONFIGURED respectively when SOF tokens flow again. | ||
727 | */ | ||
728 | }; | ||
729 | |||
730 | /* All standard descriptors have these 2 fields at the beginning */ | ||
731 | struct usb_descriptor_header { | ||
732 | uint8_t bLength; | ||
733 | uint8_t bDescriptorType; | ||
734 | } __attribute__ ((packed)); | ||
735 | |||
736 | /** | ||
737 | * struct usb_string - wraps a C string and its USB id | ||
738 | * @id:the (nonzero) ID for this string | ||
739 | * @s:the string, in UTF-8 encoding | ||
740 | * | ||
741 | * If you're using usb_gadget_get_string(), use this to wrap a string | ||
742 | * together with its ID. | ||
743 | */ | ||
744 | struct usb_string { | ||
745 | uint8_t id; | ||
746 | const char* s; | ||
747 | }; | ||
748 | |||
749 | /** | ||
750 | * struct usb_gadget_strings - a set of USB strings in a given language | ||
751 | * @language:identifies the strings' language (0x0409 for en-us) | ||
752 | * @strings:array of strings with their ids | ||
753 | * | ||
754 | * If you're using usb_gadget_get_string(), use this to wrap all the | ||
755 | * strings for a given language. | ||
756 | */ | ||
757 | struct usb_gadget_strings { | ||
758 | uint16_t language; /* 0x0409 for en-us */ | ||
759 | struct usb_string* strings; | ||
760 | }; | ||
761 | |||
762 | #endif /*_CH9_H_*/ | ||
diff --git a/firmware/export/usbstack.h b/firmware/export/usbstack.h new file mode 100644 index 0000000000..9142b1bdba --- /dev/null +++ b/firmware/export/usbstack.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef _USBSTACK_H_ | ||
21 | #define _USBSTACK_H_ | ||
22 | |||
23 | #include <errno.h> | ||
24 | |||
25 | #define USB_STACK_MAX_SETTINGS_NAME 32*10 /* should be enough for > 10 driver names */ | ||
26 | |||
27 | /* | ||
28 | * error codes | ||
29 | */ | ||
30 | #define ENOFREESLOT 1 | ||
31 | #define EWRONGCONTROLLERTYPE 2 | ||
32 | #define ENODRIVERFOUND 3 | ||
33 | #define EHWCRITICAL 4 | ||
34 | |||
35 | enum usb_controller_type { | ||
36 | DEVICE = 0, | ||
37 | HOST, | ||
38 | }; | ||
39 | |||
40 | /* | ||
41 | * stack routines | ||
42 | */ | ||
43 | void usb_stack_init(void); | ||
44 | void usb_stack_start(void); | ||
45 | void usb_stack_stop(void); | ||
46 | |||
47 | void usb_controller_select(int type); | ||
48 | int usb_stack_get_mode(void); | ||
49 | int usb_device_driver_bind(const char* name); | ||
50 | void ubs_device_driver_unbind(void); | ||
51 | |||
52 | /* used by apps settings code */ | ||
53 | unsigned char device_driver_names[USB_STACK_MAX_SETTINGS_NAME]; | ||
54 | |||
55 | #endif /*_USBSTACK_H_*/ | ||
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c index 98ee78b0ff..a282564d19 100644 --- a/firmware/target/arm/system-pp502x.c +++ b/firmware/target/arm/system-pp502x.c | |||
@@ -35,13 +35,20 @@ extern void clickwheel_int(void); | |||
35 | extern void microsd_int(void); | 35 | extern void microsd_int(void); |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #ifdef HAVE_USBSTACK | ||
39 | #include "usbstack/core.h" | ||
40 | #endif | ||
41 | |||
38 | void irq(void) | 42 | void irq(void) |
39 | { | 43 | { |
40 | if(CURRENT_CORE == CPU) | 44 | if(CURRENT_CORE == CPU) |
41 | { | 45 | { |
42 | if (CPU_INT_STAT & TIMER1_MASK) | 46 | if (CPU_INT_STAT & TIMER1_MASK) { |
43 | TIMER1(); | 47 | TIMER1(); |
44 | else if (CPU_INT_STAT & TIMER2_MASK) | 48 | #ifdef HAVE_USBSTACK |
49 | usb_stack_irq(); | ||
50 | #endif | ||
51 | } else if (CPU_INT_STAT & TIMER2_MASK) | ||
45 | TIMER2(); | 52 | TIMER2(); |
46 | #if defined(IPOD_MINI) /* Mini 1st gen only, mini 2nd gen uses iPod 4G code */ | 53 | #if defined(IPOD_MINI) /* Mini 1st gen only, mini 2nd gen uses iPod 4G code */ |
47 | else if (CPU_HI_INT_STAT & GPIO_MASK) | 54 | else if (CPU_HI_INT_STAT & GPIO_MASK) |
diff --git a/firmware/target/arm/usb-fw-pp502x.c b/firmware/target/arm/usb-fw-pp502x.c index 92e3dee562..f687782447 100644 --- a/firmware/target/arm/usb-fw-pp502x.c +++ b/firmware/target/arm/usb-fw-pp502x.c | |||
@@ -22,71 +22,16 @@ | |||
22 | * | 22 | * |
23 | ****************************************************************************/ | 23 | ****************************************************************************/ |
24 | #include "config.h" | 24 | #include "config.h" |
25 | #include "cpu.h" | ||
26 | #include "kernel.h" | ||
27 | #include "thread.h" | ||
28 | #include "system.h" | 25 | #include "system.h" |
29 | #include "debug.h" | ||
30 | #include "ata.h" | ||
31 | #include "fat.h" | ||
32 | #include "disk.h" | ||
33 | #include "panic.h" | ||
34 | #include "lcd.h" | ||
35 | #include "adc.h" | ||
36 | #include "usb.h" | 26 | #include "usb.h" |
37 | #include "button.h" | ||
38 | #include "sprintf.h" | ||
39 | #include "string.h" | ||
40 | #include "hwcompat.h" | ||
41 | |||
42 | #include "usb-target.h" | ||
43 | #include "arcotg_udc.h" | 27 | #include "arcotg_udc.h" |
44 | 28 | ||
29 | #ifdef HAVE_USBSTACK | ||
30 | #include "usbstack.h" | ||
31 | #endif | ||
32 | |||
45 | void usb_init_device(void) | 33 | void usb_init_device(void) |
46 | { | 34 | { |
47 | int r0; | ||
48 | outl(inl(0x70000084) | 0x200, 0x70000084); | ||
49 | |||
50 | outl(inl(0x7000002C) | 0x3000000, 0x7000002C); | ||
51 | DEV_EN |= DEV_USB; | ||
52 | |||
53 | DEV_RS |= DEV_USB; /* reset usb start */ | ||
54 | DEV_RS &=~DEV_USB;/* reset usb end */ | ||
55 | |||
56 | DEV_INIT |= INIT_USB; | ||
57 | while ((inl(0x70000028) & 0x80) == 0); | ||
58 | |||
59 | UDC_PORTSC1 |= PORTSCX_PORT_RESET; | ||
60 | while ((UDC_PORTSC1 & PORTSCX_PORT_RESET) != 0); | ||
61 | |||
62 | UDC_OTGSC |= 0x5F000000; | ||
63 | if( (UDC_OTGSC & 0x100) == 0) { | ||
64 | UDC_USBMODE &=~ USB_MODE_CTRL_MODE_HOST; | ||
65 | UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE; | ||
66 | outl(inl(0x70000028) | 0x4000, 0x70000028); | ||
67 | outl(inl(0x70000028) | 0x2, 0x70000028); | ||
68 | } else { | ||
69 | UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE; | ||
70 | outl(inl(0x70000028) &~0x4000, 0x70000028); | ||
71 | outl(inl(0x70000028) | 0x2, 0x70000028); | ||
72 | } | ||
73 | |||
74 | |||
75 | UDC_USBCMD |= USB_CMD_CTRL_RESET; | ||
76 | while((UDC_USBCMD & USB_CMD_CTRL_RESET) != 0); | ||
77 | |||
78 | r0 = UDC_PORTSC1; | ||
79 | |||
80 | /* Note from IPL source (referring to next 5 lines of code: | ||
81 | THIS NEEDS TO BE CHANGED ONCE THERE IS KERNEL USB */ | ||
82 | DEV_INIT |= INIT_USB; | ||
83 | DEV_EN |= DEV_USB; | ||
84 | while ((inl(0x70000028) & 0x80) == 0); | ||
85 | outl(inl(0x70000028) | 0x2, 0x70000028); | ||
86 | |||
87 | udelay(0x186A0); | ||
88 | |||
89 | dr_controller_setup(); | ||
90 | 35 | ||
91 | #if defined(IPOD_COLOR) || defined(IPOD_4G) \ | 36 | #if defined(IPOD_COLOR) || defined(IPOD_4G) \ |
92 | || defined(IPOD_MINI) || defined(IPOD_MINI2G) | 37 | || defined(IPOD_MINI) || defined(IPOD_MINI2G) |
@@ -98,6 +43,7 @@ void usb_init_device(void) | |||
98 | 43 | ||
99 | void usb_enable(bool on) | 44 | void usb_enable(bool on) |
100 | { | 45 | { |
46 | #ifndef HAVE_USBSTACK | ||
101 | /* This device specific code will eventually give way to proper USB | 47 | /* This device specific code will eventually give way to proper USB |
102 | handling, which should be the same for all PP502x targets. */ | 48 | handling, which should be the same for all PP502x targets. */ |
103 | if (on) | 49 | if (on) |
@@ -125,6 +71,7 @@ void usb_enable(bool on) | |||
125 | } | 71 | } |
126 | #endif | 72 | #endif |
127 | } | 73 | } |
74 | #endif | ||
128 | } | 75 | } |
129 | 76 | ||
130 | bool usb_detect(void) | 77 | bool usb_detect(void) |
@@ -151,12 +98,13 @@ bool usb_detect(void) | |||
151 | } | 98 | } |
152 | 99 | ||
153 | usbstatus1 = (UDC_OTGSC & 0x800) ? true : false; | 100 | usbstatus1 = (UDC_OTGSC & 0x800) ? true : false; |
101 | #ifdef HAVE_USBSTACK | ||
154 | if ((usbstatus1 == true) && (prev_usbstatus1 == false)) { | 102 | if ((usbstatus1 == true) && (prev_usbstatus1 == false)) { |
155 | dr_controller_run(); | 103 | usb_stack_start(); |
156 | } else if ((usbstatus1 == false) && (prev_usbstatus1 == true)) { | 104 | } else if ((usbstatus1 == false) && (prev_usbstatus1 == true)) { |
157 | dr_controller_stop(); | 105 | usb_stack_stop(); |
158 | } | 106 | } |
159 | 107 | #endif | |
160 | prev_usbstatus1 = usbstatus1; | 108 | prev_usbstatus1 = usbstatus1; |
161 | usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false; | 109 | usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false; |
162 | 110 | ||
diff --git a/firmware/usbstack/config.h b/firmware/usbstack/config.h new file mode 100644 index 0000000000..95b00da1b3 --- /dev/null +++ b/firmware/usbstack/config.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef _USBSTACK_CONFIG_H_ | ||
21 | #define _USBSTACK_CONFIG_H_ | ||
22 | |||
23 | /* default: use no controller */ | ||
24 | #ifndef USBSTACK_CAPS | ||
25 | #define USBSTACK_CAPS 0 | ||
26 | #endif | ||
27 | |||
28 | #define CONTROLLER_DEVICE (1 << 0) | ||
29 | #define CONTROLLER_HOST (1 << 1) | ||
30 | |||
31 | #endif /*_USBSTACK_CONFIG_H_*/ | ||
diff --git a/firmware/usbstack/controller.h b/firmware/usbstack/controller.h new file mode 100644 index 0000000000..8e99cf6641 --- /dev/null +++ b/firmware/usbstack/controller.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef _USBSTACK_CONTROLLER_H_ | ||
21 | #define _USBSTACK_CONTROLLER_H_ | ||
22 | |||
23 | struct usb_controller { | ||
24 | const char* name; | ||
25 | enum usb_controller_type type; | ||
26 | enum usb_device_speed speed; | ||
27 | void (*init)(void); | ||
28 | void (*shutdown)(void); | ||
29 | void (*irq)(void); | ||
30 | void (*start)(void); | ||
31 | void (*stop)(void); | ||
32 | void* controller_ops; | ||
33 | struct usb_device_driver* device_driver; | ||
34 | struct usb_host_driver* host_driver; | ||
35 | struct usb_ep* ep0; | ||
36 | struct usb_ep endpoints; | ||
37 | }; | ||
38 | |||
39 | struct usb_dcd_controller_ops { | ||
40 | /* endpoint management */ | ||
41 | int (*enable)(struct usb_ep* ep); | ||
42 | int (*disable)(struct usb_ep* ep); | ||
43 | int (*set_halt)(struct usb_ep* ep, bool hald); | ||
44 | |||
45 | /* transmitting */ | ||
46 | int (*send)(struct usb_ep* ep, struct usb_response* req); | ||
47 | int (*receive)(struct usb_ep* ep, struct usb_response* res); | ||
48 | |||
49 | /* ep0 */ | ||
50 | struct usb_ep* ep0; | ||
51 | }; | ||
52 | |||
53 | int usb_controller_register(struct usb_controller* ctrl); | ||
54 | int usb_controller_unregister(struct usb_controller* ctrl); | ||
55 | |||
56 | /* | ||
57 | * dcd - device controller driver | ||
58 | */ | ||
59 | void usb_dcd_init(void); | ||
60 | void usb_dcd_shutdown(void); | ||
61 | |||
62 | /* | ||
63 | * hcd - host controller driver | ||
64 | */ | ||
65 | void usb_hcd_init(void); | ||
66 | void usb_hcd_shutdown(void); | ||
67 | |||
68 | #endif /*_USBSTACK_CONTROLLER_H_*/ | ||
diff --git a/firmware/usbstack/core.h b/firmware/usbstack/core.h new file mode 100644 index 0000000000..7bda2934e7 --- /dev/null +++ b/firmware/usbstack/core.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef _USBSTACK_CORE_H_ | ||
21 | #define _USBSTACK_CORE_H_ | ||
22 | |||
23 | #include "linkedlist.h" | ||
24 | #include "usb_ch9.h" | ||
25 | #include "logf.h" | ||
26 | #include "system.h" | ||
27 | |||
28 | #include "usbstack.h" | ||
29 | |||
30 | /* | ||
31 | * stack datatypes | ||
32 | */ | ||
33 | struct usb_response { | ||
34 | void* buf; | ||
35 | uint32_t length; | ||
36 | }; | ||
37 | |||
38 | struct usb_ep { | ||
39 | const char name[15]; | ||
40 | uint8_t type; | ||
41 | uint32_t ep_num; /* which endpoint? */ | ||
42 | uint32_t pipe_num; /* which pipe? */ | ||
43 | uint32_t maxpacket; | ||
44 | bool claimed; | ||
45 | |||
46 | struct usb_endpoint_descriptor *desc; | ||
47 | struct list_head list; | ||
48 | }; | ||
49 | |||
50 | #include "usbstack/controller.h" | ||
51 | #include "usbstack/device.h" | ||
52 | #include "usbstack/host.h" | ||
53 | |||
54 | #define NUM_DRIVERS 3 | ||
55 | |||
56 | /* | ||
57 | * usb core | ||
58 | */ | ||
59 | struct usb_core { | ||
60 | /* we can have maximum two controllers (one device, one host) */ | ||
61 | struct usb_controller* controller[2]; | ||
62 | struct usb_controller* active_controller; | ||
63 | /* device driver used by stack */ | ||
64 | struct usb_device_driver* device_driver; | ||
65 | /* for each type of driver use own array */ | ||
66 | struct usb_host_driver* host_drivers[NUM_DRIVERS]; | ||
67 | struct usb_device_driver* device_drivers[NUM_DRIVERS]; | ||
68 | enum usb_controller_type mode; | ||
69 | bool running; | ||
70 | }; | ||
71 | |||
72 | void usb_stack_irq(void); | ||
73 | void usb_stack_work(void); | ||
74 | |||
75 | /* endpoint configuration */ | ||
76 | void usb_ep_autoconfig_reset(void); | ||
77 | struct usb_ep* usb_ep_autoconfig(struct usb_endpoint_descriptor* desc); | ||
78 | |||
79 | /* only used for debug */ | ||
80 | void into_usb_ctrlrequest(struct usb_ctrlrequest* request); | ||
81 | |||
82 | extern struct usb_core usbcore; | ||
83 | |||
84 | #endif /*_USBSTACK_CORE_H_*/ | ||
diff --git a/firmware/usbstack/core/config.c b/firmware/usbstack/core/config.c new file mode 100644 index 0000000000..a05a508bf9 --- /dev/null +++ b/firmware/usbstack/core/config.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * Based on linux/drivers/usb/gadget/config.c | ||
13 | * Copyright (C) 2003 David Brownell | ||
14 | * | ||
15 | * All files in this archive are subject to the GNU General Public License. | ||
16 | * See the file COPYING in the source tree root for full license agreement. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | #include <string.h> | ||
24 | #include "usbstack/core.h" | ||
25 | |||
26 | static int usb_descriptor_fillbuf(void* buf, unsigned buflen, struct usb_descriptor_header** src) { | ||
27 | |||
28 | uint8_t* dest = buf; | ||
29 | |||
30 | if (!src) { | ||
31 | return -EINVAL; | ||
32 | } | ||
33 | |||
34 | /* fill buffer from src[] until null descriptor ptr */ | ||
35 | for (; 0 != *src; src++) { | ||
36 | unsigned len = (*src)->bLength; | ||
37 | |||
38 | logf("len: %d", len); | ||
39 | |||
40 | if (len > buflen) | ||
41 | return -EINVAL; | ||
42 | memcpy(dest, *src, len); | ||
43 | buflen -= len; | ||
44 | dest += len; | ||
45 | } | ||
46 | return dest - (uint8_t *)buf; | ||
47 | } | ||
48 | |||
49 | int usb_stack_configdesc(const struct usb_config_descriptor* config, void* buf, unsigned length, struct usb_descriptor_header** desc) { | ||
50 | |||
51 | struct usb_config_descriptor* cp = buf; | ||
52 | int len; | ||
53 | |||
54 | if (length < USB_DT_CONFIG_SIZE || !desc) { | ||
55 | return -EINVAL; | ||
56 | } | ||
57 | |||
58 | /* config descriptor first */ | ||
59 | *cp = *config; | ||
60 | |||
61 | /* then interface/endpoint/class/vendor/... */ | ||
62 | len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (uint8_t*)buf, length - USB_DT_CONFIG_SIZE, desc); | ||
63 | |||
64 | if (len < 0) { | ||
65 | return len; | ||
66 | } | ||
67 | |||
68 | len += USB_DT_CONFIG_SIZE; | ||
69 | if (len > 0xffff) { | ||
70 | return -EINVAL; | ||
71 | } | ||
72 | |||
73 | /* patch up the config descriptor */ | ||
74 | cp->bLength = USB_DT_CONFIG_SIZE; | ||
75 | cp->bDescriptorType = USB_DT_CONFIG; | ||
76 | cp->wTotalLength = len; | ||
77 | cp->bmAttributes |= USB_CONFIG_ATT_ONE; | ||
78 | |||
79 | return len; | ||
80 | } | ||
diff --git a/firmware/usbstack/core/core.c b/firmware/usbstack/core/core.c new file mode 100644 index 0000000000..61b7f83636 --- /dev/null +++ b/firmware/usbstack/core/core.c | |||
@@ -0,0 +1,392 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include <errno.h> | ||
21 | #include <string.h> | ||
22 | #include <ctype.h> | ||
23 | #include "usbstack.h" | ||
24 | |||
25 | #include "config.h" | ||
26 | |||
27 | #include "usbstack/core.h" | ||
28 | #include "usbstack/config.h" | ||
29 | #include "usbstack/controller.h" | ||
30 | #include "usbstack/drivers/device/usb_serial.h" | ||
31 | #include "usbstack/drivers/device/usb_storage.h" | ||
32 | |||
33 | struct usb_core usbcore; | ||
34 | |||
35 | /* private used functions */ | ||
36 | static void update_driver_names(unsigned char* result); | ||
37 | static void bind_device_driver(struct usb_device_driver* driver); | ||
38 | |||
39 | /** | ||
40 | * Initialize usb stack. | ||
41 | */ | ||
42 | void usb_stack_init(void) { | ||
43 | |||
44 | int i; | ||
45 | logf("usb_stack_init"); | ||
46 | |||
47 | /* init datastructures */ | ||
48 | usbcore.controller[0] = NULL; | ||
49 | usbcore.controller[1] = NULL; | ||
50 | usbcore.active_controller = NULL; | ||
51 | usbcore.device_driver = NULL; | ||
52 | usbcore.running = false; | ||
53 | |||
54 | memset(&device_driver_names, 0, USB_STACK_MAX_SETTINGS_NAME); | ||
55 | |||
56 | /* init arrays */ | ||
57 | for (i = 0; i < NUM_DRIVERS; i++) { | ||
58 | usbcore.device_drivers[i] = NULL; | ||
59 | usbcore.host_drivers[i] = NULL; | ||
60 | } | ||
61 | |||
62 | /* init controllers */ | ||
63 | #if (USBSTACK_CAPS & CONTROLLER_DEVICE) | ||
64 | usb_dcd_init(); | ||
65 | #endif | ||
66 | |||
67 | #if (USBSTACK_CAPS & CONTROLLER_HOST) | ||
68 | usb_hcd_init(); | ||
69 | #endif | ||
70 | |||
71 | /* init drivers */ | ||
72 | usb_serial_driver_init(); | ||
73 | usb_storage_driver_init(); | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * Start processing of usb stack. This function init | ||
78 | * active usb controller. | ||
79 | */ | ||
80 | void usb_stack_start(void) { | ||
81 | |||
82 | /* are we allready running? */ | ||
83 | if (usbcore.running) { | ||
84 | logf("allready running!"); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | if (usbcore.active_controller == NULL) { | ||
89 | logf("no active controller!"); | ||
90 | return; | ||
91 | } | ||
92 | |||
93 | /* forward to controller */ | ||
94 | logf("starting controller"); | ||
95 | usbcore.active_controller->start(); | ||
96 | usbcore.running = true; | ||
97 | |||
98 | /* look if started controller is a device controller | ||
99 | * and if it has a device driver bind to it */ | ||
100 | logf("check for auto bind"); | ||
101 | if (usbcore.active_controller->type == DEVICE) { | ||
102 | if (usbcore.active_controller->device_driver == NULL && usbcore.device_driver != NULL) { | ||
103 | /* bind driver */ | ||
104 | logf("binding..."); | ||
105 | bind_device_driver(usbcore.device_driver); | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * Stop processing of usb stack. This function shutsdown | ||
112 | * active usb controller. | ||
113 | */ | ||
114 | void usb_stack_stop(void) { | ||
115 | |||
116 | /* are we allready stopped? */ | ||
117 | if (usbcore.running == false) { | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | /* forward to controller */ | ||
122 | usbcore.active_controller->stop(); | ||
123 | usbcore.running = false; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * Gets called by upper layers to indicate that there is | ||
128 | * an interrupt waiting for the controller. | ||
129 | */ | ||
130 | void usb_stack_irq(void) { | ||
131 | |||
132 | /* simply notify usb controller */ | ||
133 | if (usbcore.active_controller != NULL && usbcore.active_controller->irq != NULL) { | ||
134 | usbcore.active_controller->irq(); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * If a host device controller is loaded, we need to have a function | ||
140 | * to call for maintanence. We need to check if a new device has connected, | ||
141 | * find suitable drivers for new devices. | ||
142 | */ | ||
143 | void usb_stack_work(void) { | ||
144 | /* TODO will be used with host device controllers | ||
145 | * and needs to be called in a loop (thread) */ | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * Register an usb controller in the stack. The stack can | ||
150 | * only have two controllers registered at one time. | ||
151 | * One device host controller and one host device controller. | ||
152 | * | ||
153 | * @param ctrl pointer to controller to register. | ||
154 | * @return 0 on success else a defined error code. | ||
155 | */ | ||
156 | int usb_controller_register(struct usb_controller* ctrl) { | ||
157 | |||
158 | if (ctrl == NULL) { | ||
159 | return EINVAL; | ||
160 | } | ||
161 | |||
162 | logf("usb_stack: register usb ctrl"); | ||
163 | logf(" -> name: %s", ctrl->name); | ||
164 | logf(" -> type: %d", ctrl->type); | ||
165 | |||
166 | switch (ctrl->type) { | ||
167 | case DEVICE: | ||
168 | if (usbcore.controller[0] == NULL) { | ||
169 | usbcore.controller[0] = ctrl; | ||
170 | return 0; | ||
171 | } | ||
172 | break; | ||
173 | case HOST: | ||
174 | if (usbcore.controller[1] == NULL) { | ||
175 | usbcore.controller[1] = ctrl; | ||
176 | return 0; | ||
177 | } | ||
178 | break; | ||
179 | default: | ||
180 | return EINVAL; | ||
181 | } | ||
182 | |||
183 | return ENOFREESLOT; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * Unregister an usb controller from the stack. | ||
188 | * | ||
189 | * @param ctrl pointer to controller to unregister. | ||
190 | * @return 0 on success else a defined error code. | ||
191 | */ | ||
192 | int usb_controller_unregister(struct usb_controller* ctrl) { | ||
193 | |||
194 | if (ctrl == NULL) { | ||
195 | return EINVAL; | ||
196 | } | ||
197 | |||
198 | switch (ctrl->type) { | ||
199 | case DEVICE: | ||
200 | if (usbcore.controller[0] == ctrl) { | ||
201 | usbcore.controller[0] = NULL; | ||
202 | return 0; | ||
203 | } | ||
204 | break; | ||
205 | case HOST: | ||
206 | if (usbcore.controller[1] == ctrl) { | ||
207 | usbcore.controller[1] = NULL; | ||
208 | return 0; | ||
209 | } | ||
210 | break; | ||
211 | default: | ||
212 | return EINVAL; | ||
213 | } | ||
214 | |||
215 | return 0; /* never reached */ | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * Select an usb controller and active it. | ||
220 | * | ||
221 | * @param type of controller to activate. | ||
222 | */ | ||
223 | void usb_controller_select(int type) { | ||
224 | |||
225 | struct usb_controller* new = NULL; | ||
226 | |||
227 | /* check if a controller of the wanted type is already loaded */ | ||
228 | if (usbcore.active_controller != NULL && (int)usbcore.active_controller->type == type) { | ||
229 | logf("controller already set"); | ||
230 | return; | ||
231 | } | ||
232 | |||
233 | logf("usb_controller_select"); | ||
234 | logf(" -> type: %d", type); | ||
235 | |||
236 | usbcore.mode = type; | ||
237 | |||
238 | switch (type) { | ||
239 | case DEVICE: | ||
240 | new = usbcore.controller[0]; | ||
241 | break; | ||
242 | case HOST: | ||
243 | new = usbcore.controller[1]; | ||
244 | break; | ||
245 | } | ||
246 | |||
247 | /* if there is only one controller, stop here */ | ||
248 | if (new == NULL) { | ||
249 | logf("no suitable cntrl found"); | ||
250 | return; | ||
251 | } | ||
252 | |||
253 | /* shutdown current used controller */ | ||
254 | if (usbcore.active_controller != NULL) { | ||
255 | logf("shuting down old one"); | ||
256 | usbcore.active_controller->shutdown(); | ||
257 | } | ||
258 | |||
259 | /* set and init new controller */ | ||
260 | usbcore.active_controller = new; | ||
261 | logf("init controller"); | ||
262 | usbcore.active_controller->init(); | ||
263 | } | ||
264 | |||
265 | int usb_stack_get_mode(void) { | ||
266 | return usbcore.mode; | ||
267 | } | ||
268 | |||
269 | /** | ||
270 | * Register an usb device driver. | ||
271 | * | ||
272 | * @param driver pointer to an usb_device_driver struct. | ||
273 | * @return 0 on success, else a defined error code. | ||
274 | */ | ||
275 | int usb_device_driver_register(struct usb_device_driver* driver) { | ||
276 | |||
277 | int i; | ||
278 | |||
279 | if (driver == NULL) { | ||
280 | return EINVAL; | ||
281 | } | ||
282 | |||
283 | /* add to linked list */ | ||
284 | logf("usb_stack: register usb driver"); | ||
285 | for (i = 0; i < NUM_DRIVERS; i++) { | ||
286 | if (usbcore.device_drivers[i] == NULL) { | ||
287 | usbcore.device_drivers[i] = driver; | ||
288 | update_driver_names(device_driver_names); | ||
289 | return 0; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | update_driver_names(device_driver_names); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | int usb_device_driver_bind(const char* name) { | ||
299 | |||
300 | int i; | ||
301 | struct usb_device_driver *tmp = NULL; | ||
302 | struct usb_device_driver *driver = NULL; | ||
303 | |||
304 | if (name == NULL) { | ||
305 | return EINVAL; | ||
306 | } | ||
307 | |||
308 | /* look for driver */ | ||
309 | logf("looking for driver %s", name); | ||
310 | for (i = 0; i < NUM_DRIVERS; i++) { | ||
311 | tmp = usbcore.device_drivers[i]; | ||
312 | if (tmp != NULL && strcmp(name, tmp->name) == 0) { | ||
313 | driver = tmp; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | if (driver == NULL) { | ||
318 | logf("no driver found"); | ||
319 | return ENODRIVERFOUND; | ||
320 | } | ||
321 | |||
322 | /* look if there is an usb controller loaded */ | ||
323 | if (usbcore.active_controller == NULL) { | ||
324 | /* safe choosen driver and set it when controller starts */ | ||
325 | usbcore.device_driver = driver; | ||
326 | |||
327 | } else { | ||
328 | |||
329 | /* we need to have an active dcd controller */ | ||
330 | if (usbcore.active_controller->type != DEVICE) { | ||
331 | logf("wrong type"); | ||
332 | return EWRONGCONTROLLERTYPE; | ||
333 | } | ||
334 | |||
335 | /* bind driver to controller */ | ||
336 | bind_device_driver(driver); | ||
337 | } | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | void usb_device_driver_unbind(void) { | ||
343 | |||
344 | logf("usb_device_driver_unbind"); | ||
345 | if (usbcore.active_controller->device_driver != NULL) { | ||
346 | usbcore.active_controller->device_driver->unbind(); | ||
347 | usbcore.active_controller->device_driver = NULL; | ||
348 | } | ||
349 | |||
350 | usbcore.device_driver = NULL; | ||
351 | } | ||
352 | |||
353 | static void update_driver_names(unsigned char* result) { | ||
354 | |||
355 | int i; | ||
356 | int pos = 0; | ||
357 | unsigned char terminator = ','; | ||
358 | struct usb_device_driver* dd = NULL; | ||
359 | |||
360 | /* reset buffer, iterate through drivers and add to char array */ | ||
361 | memset(result, 0, USB_STACK_MAX_SETTINGS_NAME); | ||
362 | for (i = 0; i < NUM_DRIVERS; i++) { | ||
363 | int len; | ||
364 | dd = usbcore.device_drivers[i]; | ||
365 | |||
366 | if (dd != NULL) { | ||
367 | len = strlen(dd->name); | ||
368 | if (pos > 0) { | ||
369 | memcpy(result + pos, &terminator, 1); | ||
370 | pos++; | ||
371 | } | ||
372 | memcpy(result + pos, dd->name, len); | ||
373 | pos += len; | ||
374 | } | ||
375 | } | ||
376 | } | ||
377 | |||
378 | static void bind_device_driver(struct usb_device_driver* driver) { | ||
379 | |||
380 | /* look if there is an old driver */ | ||
381 | if (usbcore.active_controller->device_driver != NULL) { | ||
382 | usbcore.active_controller->device_driver->unbind(); | ||
383 | } | ||
384 | |||
385 | /* bind driver to controller */ | ||
386 | usbcore.active_controller->device_driver = driver; | ||
387 | |||
388 | /* init dirver */ | ||
389 | driver->bind(usbcore.active_controller->controller_ops); | ||
390 | } | ||
391 | |||
392 | |||
diff --git a/firmware/usbstack/core/epsetup.c b/firmware/usbstack/core/epsetup.c new file mode 100644 index 0000000000..6ae54fb9ac --- /dev/null +++ b/firmware/usbstack/core/epsetup.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include <string.h> | ||
21 | #include <ctype.h> | ||
22 | #include "usbstack/core.h" | ||
23 | |||
24 | /** | ||
25 | * | ||
26 | * Naming Convention for Endpoint Names | ||
27 | * | ||
28 | * - ep1, ep2, ... address is fixed, not direction or type | ||
29 | * - ep1in, ep2out, ... address and direction are fixed, not type | ||
30 | * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction | ||
31 | * - ep1in-bulk, ep2out-iso, ... all three are fixed | ||
32 | * - ep-* ... no functionality restrictions | ||
33 | * | ||
34 | * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. | ||
35 | * | ||
36 | */ | ||
37 | static int ep_matches(struct usb_ep* ep, struct usb_endpoint_descriptor* desc); | ||
38 | |||
39 | void usb_ep_autoconfig_reset(void) { | ||
40 | |||
41 | struct usb_ep* ep = NULL; | ||
42 | if (usbcore.active_controller == NULL) { | ||
43 | return; | ||
44 | } | ||
45 | |||
46 | logf("resetting endpoints"); | ||
47 | list_for_each_entry(ep, &usbcore.active_controller->endpoints.list, list) { | ||
48 | logf("reset %s", ep->name); | ||
49 | ep->claimed = false; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * Find a suitable endpoint for the requested endpoint descriptor. | ||
55 | * @param desc usb descritpro to use for seraching. | ||
56 | * @return NULL or a valid endpoint. | ||
57 | */ | ||
58 | struct usb_ep* usb_ep_autoconfig(struct usb_endpoint_descriptor* desc) { | ||
59 | |||
60 | struct usb_ep* ep = NULL; | ||
61 | if (usbcore.active_controller == NULL) { | ||
62 | logf("active controller NULL"); | ||
63 | return NULL; | ||
64 | } | ||
65 | |||
66 | list_for_each_entry(ep, &usbcore.active_controller->endpoints.list, list) { | ||
67 | if (ep_matches (ep, desc)) { | ||
68 | return ep; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | return NULL; | ||
73 | } | ||
74 | |||
75 | static int ep_matches(struct usb_ep* ep, struct usb_endpoint_descriptor* desc) { | ||
76 | |||
77 | uint8_t type; | ||
78 | const char* tmp; | ||
79 | uint16_t max; | ||
80 | |||
81 | /* endpoint already claimed? */ | ||
82 | if (ep->claimed) { | ||
83 | logf("!! claimed !!"); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | /* only support ep0 for portable CONTROL traffic */ | ||
88 | type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; | ||
89 | if (type == USB_ENDPOINT_XFER_CONTROL) { | ||
90 | logf("type == control"); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /* some other naming convention */ | ||
95 | if (ep->name[0] != 'e') { | ||
96 | logf("wrong name"); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | /* type-restriction: "-iso", "-bulk", or "-int". | ||
101 | * direction-restriction: "in", "out". | ||
102 | */ | ||
103 | if (ep->name[2] != '-' ) { | ||
104 | tmp = strrchr (ep->name, '-'); | ||
105 | if (tmp) { | ||
106 | switch (type) { | ||
107 | case USB_ENDPOINT_XFER_INT: | ||
108 | /* bulk endpoints handle interrupt transfers, | ||
109 | * except the toggle-quirky iso-synch kind | ||
110 | */ | ||
111 | if (tmp[2] == 's') { // == "-iso" | ||
112 | return 0; | ||
113 | } | ||
114 | break; | ||
115 | case USB_ENDPOINT_XFER_BULK: | ||
116 | if (tmp[1] != 'b') { // != "-bulk" | ||
117 | return 0; | ||
118 | } | ||
119 | break; | ||
120 | case USB_ENDPOINT_XFER_ISOC: | ||
121 | if (tmp[2] != 's') { // != "-iso" | ||
122 | return 0; | ||
123 | } | ||
124 | } | ||
125 | } else { | ||
126 | tmp = ep->name + strlen (ep->name); | ||
127 | } | ||
128 | |||
129 | /* direction-restriction: "..in-..", "out-.." */ | ||
130 | tmp--; | ||
131 | if (!isdigit(*tmp)) { | ||
132 | if (desc->bEndpointAddress & USB_DIR_IN) { | ||
133 | if ('n' != *tmp) { | ||
134 | return 0; | ||
135 | } | ||
136 | } else { | ||
137 | if ('t' != *tmp) { | ||
138 | return 0; | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | /* endpoint maxpacket size is an input parameter, except for bulk | ||
146 | * where it's an output parameter representing the full speed limit. | ||
147 | * the usb spec fixes high speed bulk maxpacket at 512 bytes. | ||
148 | */ | ||
149 | max = 0x7ff & desc->wMaxPacketSize; | ||
150 | |||
151 | switch (type) { | ||
152 | case USB_ENDPOINT_XFER_INT: | ||
153 | /* INT: limit 64 bytes full speed, 1024 high speed */ | ||
154 | if ((usbcore.active_controller->speed != USB_SPEED_HIGH) && (max > 64)) { | ||
155 | return 0; | ||
156 | } | ||
157 | /* FALLTHROUGH */ | ||
158 | |||
159 | case USB_ENDPOINT_XFER_ISOC: | ||
160 | if ((usbcore.active_controller->speed != USB_SPEED_HIGH) && (max > 1023)) { | ||
161 | return 0; | ||
162 | } | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | /* MATCH!! */ | ||
167 | |||
168 | /* report address */ | ||
169 | desc->bEndpointAddress |= ep->ep_num; | ||
170 | |||
171 | /* report (variable) full speed bulk maxpacket */ | ||
172 | if (type == USB_ENDPOINT_XFER_BULK) { | ||
173 | int size = max; | ||
174 | |||
175 | /* min() doesn't work on bitfields with gcc-3.5 */ | ||
176 | if (size > 64) { | ||
177 | size = 64; | ||
178 | } | ||
179 | desc->wMaxPacketSize = size; | ||
180 | } | ||
181 | |||
182 | /* save desc in endpoint */ | ||
183 | ep->desc = desc; | ||
184 | |||
185 | return 1; | ||
186 | } | ||
diff --git a/firmware/usbstack/core/utils.c b/firmware/usbstack/core/utils.c new file mode 100644 index 0000000000..2fb2695732 --- /dev/null +++ b/firmware/usbstack/core/utils.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include <string.h> | ||
21 | #include "usbstack/core.h" | ||
22 | |||
23 | void into_usb_ctrlrequest(struct usb_ctrlrequest* request) { | ||
24 | |||
25 | char* type = ""; | ||
26 | char* req = ""; | ||
27 | char* extra = 0; | ||
28 | |||
29 | logf("-usb request-"); | ||
30 | /* check if packet is okay */ | ||
31 | if (request->bRequestType == 0 && | ||
32 | request->bRequest == 0 && | ||
33 | request->wValue == 0 && | ||
34 | request->wIndex == 0 && | ||
35 | request->wLength == 0) { | ||
36 | logf(" -> INVALID <-"); | ||
37 | return; | ||
38 | } | ||
39 | |||
40 | switch (request->bRequestType & USB_TYPE_MASK) { | ||
41 | case USB_TYPE_STANDARD: | ||
42 | type = "standard"; | ||
43 | |||
44 | switch (request->bRequest) { | ||
45 | case USB_REQ_GET_STATUS: | ||
46 | req = "get status"; | ||
47 | break; | ||
48 | case USB_REQ_CLEAR_FEATURE: | ||
49 | req = "clear feature"; | ||
50 | break; | ||
51 | case USB_REQ_SET_FEATURE: | ||
52 | req = "set feature"; | ||
53 | break; | ||
54 | case USB_REQ_SET_ADDRESS: | ||
55 | req = "set address"; | ||
56 | break; | ||
57 | case USB_REQ_GET_DESCRIPTOR: | ||
58 | req = "get descriptor"; | ||
59 | |||
60 | switch (request->wValue >> 8) { | ||
61 | case USB_DT_DEVICE: | ||
62 | extra = "get device descriptor"; | ||
63 | break; | ||
64 | case USB_DT_DEVICE_QUALIFIER: | ||
65 | extra = "get device qualifier"; | ||
66 | break; | ||
67 | case USB_DT_OTHER_SPEED_CONFIG: | ||
68 | extra = "get other-speed config descriptor"; | ||
69 | case USB_DT_CONFIG: | ||
70 | extra = "get configuration descriptor"; | ||
71 | break; | ||
72 | case USB_DT_STRING: | ||
73 | extra = "get string descriptor"; | ||
74 | break; | ||
75 | case USB_DT_DEBUG: | ||
76 | extra = "debug"; | ||
77 | break; | ||
78 | } | ||
79 | break; | ||
80 | |||
81 | break; | ||
82 | case USB_REQ_SET_DESCRIPTOR: | ||
83 | req = "set descriptor"; | ||
84 | break; | ||
85 | case USB_REQ_GET_CONFIGURATION: | ||
86 | req = "get configuration"; | ||
87 | break; | ||
88 | case USB_REQ_SET_CONFIGURATION: | ||
89 | req = "set configuration"; | ||
90 | break; | ||
91 | case USB_REQ_GET_INTERFACE: | ||
92 | req = "get interface"; | ||
93 | break; | ||
94 | case USB_REQ_SET_INTERFACE: | ||
95 | req = "set interface"; | ||
96 | break; | ||
97 | case USB_REQ_SYNCH_FRAME: | ||
98 | req = "sync frame"; | ||
99 | break; | ||
100 | default: | ||
101 | req = "unkown"; | ||
102 | break; | ||
103 | } | ||
104 | |||
105 | break; | ||
106 | case USB_TYPE_CLASS: | ||
107 | type = "class"; | ||
108 | break; | ||
109 | |||
110 | case USB_TYPE_VENDOR: | ||
111 | type = "vendor"; | ||
112 | break; | ||
113 | } | ||
114 | |||
115 | logf(" -b 0x%x", request->bRequestType); | ||
116 | logf(" -b 0x%x", request->bRequest); | ||
117 | logf(" -b 0x%x", request->wValue); | ||
118 | logf(" -b 0x%x", request->wIndex); | ||
119 | logf(" -b 0x%x", request->wLength); | ||
120 | logf(" -> t: %s", type); | ||
121 | logf(" -> r: %s", req); | ||
122 | if (extra != 0) { | ||
123 | logf(" -> e: %s", extra); | ||
124 | } | ||
125 | } | ||
diff --git a/firmware/usbstack/device.h b/firmware/usbstack/device.h new file mode 100644 index 0000000000..5b385d8129 --- /dev/null +++ b/firmware/usbstack/device.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef _USBSTACK_DEVICE_H_ | ||
21 | #define _USBSTACK_DEVICE_H_ | ||
22 | |||
23 | /* | ||
24 | * usb device driver | ||
25 | */ | ||
26 | struct usb_device_driver { | ||
27 | const char* name; | ||
28 | void (*bind)(void* controller_ops); | ||
29 | void (*unbind)(void); | ||
30 | int (*request)(struct usb_ctrlrequest* req); | ||
31 | void (*suspend)(void); | ||
32 | void (*resume)(void); | ||
33 | void (*speed)(enum usb_device_speed speed); | ||
34 | struct usb_descriptors* descriptors; | ||
35 | void* data; /* used to store controller specific ops struct */ | ||
36 | }; | ||
37 | |||
38 | int usb_device_driver_register(struct usb_device_driver* driver); | ||
39 | |||
40 | /* forward declaration */ | ||
41 | struct usb_config_descriptor; | ||
42 | struct usb_descriptor_header; | ||
43 | |||
44 | int usb_stack_configdesc(const struct usb_config_descriptor* config, | ||
45 | void* buf, unsigned length, | ||
46 | struct usb_descriptor_header** desc); | ||
47 | |||
48 | #endif /*_USBSTACK_DEVICE_H_*/ | ||
diff --git a/firmware/usbstack/drivers/device/usb_serial.c b/firmware/usbstack/drivers/device/usb_serial.c new file mode 100644 index 0000000000..fe1e52f25a --- /dev/null +++ b/firmware/usbstack/drivers/device/usb_serial.c | |||
@@ -0,0 +1,300 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "usb_serial.h" | ||
21 | #include <string.h> | ||
22 | |||
23 | static struct usb_dcd_controller_ops* ops; | ||
24 | |||
25 | struct usb_device_driver usb_serial_driver = { | ||
26 | .name = "serial", | ||
27 | .bind = usb_serial_driver_bind, | ||
28 | .unbind = NULL, | ||
29 | .request = usb_serial_driver_request, | ||
30 | .suspend = NULL, | ||
31 | .resume = NULL, | ||
32 | .speed = usb_serial_driver_speed, | ||
33 | }; | ||
34 | |||
35 | /*-------------------------------------------------------------------------*/ | ||
36 | /* usb descriptors */ | ||
37 | |||
38 | /* TODO: implement strings */ | ||
39 | #define GS_MANUFACTURER_STR_ID 0 | ||
40 | #define GS_PRODUCT_STR_ID 0 | ||
41 | #define GS_SERIAL_STR_ID 0 | ||
42 | #define GS_BULK_CONFIG_STR_ID 0 | ||
43 | #define GS_DATA_STR_ID 0 | ||
44 | |||
45 | #define GS_BULK_CONFIG_ID 1 | ||
46 | |||
47 | static struct usb_device_descriptor serial_device_desc = { | ||
48 | .bLength = USB_DT_DEVICE_SIZE, | ||
49 | .bDescriptorType = USB_DT_DEVICE, | ||
50 | .bcdUSB = 0x0200, | ||
51 | .bDeviceClass = USB_CLASS_COMM, | ||
52 | .bDeviceSubClass = 0, | ||
53 | .bDeviceProtocol = 0, | ||
54 | .idVendor = 0x0525, | ||
55 | .idProduct = 0xa4a6, | ||
56 | .iManufacturer = GS_MANUFACTURER_STR_ID, | ||
57 | .iProduct = GS_PRODUCT_STR_ID, | ||
58 | .iSerialNumber = GS_SERIAL_STR_ID, | ||
59 | .bNumConfigurations = 1, | ||
60 | }; | ||
61 | |||
62 | static struct usb_config_descriptor serial_bulk_config_desc = { | ||
63 | .bLength = USB_DT_CONFIG_SIZE, | ||
64 | .bDescriptorType = USB_DT_CONFIG, | ||
65 | |||
66 | .bNumInterfaces = 1, | ||
67 | .bConfigurationValue = GS_BULK_CONFIG_ID, | ||
68 | .iConfiguration = GS_BULK_CONFIG_STR_ID, | ||
69 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, | ||
70 | .bMaxPower = 1, | ||
71 | }; | ||
72 | |||
73 | static struct usb_interface_descriptor serial_bulk_interface_desc = { | ||
74 | .bLength = USB_DT_INTERFACE_SIZE, | ||
75 | .bDescriptorType = USB_DT_INTERFACE, | ||
76 | .bInterfaceNumber = 0, | ||
77 | .bNumEndpoints = 2, | ||
78 | .bInterfaceClass = USB_CLASS_CDC_DATA, | ||
79 | .bInterfaceSubClass = 0, | ||
80 | .bInterfaceProtocol = 0, | ||
81 | .iInterface = GS_DATA_STR_ID, | ||
82 | }; | ||
83 | |||
84 | static struct usb_endpoint_descriptor serial_fullspeed_in_desc = { | ||
85 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
86 | .bDescriptorType = USB_DT_ENDPOINT, | ||
87 | .bEndpointAddress = USB_DIR_IN, | ||
88 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
89 | .wMaxPacketSize = 8, | ||
90 | }; | ||
91 | |||
92 | static struct usb_endpoint_descriptor serial_fullspeed_out_desc = { | ||
93 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
94 | .bDescriptorType = USB_DT_ENDPOINT, | ||
95 | .bEndpointAddress = USB_DIR_OUT, | ||
96 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
97 | .wMaxPacketSize = 8, | ||
98 | }; | ||
99 | |||
100 | static struct usb_debug_descriptor serial_debug_desc = { | ||
101 | .bLength = sizeof(struct usb_debug_descriptor), | ||
102 | .bDescriptorType = USB_DT_DEBUG, | ||
103 | }; | ||
104 | |||
105 | static struct usb_qualifier_descriptor serial_qualifier_desc = { | ||
106 | .bLength = sizeof(struct usb_qualifier_descriptor), | ||
107 | .bDescriptorType = USB_DT_DEVICE_QUALIFIER, | ||
108 | .bcdUSB = 0x0200, | ||
109 | .bDeviceClass = USB_CLASS_COMM, | ||
110 | .bNumConfigurations = 1, | ||
111 | }; | ||
112 | |||
113 | struct usb_descriptor_header *serial_bulk_fullspeed_function[] = { | ||
114 | (struct usb_descriptor_header *) &serial_bulk_interface_desc, | ||
115 | (struct usb_descriptor_header *) &serial_fullspeed_in_desc, | ||
116 | (struct usb_descriptor_header *) &serial_fullspeed_out_desc, | ||
117 | NULL, | ||
118 | }; | ||
119 | |||
120 | #define BUFFER_SIZE 100 | ||
121 | uint8_t buf[BUFFER_SIZE]; | ||
122 | |||
123 | struct usb_response res; | ||
124 | |||
125 | /* helper functions */ | ||
126 | static int config_buf(uint8_t *buf, uint8_t type, unsigned index); | ||
127 | static int set_config(int config); | ||
128 | |||
129 | |||
130 | struct device { | ||
131 | struct usb_ep* in; | ||
132 | struct usb_ep* out; | ||
133 | uint32_t used_config; | ||
134 | }; | ||
135 | |||
136 | static struct device dev; | ||
137 | |||
138 | /*-------------------------------------------------------------------------*/ | ||
139 | |||
140 | void usb_serial_driver_init(void) { | ||
141 | |||
142 | logf("usb serial: register"); | ||
143 | usb_device_driver_register(&usb_serial_driver); | ||
144 | } | ||
145 | |||
146 | /*-------------------------------------------------------------------------*/ | ||
147 | |||
148 | void usb_serial_driver_bind(void* controler_ops) { | ||
149 | |||
150 | logf("usb serial: bind"); | ||
151 | ops = controler_ops; | ||
152 | |||
153 | /* serach and asign endpoints */ | ||
154 | usb_ep_autoconfig_reset(); | ||
155 | |||
156 | dev.in = usb_ep_autoconfig(&serial_fullspeed_in_desc); | ||
157 | if (!dev.in) { | ||
158 | goto autoconf_fail; | ||
159 | } | ||
160 | dev.in->claimed = true; | ||
161 | logf("usb serial: in: %s", dev.in->name); | ||
162 | |||
163 | dev.out = usb_ep_autoconfig(&serial_fullspeed_out_desc); | ||
164 | if (!dev.out) { | ||
165 | goto autoconf_fail; | ||
166 | } | ||
167 | dev.out->claimed = true; | ||
168 | logf("usb serial: out: %s", dev.out->name); | ||
169 | |||
170 | /* update device decsriptor */ | ||
171 | serial_device_desc.bMaxPacketSize0 = ops->ep0->maxpacket; | ||
172 | |||
173 | /* update qualifie descriptor */ | ||
174 | serial_qualifier_desc.bMaxPacketSize0 = ops->ep0->maxpacket; | ||
175 | |||
176 | /* update debug descriptor */ | ||
177 | serial_debug_desc.bDebugInEndpoint = dev.in->ep_num; | ||
178 | serial_debug_desc.bDebugOutEndpoint = dev.out->ep_num; | ||
179 | |||
180 | return; | ||
181 | |||
182 | autoconf_fail: | ||
183 | logf("failed to find endpoiunts"); | ||
184 | } | ||
185 | |||
186 | int usb_serial_driver_request(struct usb_ctrlrequest* request) { | ||
187 | |||
188 | int ret = -EOPNOTSUPP; | ||
189 | logf("usb serial: request"); | ||
190 | |||
191 | res.length = 0; | ||
192 | res.buf = NULL; | ||
193 | |||
194 | switch (request->bRequestType & USB_TYPE_MASK) { | ||
195 | case USB_TYPE_STANDARD: | ||
196 | |||
197 | switch (request->bRequest) { | ||
198 | case USB_REQ_GET_DESCRIPTOR: | ||
199 | |||
200 | switch (request->wValue >> 8) { | ||
201 | case USB_DT_DEVICE: | ||
202 | logf("usb serial: sending device desc"); | ||
203 | ret = MIN(sizeof(struct usb_device_descriptor), request->wLength); | ||
204 | res.buf = &serial_device_desc; | ||
205 | break; | ||
206 | |||
207 | case USB_DT_DEVICE_QUALIFIER: | ||
208 | logf("usb serial: sending qualifier dec"); | ||
209 | ret = MIN(sizeof(struct usb_qualifier_descriptor), request->wLength); | ||
210 | res.buf = &serial_qualifier_desc; | ||
211 | |||
212 | case USB_DT_CONFIG: | ||
213 | logf("usb serial: sending config desc"); | ||
214 | |||
215 | ret = config_buf(buf, request->wValue >> 8, request->wValue & 0xff); | ||
216 | if (ret >= 0) { | ||
217 | logf("%d, vs %d", request->wLength, ret); | ||
218 | ret = MIN(request->wLength, (uint16_t)ret); | ||
219 | } | ||
220 | res.buf = buf; | ||
221 | break; | ||
222 | |||
223 | case USB_DT_DEBUG: | ||
224 | logf("usb serial: sending debug desc"); | ||
225 | ret = MIN(sizeof(struct usb_debug_descriptor), request->wLength); | ||
226 | res.buf = &serial_debug_desc; | ||
227 | break; | ||
228 | } | ||
229 | break; | ||
230 | |||
231 | case USB_REQ_SET_CONFIGURATION: | ||
232 | logf("usb serial: set configuration %d", request->wValue); | ||
233 | ret = set_config(request->wValue); | ||
234 | break; | ||
235 | |||
236 | case USB_REQ_GET_CONFIGURATION: | ||
237 | logf("usb serial: get configuration"); | ||
238 | ret = 1; | ||
239 | res.buf = &dev.used_config; | ||
240 | break; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | if (ret >= 0) { | ||
245 | res.length = ret; | ||
246 | ret = ops->send(NULL, &res); | ||
247 | } | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | void usb_serial_driver_speed(enum usb_device_speed speed) { | ||
253 | |||
254 | switch (speed) { | ||
255 | case USB_SPEED_LOW: | ||
256 | case USB_SPEED_FULL: | ||
257 | logf("usb serial: using fullspeed"); | ||
258 | break; | ||
259 | case USB_SPEED_HIGH: | ||
260 | logf("usb serial: using highspeed"); | ||
261 | break; | ||
262 | default: | ||
263 | logf("speed: hmm"); | ||
264 | break; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | /*-------------------------------------------------------------------------*/ | ||
269 | /* helper functions */ | ||
270 | |||
271 | static int config_buf(uint8_t *buf, uint8_t type, unsigned index) { | ||
272 | |||
273 | int len; | ||
274 | |||
275 | /* TODO check index*/ | ||
276 | |||
277 | len = usb_stack_configdesc(&serial_bulk_config_desc, buf, BUFFER_SIZE, serial_bulk_fullspeed_function); | ||
278 | if (len < 0) { | ||
279 | return len; | ||
280 | } | ||
281 | ((struct usb_config_descriptor *)buf)->bDescriptorType = type; | ||
282 | return len; | ||
283 | } | ||
284 | |||
285 | static int set_config(int config) { | ||
286 | |||
287 | /* TODO check config*/ | ||
288 | |||
289 | /* enable endpoints */ | ||
290 | logf("setup %s", dev.in->name); | ||
291 | ops->enable(dev.in); | ||
292 | logf("setup %s", dev.out->name); | ||
293 | ops->enable(dev.out); | ||
294 | |||
295 | /* store config */ | ||
296 | logf("using config %d", config); | ||
297 | dev.used_config = config; | ||
298 | |||
299 | return 0; | ||
300 | } | ||
diff --git a/firmware/usbstack/drivers/device/usb_serial.h b/firmware/usbstack/drivers/device/usb_serial.h new file mode 100644 index 0000000000..808eaa16e3 --- /dev/null +++ b/firmware/usbstack/drivers/device/usb_serial.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef _SERIAL_H_ | ||
21 | #define _SERIAL_H_ | ||
22 | |||
23 | #include "usbstack/core.h" | ||
24 | |||
25 | /* register serial driver in usb stack */ | ||
26 | void usb_serial_driver_init(void); | ||
27 | |||
28 | void usb_serial_driver_bind(void* controller_ops); | ||
29 | int usb_serial_driver_request(struct usb_ctrlrequest* req); | ||
30 | void usb_serial_driver_speed(enum usb_device_speed speed); | ||
31 | |||
32 | #endif /*_SERIAL_H_*/ | ||
diff --git a/firmware/usbstack/drivers/device/usb_storage.c b/firmware/usbstack/drivers/device/usb_storage.c new file mode 100644 index 0000000000..0cb1f108b5 --- /dev/null +++ b/firmware/usbstack/drivers/device/usb_storage.c | |||
@@ -0,0 +1,269 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "usb_storage.h" | ||
21 | #include <string.h> | ||
22 | |||
23 | /*-------------------------------------------------------------------------*/ | ||
24 | |||
25 | static struct usb_dcd_controller_ops* ops; | ||
26 | |||
27 | struct usb_device_driver usb_storage_driver = { | ||
28 | .name = "storage", | ||
29 | .bind = usb_storage_driver_bind, | ||
30 | .unbind = NULL, | ||
31 | .request = usb_storage_driver_request, | ||
32 | .suspend = NULL, | ||
33 | .resume = NULL, | ||
34 | .speed = NULL, | ||
35 | }; | ||
36 | |||
37 | struct device { | ||
38 | struct usb_ep* in; | ||
39 | struct usb_ep* out; | ||
40 | struct usb_ep* intr; | ||
41 | }; | ||
42 | |||
43 | static struct device dev; | ||
44 | |||
45 | /*-------------------------------------------------------------------------*/ | ||
46 | |||
47 | #define PROTO_BULK 0x50 // Bulk only | ||
48 | #define SUBCL_SCSI 0x06 // Transparent SCSI | ||
49 | |||
50 | /* Bulk-only class specific requests */ | ||
51 | #define USB_BULK_RESET_REQUEST 0xff | ||
52 | #define USB_BULK_GET_MAX_LUN_REQUEST 0xfe | ||
53 | |||
54 | /*-------------------------------------------------------------------------*/ | ||
55 | /* usb descriptors */ | ||
56 | |||
57 | static struct usb_device_descriptor storage_device_desc = { | ||
58 | .bLength = USB_DT_DEVICE_SIZE, | ||
59 | .bDescriptorType = USB_DT_DEVICE, | ||
60 | .bcdUSB = 0x0200, | ||
61 | .bDeviceClass = 0, | ||
62 | .bDeviceSubClass = 0, | ||
63 | .bDeviceProtocol = 0, | ||
64 | .bMaxPacketSize0 = 64, | ||
65 | .idVendor = 0xffff, | ||
66 | .idProduct = 0x0001, | ||
67 | .iManufacturer = 0, | ||
68 | .iProduct = 0, | ||
69 | .iSerialNumber = 0, | ||
70 | .bNumConfigurations = 1, | ||
71 | }; | ||
72 | |||
73 | static struct usb_config_descriptor storage_config_desc = { | ||
74 | .bLength = USB_DT_CONFIG_SIZE, | ||
75 | .bDescriptorType = USB_DT_CONFIG, | ||
76 | |||
77 | .bNumInterfaces = 1, | ||
78 | .bConfigurationValue = 1, | ||
79 | .iConfiguration = 0, | ||
80 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, | ||
81 | .bMaxPower = 1, | ||
82 | }; | ||
83 | |||
84 | static struct usb_interface_descriptor storage_interface_desc = { | ||
85 | .bLength = USB_DT_INTERFACE_SIZE, | ||
86 | .bDescriptorType = USB_DT_INTERFACE, | ||
87 | .bInterfaceNumber = 0, | ||
88 | .bNumEndpoints = 3, | ||
89 | .bInterfaceClass = USB_CLASS_MASS_STORAGE, | ||
90 | .bInterfaceSubClass = SUBCL_SCSI, | ||
91 | .bInterfaceProtocol = PROTO_BULK, | ||
92 | .iInterface = 0, | ||
93 | }; | ||
94 | |||
95 | /* endpoint I -> bulk in */ | ||
96 | static struct usb_endpoint_descriptor storage_bulk_in_desc = { | ||
97 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
98 | .bDescriptorType = USB_DT_ENDPOINT, | ||
99 | .bEndpointAddress = USB_DIR_IN, | ||
100 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
101 | .wMaxPacketSize = 512, | ||
102 | }; | ||
103 | |||
104 | /* endpoint II -> bulk out */ | ||
105 | static struct usb_endpoint_descriptor storage_bulk_out_desc = { | ||
106 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
107 | .bDescriptorType = USB_DT_ENDPOINT, | ||
108 | .bEndpointAddress = USB_DIR_OUT, | ||
109 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
110 | .wMaxPacketSize = 512, | ||
111 | }; | ||
112 | |||
113 | struct usb_descriptor_header *storage_fullspeed_function[] = { | ||
114 | (struct usb_descriptor_header *) &storage_interface_desc, | ||
115 | (struct usb_descriptor_header *) &storage_bulk_in_desc, | ||
116 | (struct usb_descriptor_header *) &storage_bulk_out_desc, | ||
117 | NULL, | ||
118 | }; | ||
119 | |||
120 | #define BUFFER_SIZE 100 | ||
121 | uint8_t buf[BUFFER_SIZE]; | ||
122 | |||
123 | struct usb_response res; | ||
124 | |||
125 | /* helper functions */ | ||
126 | static int config_buf(uint8_t *buf, uint8_t type, unsigned index); | ||
127 | static int set_config(int config); | ||
128 | |||
129 | /*-------------------------------------------------------------------------*/ | ||
130 | |||
131 | void usb_storage_driver_init(void) { | ||
132 | |||
133 | logf("usb storage: register"); | ||
134 | usb_device_driver_register(&usb_storage_driver); | ||
135 | } | ||
136 | |||
137 | /*-------------------------------------------------------------------------*/ | ||
138 | /* device driver ops */ | ||
139 | |||
140 | void usb_storage_driver_bind(void* controler_ops) { | ||
141 | |||
142 | ops = controler_ops; | ||
143 | |||
144 | /* serach and asign endpoints */ | ||
145 | usb_ep_autoconfig_reset(); | ||
146 | |||
147 | dev.in = usb_ep_autoconfig(&storage_bulk_in_desc); | ||
148 | if (!dev.in) { | ||
149 | goto autoconf_fail; | ||
150 | } | ||
151 | dev.in->claimed = true; | ||
152 | logf("usb storage: in: %s", dev.in->name); | ||
153 | |||
154 | dev.out = usb_ep_autoconfig(&storage_bulk_out_desc); | ||
155 | if (!dev.out) { | ||
156 | goto autoconf_fail; | ||
157 | } | ||
158 | dev.out->claimed = true; | ||
159 | logf("usb storage: out: %s", dev.out->name); | ||
160 | |||
161 | return; | ||
162 | |||
163 | autoconf_fail: | ||
164 | logf("failed to find endpoints"); | ||
165 | } | ||
166 | |||
167 | int usb_storage_driver_request(struct usb_ctrlrequest* request) { | ||
168 | |||
169 | int ret = -EOPNOTSUPP; | ||
170 | logf("usb storage: request"); | ||
171 | |||
172 | res.length = 0; | ||
173 | res.buf = NULL; | ||
174 | |||
175 | switch (request->bRequestType & USB_TYPE_MASK) { | ||
176 | case USB_TYPE_STANDARD: | ||
177 | |||
178 | switch (request->bRequest) { | ||
179 | case USB_REQ_GET_DESCRIPTOR: | ||
180 | |||
181 | switch (request->wValue >> 8) { | ||
182 | case USB_DT_DEVICE: | ||
183 | logf("usb storage: sending device desc"); | ||
184 | ret = MIN(sizeof(struct usb_device_descriptor), request->wLength); | ||
185 | res.buf = &storage_device_desc; | ||
186 | break; | ||
187 | |||
188 | case USB_DT_CONFIG: | ||
189 | logf("usb storage: sending config desc"); | ||
190 | |||
191 | ret = config_buf(buf, request->wValue >> 8, request->wValue & 0xff); | ||
192 | if (ret >= 0) { | ||
193 | logf("%d, vs %d", request->wLength, ret); | ||
194 | ret = MIN(request->wLength, (uint16_t)ret); | ||
195 | } | ||
196 | res.buf = buf; | ||
197 | break; | ||
198 | } | ||
199 | break; | ||
200 | |||
201 | case USB_REQ_SET_CONFIGURATION: | ||
202 | logf("usb storage: set configuration %d", request->wValue); | ||
203 | ret = set_config(request->wValue); | ||
204 | break; | ||
205 | |||
206 | case USB_REQ_SET_INTERFACE: | ||
207 | logf("usb storage: set interface"); | ||
208 | ret = 0; | ||
209 | break; | ||
210 | } | ||
211 | |||
212 | case USB_TYPE_CLASS: | ||
213 | |||
214 | switch (request->bRequest) { | ||
215 | case USB_BULK_RESET_REQUEST: | ||
216 | logf("usb storage: bulk reset"); | ||
217 | break; | ||
218 | |||
219 | case USB_BULK_GET_MAX_LUN_REQUEST: | ||
220 | logf("usb storage: get max lun"); | ||
221 | /* we support no LUNs (Logical Unit Number) */ | ||
222 | buf[0] = 0; | ||
223 | ret = 1; | ||
224 | break; | ||
225 | } | ||
226 | break; | ||
227 | } | ||
228 | |||
229 | if (ret >= 0) { | ||
230 | res.length = ret; | ||
231 | ret = ops->send(NULL, &res); | ||
232 | } | ||
233 | |||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | /*-------------------------------------------------------------------------*/ | ||
238 | /* S/GET CONFIGURATION helpers */ | ||
239 | |||
240 | static int config_buf(uint8_t *buf, uint8_t type, unsigned index) { | ||
241 | |||
242 | int len; | ||
243 | |||
244 | /* only one configuration */ | ||
245 | if (index != 0) { | ||
246 | return -EINVAL; | ||
247 | } | ||
248 | |||
249 | len = usb_stack_configdesc(&storage_config_desc, buf, BUFFER_SIZE, storage_fullspeed_function); | ||
250 | if (len < 0) { | ||
251 | return len; | ||
252 | } | ||
253 | ((struct usb_config_descriptor *)buf)->bDescriptorType = type; | ||
254 | return len; | ||
255 | } | ||
256 | |||
257 | static int set_config(int config) { | ||
258 | |||
259 | /* enable endpoints */ | ||
260 | logf("setup %s", dev.in->name); | ||
261 | ops->enable(dev.in); | ||
262 | logf("setup %s", dev.out->name); | ||
263 | ops->enable(dev.out); | ||
264 | |||
265 | /* setup buffers */ | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
diff --git a/firmware/usbstack/drivers/device/usb_storage.h b/firmware/usbstack/drivers/device/usb_storage.h new file mode 100644 index 0000000000..9494aa76ff --- /dev/null +++ b/firmware/usbstack/drivers/device/usb_storage.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef _STORGAGE_H_ | ||
21 | #define _STORGAGE_H_ | ||
22 | |||
23 | #include "usbstack/core.h" | ||
24 | |||
25 | /* register serial driver in usb stack */ | ||
26 | void usb_storage_driver_init(void); | ||
27 | |||
28 | void usb_storage_driver_bind(void* controller_ops); | ||
29 | int usb_storage_driver_request(struct usb_ctrlrequest* req); | ||
30 | |||
31 | #endif /*_STORGAGE_H_*/ | ||
diff --git a/firmware/usbstack/host.h b/firmware/usbstack/host.h new file mode 100644 index 0000000000..cb2f550e46 --- /dev/null +++ b/firmware/usbstack/host.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef _USBSTACK_HOST_H_ | ||
21 | #define _USBSTACK_HOST_H_ | ||
22 | |||
23 | /* | ||
24 | * usb host driver | ||
25 | */ | ||
26 | struct usb_host_driver { | ||
27 | const char* name; | ||
28 | void* data; /* used to store controller specific ops struct */ | ||
29 | }; | ||
30 | |||
31 | #endif /*_USBSTACK_HOST_H_*/ | ||