mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-07 05:35:02 -05:00
Add USB Audio 1.0 support
Original commit credit to Amaury Pouly, Moshe Piekarski Pushed across the finish line by Dana Conrad To enable, see setting under General Settings --> System --> USB-DAC. On devices with few endpoints, this may not work while HID and/or mass storage is enabled. Adds new dedicated mixer channel. setting usb-dac can have values: - never (0) - always (1) - while_charge_only (2) - while_mass_storage (3) Relevant devices are DWC2 and ARC usb controller devices. That being: x1000 Native targets (m3k, erosqnative, q1, others...?), sansac200, creativezenxfi2, vibe500, ipodmini2g, ipod4g, creativezenxfi, creativezenxfi3, sansaview, ipodcolor, creativezenxfistyle, samsungypz5, sansafuzeplus, iriverh10_5gb, tatungtpj1022, gigabeats, faketarget, samsungyh820, gogearhdd1630, samsungyh925, ipodmini1g, ipodvideo, creativezenmozaic, sonynwze370, creativezen, gogearsa9200, gogearhdd6330, sonynwze360, sansae200, mrobe100, iriverh10, creativezenv, ipodnano1g, samsungyh920 USB Driver-wise, it should be noted that this patch requires some slight changes: - proper blocking on control OUT transfers, to make sure the data is received *before* using it, the usb_core should probably use that too - drivers can now support interface alternate settings - drivers can be notified of completion by a new fast handler, which is called directly from the driver; this is is necessary for isochronous transfers because going through the usb queue is way too slow Designware changes: - enable for USBOTG_DESIGNWARE - set maxpacketsize to 1023 for ISO endpoints Change-Id: I570871884a4e4820b4312b203b07701f06ecacc6
This commit is contained in:
parent
af42428037
commit
9ce66e088e
20 changed files with 1867 additions and 35 deletions
|
|
@ -116,6 +116,9 @@
|
||||||
|
|
||||||
#ifdef HAVE_USBSTACK
|
#ifdef HAVE_USBSTACK
|
||||||
#include "usb_core.h"
|
#include "usb_core.h"
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
#include "../usbstack/usb_audio.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "talk.h"
|
#include "talk.h"
|
||||||
|
|
@ -2509,18 +2512,56 @@ static bool dbg_talk(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_USBSTACK
|
#ifdef HAVE_USBSTACK
|
||||||
#if defined(ROCKBOX_HAS_LOGF) && defined(USB_ENABLE_SERIAL)
|
#if (defined(ROCKBOX_HAS_LOGF) && defined(USB_ENABLE_SERIAL))
|
||||||
static bool toggle_usb_serial(void)
|
static bool toggle_usb_core_driver(int driver, char *msg)
|
||||||
{
|
{
|
||||||
bool enabled = !usb_core_driver_enabled(USB_DRIVER_SERIAL);
|
bool enabled = !usb_core_driver_enabled(driver);
|
||||||
|
|
||||||
usb_core_enable_driver(USB_DRIVER_SERIAL, enabled);
|
usb_core_enable_driver(driver,enabled);
|
||||||
splashf(HZ, "USB Serial %sabled", enabled ? "en" : "dis");
|
splashf(HZ, "%s %s", msg, enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USB_ENABLE_SERIAL
|
||||||
|
static bool toggle_usb_serial(void)
|
||||||
|
{
|
||||||
|
return toggle_usb_core_driver(USB_DRIVER_SERIAL, "USB Serial");
|
||||||
|
}
|
||||||
|
#endif /* USB_ENABLE_SERIAL */
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
static int dbg_usb_audio_cb(int action, struct gui_synclist *lists)
|
||||||
|
{
|
||||||
|
(void)lists;
|
||||||
|
simplelist_reset_lines();
|
||||||
|
simplelist_addline("%sabled", usb_core_driver_enabled(USB_DRIVER_AUDIO)?"En":"Dis");
|
||||||
|
simplelist_addline("%sPlaying", usb_audio_get_playing()?"":"Not ");
|
||||||
|
simplelist_addline("iface: %d alt: %d", usb_audio_get_main_intf(), usb_audio_get_alt_intf());
|
||||||
|
simplelist_addline("out ep: 0x%X in ep: 0x%X", usb_audio_get_out_ep(), usb_audio_get_in_ep());
|
||||||
|
simplelist_addline("Volume: %d", usb_audio_get_cur_volume());
|
||||||
|
simplelist_addline("Playback Frequency: %lu", usb_audio_get_playback_sampling_frequency());
|
||||||
|
simplelist_addline("Buffers filled: %d", usb_audio_get_prebuffering());
|
||||||
|
simplelist_addline("%s", usb_audio_get_underflow()?"UNDERFLOW!":" ");
|
||||||
|
simplelist_addline("%s", usb_audio_get_overflow()?"OVERFLOW!":" ");
|
||||||
|
simplelist_addline("%s", usb_audio_get_alloc_failed()?"ALLOC FAILED!":" ");
|
||||||
|
if (action == ACTION_NONE)
|
||||||
|
{
|
||||||
|
action = ACTION_REDRAW;
|
||||||
|
}
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
static bool dbg_usb_audio(void)
|
||||||
|
{
|
||||||
|
struct simplelist_info info;
|
||||||
|
simplelist_info_init(&info, "USB Audio", 0, NULL);
|
||||||
|
info.scroll_all = true;
|
||||||
|
info.action_callback = dbg_usb_audio_cb;
|
||||||
|
return simplelist_show_list(&info);
|
||||||
|
}
|
||||||
|
#endif /* USB_ENABLE_AUDIO */
|
||||||
|
#endif /* HAVE_USBSTACK */
|
||||||
|
|
||||||
#if CONFIG_USBOTG == USBOTG_ISP1583
|
#if CONFIG_USBOTG == USBOTG_ISP1583
|
||||||
extern int dbg_usb_num_items(void);
|
extern int dbg_usb_num_items(void);
|
||||||
|
|
@ -2847,6 +2888,9 @@ static const struct {
|
||||||
#if defined(ROCKBOX_HAS_LOGF) && defined(USB_ENABLE_SERIAL)
|
#if defined(ROCKBOX_HAS_LOGF) && defined(USB_ENABLE_SERIAL)
|
||||||
{"USB Serial driver (logf)", toggle_usb_serial },
|
{"USB Serial driver (logf)", toggle_usb_serial },
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(USB_ENABLE_AUDIO)
|
||||||
|
{"USB-DAC", dbg_usb_audio},
|
||||||
|
#endif
|
||||||
#endif /* HAVE_USBSTACK */
|
#endif /* HAVE_USBSTACK */
|
||||||
#ifdef CPU_BOOST_LOGGING
|
#ifdef CPU_BOOST_LOGGING
|
||||||
{"Show cpu_boost log",cpu_boost_log},
|
{"Show cpu_boost log",cpu_boost_log},
|
||||||
|
|
|
||||||
|
|
@ -10370,6 +10370,62 @@
|
||||||
usb_hid: "Mouse"
|
usb_hid: "Mouse"
|
||||||
</voice>
|
</voice>
|
||||||
</phrase>
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_USB_DAC
|
||||||
|
desc: in settings_menu
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: "USB-DAC"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: "USB-DAC"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: "USB-DAC"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_WHILE_USB_CHARGE_ONLY
|
||||||
|
desc: in settings_menu
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: "While In USB Charge-Only Mode"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: "While In USB Charge-Only Mode"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: "While In USB Charge-Only Mode"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_WHILE_MASS_STORAGE_USB_ONLY
|
||||||
|
desc: in settings_menu
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: "While In USB Mass-Storage Mode"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: "While In USB Mass-Storage Mode"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: "While In USB Mass-Storage Mode"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_USB_DAC_ACTIVE
|
||||||
|
desc: for splash
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: "USB-DAC Active"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: "USB-DAC Active"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: "USB-DAC Active"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
<phrase>
|
<phrase>
|
||||||
id: LANG_SCROLLBAR_WIDTH
|
id: LANG_SCROLLBAR_WIDTH
|
||||||
desc: in Settings -> General -> Display -> Status-/Scrollbar
|
desc: in Settings -> General -> Display -> Status-/Scrollbar
|
||||||
|
|
|
||||||
|
|
@ -358,6 +358,9 @@ MENUITEM_SETTING(lineout_onoff, &global_settings.lineout_active, NULL);
|
||||||
MENUITEM_SETTING(usb_hid, &global_settings.usb_hid, NULL);
|
MENUITEM_SETTING(usb_hid, &global_settings.usb_hid, NULL);
|
||||||
MENUITEM_SETTING(usb_keypad_mode, &global_settings.usb_keypad_mode, NULL);
|
MENUITEM_SETTING(usb_keypad_mode, &global_settings.usb_keypad_mode, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
MENUITEM_SETTING(usb_audio, &global_settings.usb_audio, NULL);
|
||||||
|
#endif
|
||||||
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
||||||
MENUITEM_SETTING(usb_skip_first_drive, &global_settings.usb_skip_first_drive, NULL);
|
MENUITEM_SETTING(usb_skip_first_drive, &global_settings.usb_skip_first_drive, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -454,6 +457,9 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM),
|
||||||
&usb_hid,
|
&usb_hid,
|
||||||
&usb_keypad_mode,
|
&usb_keypad_mode,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
&usb_audio,
|
||||||
|
#endif
|
||||||
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
||||||
&usb_skip_first_drive,
|
&usb_skip_first_drive,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -823,6 +823,10 @@ struct user_settings
|
||||||
int usb_keypad_mode;
|
int usb_keypad_mode;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
int usb_audio;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
||||||
bool usb_skip_first_drive;
|
bool usb_skip_first_drive;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -2315,6 +2315,11 @@ const struct settings_list settings[] = {
|
||||||
), /* CHOICE_SETTING( usb_keypad_mode ) */
|
), /* CHOICE_SETTING( usb_keypad_mode ) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
CHOICE_SETTING(0, usb_audio, LANG_USB_DAC, 0, "usb-dac", "never,always,while_charge_only,while_mass_storage", usb_set_audio, 4,
|
||||||
|
ID2P(LANG_NEVER), ID2P(LANG_ALWAYS), ID2P(LANG_WHILE_USB_CHARGE_ONLY), ID2P(LANG_WHILE_MASS_STORAGE_USB_ONLY)),
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
||||||
OFFON_SETTING(0, usb_skip_first_drive, LANG_USB_SKIP_FIRST_DRIVE, false, "usb skip first drive", usb_set_skip_first_drive),
|
OFFON_SETTING(0, usb_skip_first_drive, LANG_USB_SKIP_FIRST_DRIVE, false, "usb skip first drive", usb_set_skip_first_drive),
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -935,6 +935,9 @@ usbstack/usb_storage.c
|
||||||
#ifdef USB_ENABLE_SERIAL
|
#ifdef USB_ENABLE_SERIAL
|
||||||
usbstack/usb_serial.c
|
usbstack/usb_serial.c
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
usbstack/usb_audio.c
|
||||||
|
#endif
|
||||||
#ifdef USB_ENABLE_CHARGING_ONLY
|
#ifdef USB_ENABLE_CHARGING_ONLY
|
||||||
usbstack/usb_charging_only.c
|
usbstack/usb_charging_only.c
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ static void usb_dw_set_stall(int epnum, enum usb_dw_epdir epdir, int stall)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DWC_EPCTL(epnum, epdir) &= ~STALL;
|
DWC_EPCTL(epnum, epdir) &= ~STALL;
|
||||||
DWC_EPCTL(epnum, epdir) |= SD0PID;
|
DWC_EPCTL(epnum, epdir) |= SETD0PIDEF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -668,7 +668,7 @@ static void usb_dw_unconfigure_ep(int epnum, enum usb_dw_epdir epdir)
|
||||||
static int usb_dw_configure_ep(int epnum,
|
static int usb_dw_configure_ep(int epnum,
|
||||||
enum usb_dw_epdir epdir, int type, int maxpktsize)
|
enum usb_dw_epdir epdir, int type, int maxpktsize)
|
||||||
{
|
{
|
||||||
uint32_t epctl = SD0PID|EPTYP(type)|USBAEP|maxpktsize;
|
uint32_t epctl = SETD0PIDEF|EPTYP(type)|USBAEP|maxpktsize;
|
||||||
|
|
||||||
if (epdir == USB_DW_EPDIR_IN)
|
if (epdir == USB_DW_EPDIR_IN)
|
||||||
{
|
{
|
||||||
|
|
@ -1259,7 +1259,7 @@ static void usb_dw_irq(void)
|
||||||
* FIFO and raises StatusRecvd | XferCompl.
|
* FIFO and raises StatusRecvd | XferCompl.
|
||||||
*
|
*
|
||||||
* We do not need or want this -- we've already handled
|
* We do not need or want this -- we've already handled
|
||||||
* the data phase by this point -- but EP0 is stoppped
|
* the data phase by this point -- but EP0 is stopped
|
||||||
* as a side effect of XferCompl, so we need to restart
|
* as a side effect of XferCompl, so we need to restart
|
||||||
* it to keep receiving packets. */
|
* it to keep receiving packets. */
|
||||||
usb_dw_ep0_recv();
|
usb_dw_ep0_recv();
|
||||||
|
|
@ -1528,7 +1528,7 @@ void usb_drv_cancel_all_transfers()
|
||||||
{
|
{
|
||||||
//usb_dw_flush_endpoint(ep, dir);
|
//usb_dw_flush_endpoint(ep, dir);
|
||||||
usb_dw_abort_endpoint(ep, dir);
|
usb_dw_abort_endpoint(ep, dir);
|
||||||
DWC_EPCTL(ep, dir) |= SD0PID;
|
DWC_EPCTL(ep, dir) |= SETD0PIDEF;
|
||||||
}
|
}
|
||||||
usb_dw_target_enable_irq();
|
usb_dw_target_enable_irq();
|
||||||
}
|
}
|
||||||
|
|
@ -1606,8 +1606,15 @@ int usb_drv_request_endpoint(int type, int dir)
|
||||||
struct usb_dw_ep* dw_ep = usb_dw_get_ep(ep, epdir);
|
struct usb_dw_ep* dw_ep = usb_dw_get_ep(ep, epdir);
|
||||||
if (!dw_ep->active)
|
if (!dw_ep->active)
|
||||||
{
|
{
|
||||||
|
int maxpktsize = 64;
|
||||||
|
if (type == EPTYP_ISOCHRONOUS){
|
||||||
|
maxpktsize = 1023;
|
||||||
|
} else {
|
||||||
|
maxpktsize = usb_drv_port_speed() ? 512 : 64;
|
||||||
|
}
|
||||||
|
|
||||||
if (usb_dw_configure_ep(ep, epdir, type,
|
if (usb_dw_configure_ep(ep, epdir, type,
|
||||||
usb_drv_port_speed() ? 512 : 64) >= 0)
|
maxpktsize) >= 0)
|
||||||
{
|
{
|
||||||
dw_ep->active = true;
|
dw_ep->active = true;
|
||||||
request_ep = ep | dir;
|
request_ep = ep | dir;
|
||||||
|
|
@ -1679,3 +1686,11 @@ void usb_drv_control_response(enum usb_control_response resp,
|
||||||
usb_dw_control_response(resp, data, length);
|
usb_dw_control_response(resp, data, length);
|
||||||
usb_dw_target_enable_irq();
|
usb_dw_target_enable_irq();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int usb_drv_get_frame_number()
|
||||||
|
{
|
||||||
|
// SOFFN is 14 bits, the least significant 3 appear to be some sort of microframe count.
|
||||||
|
// The USB spec says a frame number is 11 bits. This way we get 1 frame per millisecond,
|
||||||
|
// just like we're supposed to!
|
||||||
|
return (DWC_DSTS >> 11) & 0x7FF;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1347,6 +1347,7 @@ Lyre prototype 1 */
|
||||||
#elif (CONFIG_USBOTG == USBOTG_DESIGNWARE)
|
#elif (CONFIG_USBOTG == USBOTG_DESIGNWARE)
|
||||||
#define USB_HAS_BULK
|
#define USB_HAS_BULK
|
||||||
#define USB_HAS_INTERRUPT
|
#define USB_HAS_INTERRUPT
|
||||||
|
#define USB_HAS_ISOCHRONOUS
|
||||||
#elif (CONFIG_USBOTG == USBOTG_ARC) || \
|
#elif (CONFIG_USBOTG == USBOTG_ARC) || \
|
||||||
(CONFIG_USBOTG == USBOTG_JZ4740) || \
|
(CONFIG_USBOTG == USBOTG_JZ4740) || \
|
||||||
(CONFIG_USBOTG == USBOTG_JZ4760) || \
|
(CONFIG_USBOTG == USBOTG_JZ4760) || \
|
||||||
|
|
@ -1356,6 +1357,9 @@ Lyre prototype 1 */
|
||||||
(CONFIG_USBOTG == USBOTG_TNETV105)
|
(CONFIG_USBOTG == USBOTG_TNETV105)
|
||||||
#define USB_HAS_BULK
|
#define USB_HAS_BULK
|
||||||
#define USB_HAS_INTERRUPT
|
#define USB_HAS_INTERRUPT
|
||||||
|
#if (CONFIG_USBOTG == USBOTG_ARC)
|
||||||
|
#define USB_HAS_ISOCHRONOUS
|
||||||
|
#endif
|
||||||
#define USB_LEGACY_CONTROL_API
|
#define USB_LEGACY_CONTROL_API
|
||||||
#elif defined(CPU_TCC780X)
|
#elif defined(CPU_TCC780X)
|
||||||
#define USB_HAS_BULK
|
#define USB_HAS_BULK
|
||||||
|
|
@ -1366,11 +1370,6 @@ Lyre prototype 1 */
|
||||||
//#define USB_HAS_INTERRUPT -- seems to be broken
|
//#define USB_HAS_INTERRUPT -- seems to be broken
|
||||||
#endif /* CONFIG_USBOTG */
|
#endif /* CONFIG_USBOTG */
|
||||||
|
|
||||||
#if (CONFIG_USBOTG == USBOTG_ARC) || \
|
|
||||||
(CONFIG_USBOTG == USBOTG_AS3525)
|
|
||||||
#define USB_HAS_ISOCHRONOUS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* define the class drivers to enable */
|
/* define the class drivers to enable */
|
||||||
#ifdef BOOTLOADER
|
#ifdef BOOTLOADER
|
||||||
|
|
||||||
|
|
@ -1398,6 +1397,10 @@ Lyre prototype 1 */
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_HAS_ISOCHRONOUS
|
||||||
|
#define USB_ENABLE_AUDIO
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* BOOTLOADER */
|
#endif /* BOOTLOADER */
|
||||||
|
|
||||||
#endif /* HAVE_USBSTACK */
|
#endif /* HAVE_USBSTACK */
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,9 @@
|
||||||
enum pcm_mixer_channel
|
enum pcm_mixer_channel
|
||||||
{
|
{
|
||||||
PCM_MIXER_CHAN_PLAYBACK = 0,
|
PCM_MIXER_CHAN_PLAYBACK = 0,
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
PCM_MIXER_CHAN_USBAUDIO,
|
||||||
|
#endif
|
||||||
PCM_MIXER_CHAN_VOICE,
|
PCM_MIXER_CHAN_VOICE,
|
||||||
#ifndef HAVE_HARDWARE_BEEP
|
#ifndef HAVE_HARDWARE_BEEP
|
||||||
PCM_MIXER_CHAN_BEEP,
|
PCM_MIXER_CHAN_BEEP,
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,8 @@
|
||||||
#define DWC_DOEPCTL(x) (*((REG32_PTR_T)(OTGBASE + 0xb00 + 0x20*(x))))
|
#define DWC_DOEPCTL(x) (*((REG32_PTR_T)(OTGBASE + 0xb00 + 0x20*(x))))
|
||||||
#define EPENA (1<<31)
|
#define EPENA (1<<31)
|
||||||
#define EPDIS (1<<30)
|
#define EPDIS (1<<30)
|
||||||
#define SD0PID (1<<28)
|
#define SETD1PIDOF (1<<29)
|
||||||
|
#define SETD0PIDEF (1<<28)
|
||||||
#define SNAK (1<<27)
|
#define SNAK (1<<27)
|
||||||
#define CNAK (1<<26)
|
#define CNAK (1<<26)
|
||||||
#define DTXFNUM(x) ((x)<<22)
|
#define DTXFNUM(x) ((x)<<22)
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,9 @@ enum {
|
||||||
#endif
|
#endif
|
||||||
#ifdef USB_ENABLE_HID
|
#ifdef USB_ENABLE_HID
|
||||||
USB_DRIVER_HID,
|
USB_DRIVER_HID,
|
||||||
|
#endif
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
USB_DRIVER_AUDIO,
|
||||||
#endif
|
#endif
|
||||||
USB_NUM_DRIVERS
|
USB_NUM_DRIVERS
|
||||||
};
|
};
|
||||||
|
|
@ -256,6 +259,10 @@ void usb_firewire_connect_event(void);
|
||||||
void usb_set_hid(bool enable);
|
void usb_set_hid(bool enable);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
void usb_set_audio(int value);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
#if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)
|
||||||
/* when the target has several drives, decide whether mass storage should
|
/* when the target has several drives, decide whether mass storage should
|
||||||
* skip the first drive. This is useful when the second drive is a SD card
|
* skip the first drive. This is useful when the second drive is a SD card
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,12 @@ struct usb_endpoint_descriptor {
|
||||||
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
|
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
|
||||||
#define USB_ENDPOINT_DIR_MASK 0x80
|
#define USB_ENDPOINT_DIR_MASK 0x80
|
||||||
|
|
||||||
|
#define USB_ENDPOINT_SYNCTYPE_MASK 0x0c /* in bmAttributes */
|
||||||
|
#define USB_ENDPOINT_SYNC_NONE (0 << 2)
|
||||||
|
#define USB_ENDPOINT_SYNC_ASYNC (1 << 2)
|
||||||
|
#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << 2)
|
||||||
|
#define USB_ENDPOINT_SYNC_SYNC (3 << 2)
|
||||||
|
|
||||||
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
|
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
|
||||||
#define USB_ENDPOINT_XFER_CONTROL 0
|
#define USB_ENDPOINT_XFER_CONTROL 0
|
||||||
#define USB_ENDPOINT_XFER_ISOC 1
|
#define USB_ENDPOINT_XFER_ISOC 1
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ void usb_drv_stall(int endpoint, bool stall,bool in);
|
||||||
bool usb_drv_stalled(int endpoint,bool in);
|
bool usb_drv_stalled(int endpoint,bool in);
|
||||||
int usb_drv_send(int endpoint, void* ptr, int length);
|
int usb_drv_send(int endpoint, void* ptr, int length);
|
||||||
int usb_drv_send_nonblocking(int endpoint, void* ptr, int length);
|
int usb_drv_send_nonblocking(int endpoint, void* ptr, int length);
|
||||||
|
int usb_drv_recv_blocking(int endpoint, void* ptr, int length);
|
||||||
int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length);
|
int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length);
|
||||||
void usb_drv_control_response(enum usb_control_response resp,
|
void usb_drv_control_response(enum usb_control_response resp,
|
||||||
void* data, int length);
|
void* data, int length);
|
||||||
|
|
@ -86,6 +87,14 @@ void usb_drv_set_test_mode(int mode);
|
||||||
bool usb_drv_connected(void);
|
bool usb_drv_connected(void);
|
||||||
int usb_drv_request_endpoint(int type, int dir);
|
int usb_drv_request_endpoint(int type, int dir);
|
||||||
void usb_drv_release_endpoint(int ep);
|
void usb_drv_release_endpoint(int ep);
|
||||||
|
#ifdef USB_HAS_ISOCHRONOUS
|
||||||
|
/* returns the last received frame number (the 11-bit number contained in the last SOF):
|
||||||
|
* - full-speed: the host sends one SOF every 1ms (so 1000 SOF/s)
|
||||||
|
* - high-speed: the hosts sends one SOF every 125us but each consecutive 8 SOF have the same frame
|
||||||
|
* number
|
||||||
|
* thus in all mode, the frame number can be interpreted as the current millisecond *in USB time*. */
|
||||||
|
int usb_drv_get_frame_number(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* USB_STRING_INITIALIZER(u"Example String") */
|
/* USB_STRING_INITIALIZER(u"Example String") */
|
||||||
#define USB_STRING_INITIALIZER(S) { \
|
#define USB_STRING_INITIALIZER(S) { \
|
||||||
|
|
|
||||||
|
|
@ -599,11 +599,22 @@ int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length)
|
||||||
return prime_transfer(EP_NUM(endpoint), ptr, length, false, false);
|
return prime_transfer(EP_NUM(endpoint), ptr, length, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int usb_drv_recv_blocking(int endpoint, void* ptr, int length)
|
||||||
|
{
|
||||||
|
return prime_transfer(EP_NUM(endpoint), ptr, length, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
int usb_drv_port_speed(void)
|
int usb_drv_port_speed(void)
|
||||||
{
|
{
|
||||||
return (REG_PORTSC1 & 0x08000000) ? 1 : 0;
|
return (REG_PORTSC1 & 0x08000000) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int usb_drv_get_frame_number(void)
|
||||||
|
{
|
||||||
|
/* the lower 3 bits store the microframe (in HS mode), discard them */
|
||||||
|
return (REG_FRINDEX & USB_FRINDEX_MASKS) >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
bool usb_drv_connected(void)
|
bool usb_drv_connected(void)
|
||||||
{
|
{
|
||||||
return (REG_PORTSC1 &
|
return (REG_PORTSC1 &
|
||||||
|
|
@ -970,10 +981,8 @@ static void init_control_queue_heads(void)
|
||||||
/* manual: 32.14.4.1 Queue Head Initialization */
|
/* manual: 32.14.4.1 Queue Head Initialization */
|
||||||
static void init_queue_heads(void)
|
static void init_queue_heads(void)
|
||||||
{
|
{
|
||||||
/* FIXME the packetsize for isochronous transfers is 1023 : 1024 but
|
|
||||||
* the current code only support one type of packet size so we restrict
|
|
||||||
* isochronous packet size for now also */
|
|
||||||
int packetsize = (usb_drv_port_speed() ? 512 : 64);
|
int packetsize = (usb_drv_port_speed() ? 512 : 64);
|
||||||
|
int isopacketsize = (usb_drv_port_speed() ? 1024 : 1024);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* TODO: this should take ep_allocation into account */
|
/* TODO: this should take ep_allocation into account */
|
||||||
|
|
@ -982,7 +991,7 @@ static void init_queue_heads(void)
|
||||||
/* OUT */
|
/* OUT */
|
||||||
if(endpoints[i].type[DIR_OUT] == USB_ENDPOINT_XFER_ISOC)
|
if(endpoints[i].type[DIR_OUT] == USB_ENDPOINT_XFER_ISOC)
|
||||||
/* FIXME: we can adjust the number of packets per frame, currently use one */
|
/* FIXME: we can adjust the number of packets per frame, currently use one */
|
||||||
qh_array[i*2].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
|
qh_array[i*2].max_pkt_length = isopacketsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
|
||||||
else
|
else
|
||||||
qh_array[i*2].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
|
qh_array[i*2].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
|
||||||
|
|
||||||
|
|
@ -991,7 +1000,7 @@ static void init_queue_heads(void)
|
||||||
/* IN */
|
/* IN */
|
||||||
if(endpoints[i].type[DIR_IN] == USB_ENDPOINT_XFER_ISOC)
|
if(endpoints[i].type[DIR_IN] == USB_ENDPOINT_XFER_ISOC)
|
||||||
/* FIXME: we can adjust the number of packets per frame, currently use one */
|
/* FIXME: we can adjust the number of packets per frame, currently use one */
|
||||||
qh_array[i*2+1].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
|
qh_array[i*2+1].max_pkt_length = isopacketsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
|
||||||
else
|
else
|
||||||
qh_array[i*2+1].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
|
qh_array[i*2+1].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,9 @@ static bool exclusive_storage_access = false;
|
||||||
#ifdef USB_ENABLE_HID
|
#ifdef USB_ENABLE_HID
|
||||||
static bool usb_hid = true;
|
static bool usb_hid = true;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
static int usb_audio = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USB_FULL_INIT
|
#ifdef USB_FULL_INIT
|
||||||
static bool usb_host_present = false;
|
static bool usb_host_present = false;
|
||||||
|
|
@ -194,6 +197,10 @@ static inline void usb_handle_hotswap(long id)
|
||||||
|
|
||||||
static inline bool usb_configure_drivers(int for_state)
|
static inline bool usb_configure_drivers(int for_state)
|
||||||
{
|
{
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
// FIXME: doesn't seem to get set when loaded at boot...
|
||||||
|
usb_audio = global_settings.usb_audio;
|
||||||
|
#endif
|
||||||
switch(for_state)
|
switch(for_state)
|
||||||
{
|
{
|
||||||
case USB_POWERED:
|
case USB_POWERED:
|
||||||
|
|
@ -207,6 +214,9 @@ static inline bool usb_configure_drivers(int for_state)
|
||||||
usb_core_enable_driver(USB_DRIVER_HID, true);
|
usb_core_enable_driver(USB_DRIVER_HID, true);
|
||||||
#endif /* USB_ENABLE_CHARGING_ONLY */
|
#endif /* USB_ENABLE_CHARGING_ONLY */
|
||||||
#endif /* USB_ENABLE_HID */
|
#endif /* USB_ENABLE_HID */
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
usb_core_enable_driver(USB_DRIVER_AUDIO, (usb_audio == 1) || (usb_audio == 2)); // while "always" or "only in charge-only mode"
|
||||||
|
#endif /* USB_ENABLE_AUDIO */
|
||||||
|
|
||||||
#ifdef USB_ENABLE_CHARGING_ONLY
|
#ifdef USB_ENABLE_CHARGING_ONLY
|
||||||
usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true);
|
usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true);
|
||||||
|
|
@ -224,6 +234,9 @@ static inline bool usb_configure_drivers(int for_state)
|
||||||
#ifdef USB_ENABLE_HID
|
#ifdef USB_ENABLE_HID
|
||||||
usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
|
usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
usb_core_enable_driver(USB_DRIVER_AUDIO, (usb_audio == 1) || (usb_audio == 3)); // while "always" or "only in mass-storage mode"
|
||||||
|
#endif /* USB_ENABLE_AUDIO */
|
||||||
#ifdef USB_ENABLE_CHARGING_ONLY
|
#ifdef USB_ENABLE_CHARGING_ONLY
|
||||||
usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false);
|
usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -845,6 +858,13 @@ void usb_set_hid(bool enable)
|
||||||
}
|
}
|
||||||
#endif /* USB_ENABLE_HID */
|
#endif /* USB_ENABLE_HID */
|
||||||
|
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
void usb_set_audio(int value)
|
||||||
|
{
|
||||||
|
usb_audio = value;
|
||||||
|
}
|
||||||
|
#endif /* USB_ENABLE_AUDIO */
|
||||||
|
|
||||||
#ifdef HAVE_USB_POWER
|
#ifdef HAVE_USB_POWER
|
||||||
bool usb_powered_only(void)
|
bool usb_powered_only(void)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
1105
firmware/usbstack/usb_audio.c
Normal file
1105
firmware/usbstack/usb_audio.c
Normal file
File diff suppressed because it is too large
Load diff
223
firmware/usbstack/usb_audio.h
Normal file
223
firmware/usbstack/usb_audio.h
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id: $
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 by Amaury Pouly
|
||||||
|
*
|
||||||
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef USB_AUDIO_H
|
||||||
|
#define USB_AUDIO_H
|
||||||
|
|
||||||
|
#include "usb_ch9.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_request_endpoints():
|
||||||
|
*
|
||||||
|
* Calls usb_core_request_endpoint() to request one IN and one OUT
|
||||||
|
* isochronous endpoint.
|
||||||
|
*
|
||||||
|
* Called by allocate_interfaces_and_endpoints().
|
||||||
|
*
|
||||||
|
* Returns -1 if either request fails, returns 0 if success.
|
||||||
|
*
|
||||||
|
* Also requests buffer allocations. If allocation fails,
|
||||||
|
* returns -1 so that the driver will be disabled by the USB core.
|
||||||
|
*/
|
||||||
|
int usb_audio_request_endpoints(struct usb_class_driver *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_set_first_interface():
|
||||||
|
*
|
||||||
|
* Required function for the class driver.
|
||||||
|
*
|
||||||
|
* Called by allocate_interfaces_and_endpoints() to
|
||||||
|
* tell the class driver what its first interface number is.
|
||||||
|
* Returns the number of the interface available for the next
|
||||||
|
* class driver to use.
|
||||||
|
*
|
||||||
|
* We need 2 interfaces, AudioControl and AudioStreaming.
|
||||||
|
* Return interface+2.
|
||||||
|
*/
|
||||||
|
int usb_audio_set_first_interface(int interface);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_config_descriptor():
|
||||||
|
*
|
||||||
|
* Required function for the class driver.
|
||||||
|
*
|
||||||
|
* Called by request_handler_device_get_descriptor(), which expects
|
||||||
|
* this function to fill *dest with the configuration descriptor for this
|
||||||
|
* class driver.
|
||||||
|
*
|
||||||
|
* Return the size of this descriptor in bytes.
|
||||||
|
*/
|
||||||
|
int usb_audio_get_config_descriptor(unsigned char *dest,int max_packet_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_init_connection():
|
||||||
|
*
|
||||||
|
* Called by usb_core_do_set_config() when the
|
||||||
|
* connection is ready to be used. Currently just sets
|
||||||
|
* the audio sample rate to default.
|
||||||
|
*/
|
||||||
|
void usb_audio_init_connection(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_init():
|
||||||
|
*
|
||||||
|
* Initialize the driver. Called by usb_core_init().
|
||||||
|
* Currently initializes the sampling frequency values available
|
||||||
|
* to the AudioStreaming interface.
|
||||||
|
*/
|
||||||
|
void usb_audio_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_disconnect():
|
||||||
|
*
|
||||||
|
* Called by usb_core_exit() AND usb_core_do_set_config().
|
||||||
|
*
|
||||||
|
* Indicates to the Class driver that the connection is no
|
||||||
|
* longer active. Currently just calls usb_audio_stop_playback().
|
||||||
|
*/
|
||||||
|
void usb_audio_disconnect(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_playing():
|
||||||
|
*
|
||||||
|
* Returns playing/not playing status of usbaudio.
|
||||||
|
*/
|
||||||
|
bool usb_audio_get_playing(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_alloc_failed():
|
||||||
|
*
|
||||||
|
* Return whether the buffer allocation succeeded (0)
|
||||||
|
* or failed (1).
|
||||||
|
*/
|
||||||
|
bool usb_audio_get_alloc_failed(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_transfer_complete():
|
||||||
|
*
|
||||||
|
* Dummy function.
|
||||||
|
*
|
||||||
|
* The fast_transfer_complete() function needs to be used instead.
|
||||||
|
*/
|
||||||
|
void usb_audio_transfer_complete(int ep,int dir, int status, int length);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_fast_transfer_complete():
|
||||||
|
*
|
||||||
|
* Called by usb_core_transfer_complete().
|
||||||
|
* The normal transfer complete handler system is too slow to deal with
|
||||||
|
* ISO data at the rate required, so this is required.
|
||||||
|
*
|
||||||
|
* Return true if the transfer is handled, false otherwise.
|
||||||
|
*/
|
||||||
|
bool usb_audio_fast_transfer_complete(int ep,int dir, int status, int length);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_control_request():
|
||||||
|
*
|
||||||
|
* Called by control_request_handler_drivers().
|
||||||
|
* Pass control requests down to the appropriate functions.
|
||||||
|
*
|
||||||
|
* Return true if this driver handles the request, false otherwise.
|
||||||
|
*/
|
||||||
|
bool usb_audio_control_request(struct usb_ctrlrequest* req, void* reqdata, unsigned char* dest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_set_interface():
|
||||||
|
*
|
||||||
|
* Called by control_request_handler_drivers().
|
||||||
|
* Deal with changing the interface between control and streaming.
|
||||||
|
*
|
||||||
|
* Return 0 for success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int usb_audio_set_interface(int intf, int alt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_interface():
|
||||||
|
*
|
||||||
|
* Called by control_request_handler_drivers().
|
||||||
|
* Get the alternate of the given interface.
|
||||||
|
*
|
||||||
|
* Return the alternate of the given interface, -1 if unknown.
|
||||||
|
*/
|
||||||
|
int usb_audio_get_interface(int intf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_playback_sampling_frequency():
|
||||||
|
*
|
||||||
|
* Return the sample rate currently set.
|
||||||
|
*/
|
||||||
|
unsigned long usb_audio_get_playback_sampling_frequency(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_main_intf():
|
||||||
|
*
|
||||||
|
* Return the main usb interface
|
||||||
|
*/
|
||||||
|
int usb_audio_get_main_intf(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_alt_intf():
|
||||||
|
*
|
||||||
|
* Return the alternate usb interface
|
||||||
|
*/
|
||||||
|
int usb_audio_get_alt_intf(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_out_ep():
|
||||||
|
*
|
||||||
|
* Return the out (to device) endpoint
|
||||||
|
*/
|
||||||
|
unsigned int usb_audio_get_out_ep(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_in_ep():
|
||||||
|
*
|
||||||
|
* Return the in (to host) endpoint
|
||||||
|
*/
|
||||||
|
unsigned int usb_audio_get_in_ep(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_prebuffering():
|
||||||
|
*
|
||||||
|
* Return number of buffers filled ahead of playback
|
||||||
|
*/
|
||||||
|
int usb_audio_get_prebuffering(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_underflow():
|
||||||
|
*
|
||||||
|
* Return whether playback is in "underflow" state
|
||||||
|
*/
|
||||||
|
bool usb_audio_get_underflow(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_overflow():
|
||||||
|
*
|
||||||
|
* Return whether usb is in "overflow" state
|
||||||
|
*/
|
||||||
|
bool usb_audio_get_overflow(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* usb_audio_get_cur_volume():
|
||||||
|
*
|
||||||
|
* Return current audio volume in db
|
||||||
|
*/
|
||||||
|
int usb_audio_get_cur_volume(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
233
firmware/usbstack/usb_audio_def.h
Normal file
233
firmware/usbstack/usb_audio_def.h
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id: $
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 by Amaury Pouly
|
||||||
|
*
|
||||||
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
/* Parts of this file are based on Frank Gevaerts work and on audio.h from linux */
|
||||||
|
|
||||||
|
#ifndef USB_AUDIO_DEF_H
|
||||||
|
#define USB_AUDIO_DEF_H
|
||||||
|
|
||||||
|
#include "usb_ch9.h"
|
||||||
|
|
||||||
|
#define USB_SUBCLASS_AUDIO_CONTROL 1
|
||||||
|
#define USB_SUBCLASS_AUDIO_STREAMING 2
|
||||||
|
|
||||||
|
#define USB_AC_HEADER 1
|
||||||
|
#define USB_AC_INPUT_TERMINAL 2
|
||||||
|
#define USB_AC_OUTPUT_TERMINAL 3
|
||||||
|
#define USB_AC_MIXER_UNIT 4
|
||||||
|
#define USB_AC_SELECTOR_UNIT 5
|
||||||
|
#define USB_AC_FEATURE_UNIT 6
|
||||||
|
#define USB_AC_PROCESSING_UNIT 8
|
||||||
|
#define USB_AC_EXTENSION_UNIT 9
|
||||||
|
|
||||||
|
#define USB_AS_GENERAL 1
|
||||||
|
#define USB_AS_FORMAT_TYPE 2
|
||||||
|
|
||||||
|
#define USB_AC_CHANNEL_LEFT_FRONT 0x1
|
||||||
|
#define USB_AC_CHANNEL_RIGHT_FRONT 0x2
|
||||||
|
|
||||||
|
#define USB_AC_CHANNELS_LEFT_RIGHT_FRONT (USB_AC_CHANNEL_LEFT_FRONT | USB_AC_CHANNEL_RIGHT_FRONT)
|
||||||
|
|
||||||
|
/* usb audio data structures */
|
||||||
|
struct usb_ac_header {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType; /* USB_DT_CS_INTERFACE */
|
||||||
|
uint8_t bDescriptorSubType; /* USB_AC_HEADER */
|
||||||
|
uint16_t bcdADC;
|
||||||
|
uint16_t wTotalLength;
|
||||||
|
uint8_t bInCollection;
|
||||||
|
uint8_t baInterfaceNr[];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define USB_AC_SIZEOF_HEADER(n) (8 + (n))
|
||||||
|
|
||||||
|
#define USB_AC_TERMINAL_UNDEFINED 0x100
|
||||||
|
#define USB_AC_TERMINAL_STREAMING 0x101
|
||||||
|
#define USB_AC_TERMINAL_VENDOR_SPEC 0x1ff
|
||||||
|
|
||||||
|
#define USB_AC_EXT_TERMINAL_UNDEFINED 0x600
|
||||||
|
#define USB_AC_EXT_TERMINAL_ANALOG 0x601
|
||||||
|
#define USB_AC_EXT_TERMINAL_DIGITAL 0x602
|
||||||
|
#define USB_AC_EXT_TERMINAL_LINE 0x603
|
||||||
|
#define USB_AC_EXT_TERMINAL_LEGACY 0x604
|
||||||
|
#define USB_AC_EXT_TERMINAL_SPDIF 0x605
|
||||||
|
#define USB_AC_EXT_TERMINAL_1394_DA 0x606
|
||||||
|
#define USB_AC_EXT_TERMINAL_1394_DV 0x607
|
||||||
|
|
||||||
|
#define USB_AC_EMB_MINIDISK 0x706
|
||||||
|
#define USB_AC_EMB_RADIO_RECV 0x710
|
||||||
|
|
||||||
|
#define USB_AC_INPUT_TERMINAL_UNDEFINED 0x200
|
||||||
|
#define USB_AC_INPUT_TERMINAL_MICROPHONE 0x201
|
||||||
|
#define USB_AC_INPUT_TERMINAL_DESKTOP_MICROPHONE 0x202
|
||||||
|
#define USB_AC_INPUT_TERMINAL_PERSONAL_MICROPHONE 0x203
|
||||||
|
#define USB_AC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE 0x204
|
||||||
|
#define USB_AC_INPUT_TERMINAL_MICROPHONE_ARRAY 0x205
|
||||||
|
#define USB_AC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY 0x206
|
||||||
|
|
||||||
|
struct usb_ac_input_terminal {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType; /* USB_DT_CS_INTERFACE */
|
||||||
|
uint8_t bDescriptorSubType; /* USB_AC_INPUT_TERMINAL */
|
||||||
|
uint8_t bTerminalId;
|
||||||
|
uint16_t wTerminalType; /* USB_AC_INPUT_TERMINAL_* */
|
||||||
|
uint8_t bAssocTerminal;
|
||||||
|
uint8_t bNrChannels;
|
||||||
|
uint16_t wChannelConfig;
|
||||||
|
uint8_t iChannelNames;
|
||||||
|
uint8_t iTerminal;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define USB_AC_OUTPUT_TERMINAL_UNDEFINED 0x300
|
||||||
|
#define USB_AC_OUTPUT_TERMINAL_SPEAKER 0x301
|
||||||
|
#define USB_AC_OUTPUT_TERMINAL_HEADPHONES 0x302
|
||||||
|
#define USB_AC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO 0x303
|
||||||
|
#define USB_AC_OUTPUT_TERMINAL_DESKTOP_SPEAKER 0x304
|
||||||
|
#define USB_AC_OUTPUT_TERMINAL_ROOM_SPEAKER 0x305
|
||||||
|
#define USB_AC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER 0x306
|
||||||
|
#define USB_AC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER 0x307
|
||||||
|
|
||||||
|
struct usb_ac_output_terminal {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType; /* USB_DT_CS_INTERFACE */
|
||||||
|
uint8_t bDescriptorSubType; /* USB_AC_OUTPUT_TERMINAL */
|
||||||
|
uint8_t bTerminalId;
|
||||||
|
uint16_t wTerminalType; /* USB_AC_OUTPUT_TERMINAL_* */
|
||||||
|
uint8_t bAssocTerminal;
|
||||||
|
uint8_t bSourceId;
|
||||||
|
uint8_t iTerminal;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define USB_AC_FU_CONTROL_UNDEFINED 0x00
|
||||||
|
#define USB_AC_MUTE_CONTROL 0x01
|
||||||
|
#define USB_AC_VOLUME_CONTROL 0x02
|
||||||
|
#define USB_AC_BASS_CONTROL 0x03
|
||||||
|
#define USB_AC_MID_CONTROL 0x04
|
||||||
|
#define USB_AC_TREBLE_CONTROL 0x05
|
||||||
|
#define USB_AC_EQUALIZER_CONTROL 0x06
|
||||||
|
#define USB_AC_AUTO_GAIN_CONTROL 0x07
|
||||||
|
#define USB_AC_DELAY_CONTROL 0x08
|
||||||
|
#define USB_AC_BASS_BOOST_CONTROL 0x09
|
||||||
|
#define USB_AC_LOUDNESS_CONTROL 0x0a
|
||||||
|
|
||||||
|
#define USB_AC_FU_MUTE (1 << (USB_AC_MUTE_CONTROL - 1))
|
||||||
|
#define USB_AC_FU_VOLUME (1 << (USB_AC_VOLUME_CONTROL - 1))
|
||||||
|
#define USB_AC_FU_BASS (1 << (USB_AC_BASS_CONTROL - 1))
|
||||||
|
#define USB_AC_FU_MID (1 << (USB_AC_MID_CONTROL - 1))
|
||||||
|
#define USB_AC_FU_TREBLE (1 << (USB_AC_TREBLE_CONTROL - 1))
|
||||||
|
#define USB_AC_FU_EQUILIZER (1 << (USB_AC_EQUALIZER_CONTROL - 1))
|
||||||
|
#define USB_AC_FU_AUTO_GAIN (1 << (USB_AC_AUTO_GAIN_CONTROL - 1))
|
||||||
|
#define USB_AC_FU_DELAY (1 << (USB_AC_DELAY_CONTROL - 1))
|
||||||
|
#define USB_AC_FU_BASS_BOOST (1 << (USB_AC_BASS_BOOST_CONTROL - 1))
|
||||||
|
#define USB_AC_FU_LOUDNESS (1 << (USB_AC_LOUDNESS_CONTROL - 1))
|
||||||
|
|
||||||
|
#define DEFINE_USB_AC_FEATURE_UNIT(n,ch) \
|
||||||
|
struct usb_ac_feature_unit_##n##_##ch { \
|
||||||
|
uint8_t bLength; \
|
||||||
|
uint8_t bDescriptorType; /* USB_DT_CS_INTERFACE */ \
|
||||||
|
uint8_t bDescriptorSubType; /* USB_AC_FEATURE_UNIT */ \
|
||||||
|
uint8_t bUnitId; \
|
||||||
|
uint8_t bSourceId; \
|
||||||
|
uint8_t bControlSize; \
|
||||||
|
uint##n##_t bmaControls[ch + 1]; /* FU_* ORed*/ \
|
||||||
|
uint8_t iFeature; \
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define USB_AC_SET_REQ 0x00
|
||||||
|
#define USB_AC_GET_REQ 0x80
|
||||||
|
|
||||||
|
#define USB_AC_CUR_REQ 0x1
|
||||||
|
#define USB_AC_MIN_REQ 0x2
|
||||||
|
#define USB_AC_MAX_REQ 0x3
|
||||||
|
#define USB_AC_RES_REQ 0x4
|
||||||
|
#define USB_AC_MEM_REQ 0x5
|
||||||
|
|
||||||
|
#define USB_AC_SET_CUR (USB_AC_SET_REQ | USB_AC_CUR_REQ)
|
||||||
|
#define USB_AC_GET_CUR (USB_AC_GET_REQ | USB_AC_CUR_REQ)
|
||||||
|
#define USB_AC_SET_MIN (USB_AC_SET_REQ | USB_AC_MIN_REQ)
|
||||||
|
#define USB_AC_GET_MIN (USB_AC_GET_REQ | USB_AC_MIN_REQ)
|
||||||
|
#define USB_AC_SET_MAX (USB_AC_SET_REQ | USB_AC_MAX_REQ)
|
||||||
|
#define USB_AC_GET_MAX (USB_AC_GET_REQ | USB_AC_MAX_REQ)
|
||||||
|
#define USB_AC_SET_RES (USB_AC_SET_REQ | USB_AC_RES_REQ)
|
||||||
|
#define USB_AC_GET_RES (USB_AC_GET_REQ | USB_AC_RES_REQ)
|
||||||
|
#define USB_AC_SET_MEM (USB_AC_SET_REQ | USB_AC_MEM_REQ)
|
||||||
|
#define USB_AC_GET_MEM (USB_AC_GET_REQ | USB_AC_MEM_REQ)
|
||||||
|
#define USB_AC_GET_STAT 0xff
|
||||||
|
|
||||||
|
#define USB_AS_FORMAT_TYPE_UNDEFINED 0x0
|
||||||
|
#define USB_AS_FORMAT_TYPE_I 0x1
|
||||||
|
#define USB_AS_FORMAT_TYPE_II 0x2
|
||||||
|
#define USB_AS_FORMAT_TYPE_III 0x3
|
||||||
|
|
||||||
|
struct usb_as_interface {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType; /* USB_DT_CS_INTERFACE */
|
||||||
|
uint8_t bDescriptorSubType; /* USB_AS_GENERAL */
|
||||||
|
uint8_t bTerminalLink;
|
||||||
|
uint8_t bDelay;
|
||||||
|
uint16_t wFormatTag;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define USB_AS_EP_GENERAL 0x01
|
||||||
|
|
||||||
|
#define USB_AS_EP_CS_SAMPLING_FREQ_CTL 0x01
|
||||||
|
#define USB_AS_EP_CS_PITCH_CTL 0x02
|
||||||
|
|
||||||
|
struct usb_iso_audio_endpoint_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
|
||||||
|
uint8_t bEndpointAddress;
|
||||||
|
uint8_t bmAttributes;
|
||||||
|
uint16_t wMaxPacketSize;
|
||||||
|
uint8_t bInterval;
|
||||||
|
uint8_t bRefresh;
|
||||||
|
uint8_t bSynchAddress;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct usb_as_iso_endpoint {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType; /* USB_DT_CS_ENDPOINT */
|
||||||
|
uint8_t bDescriptorSubType; /* USB_AS_EP_GENERAL */
|
||||||
|
uint8_t bmAttributes;
|
||||||
|
uint8_t bLockDelayUnits;
|
||||||
|
uint16_t wLockDelay;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define USB_AS_FORMAT_TYPE_I_UNDEFINED 0x0
|
||||||
|
#define USB_AS_FORMAT_TYPE_I_PCM 0x1
|
||||||
|
#define USB_AS_FORMAT_TYPE_I_PCM8 0x2
|
||||||
|
#define USB_AS_FORMAT_TYPE_I_IEEE_FLOAT 0x3
|
||||||
|
#define USB_AS_FORMAT_TYPE_I_ALAW 0x4
|
||||||
|
#define USB_AS_FORMAT_TYPE_I_MULAW 0x5
|
||||||
|
|
||||||
|
struct usb_as_format_type_i_discrete {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType; /* USB_DT_CS_INTERFACE */
|
||||||
|
uint8_t bDescriptorSubType; /* USB_AS_FORMAT_TYPE */
|
||||||
|
uint8_t bFormatType; /* USB_AS_FORMAT_TYPE_I */
|
||||||
|
uint8_t bNrChannels;
|
||||||
|
uint8_t bSubframeSize;
|
||||||
|
uint8_t bBitResolution;
|
||||||
|
uint8_t bSamFreqType; /* Number of discrete frequencies */
|
||||||
|
uint8_t tSamFreq[][3];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define USB_AS_SIZEOF_FORMAT_TYPE_I_DISCRETE(n) (8 + (n * 3))
|
||||||
|
|
||||||
|
#endif /* USB_AUDIO_DEF_H */
|
||||||
|
|
@ -74,7 +74,16 @@ struct usb_class_driver {
|
||||||
/* Tells the driver that a usb transfer has been completed. Note that "dir"
|
/* Tells the driver that a usb transfer has been completed. Note that "dir"
|
||||||
is relative to the host
|
is relative to the host
|
||||||
Optional function */
|
Optional function */
|
||||||
void (*transfer_complete)(int ep,int dir, int status, int length);
|
void (*transfer_complete)(int ep, int dir, int status, int length);
|
||||||
|
|
||||||
|
/* Similar to transfer_complete but called directly instead of going through
|
||||||
|
* the usb queue. Since it might be called in an interrupt context,
|
||||||
|
* processing should be kept to a minimum. This is mainly intended for
|
||||||
|
* isochronous transfers.
|
||||||
|
* The function must return true if it handled the completion, and false
|
||||||
|
* otherwise so that it is dispatched to the normal handler
|
||||||
|
* Optional function */
|
||||||
|
bool (*fast_transfer_complete)(int ep, int dir, int status, int length);
|
||||||
|
|
||||||
/* Tells the driver that a control request has come in. If the driver is
|
/* Tells the driver that a control request has come in. If the driver is
|
||||||
able to handle it, it should ack the request, and return true. Otherwise
|
able to handle it, it should ack the request, and return true. Otherwise
|
||||||
|
|
@ -88,6 +97,16 @@ struct usb_class_driver {
|
||||||
Optional function */
|
Optional function */
|
||||||
void (*notify_hotswap)(int volume, bool inserted);
|
void (*notify_hotswap)(int volume, bool inserted);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Tells the driver to select an alternate setting for a specific interface.
|
||||||
|
* Returns 0 on success and -1 on error.
|
||||||
|
* Mandatory function if alternate interface support is needed */
|
||||||
|
int (*set_interface)(int interface, int alt_setting);
|
||||||
|
|
||||||
|
/* Asks the driver what is the current alternate setting for a specific interface.
|
||||||
|
* Returns value on success and -1 on error.
|
||||||
|
* Mandatory function if alternate interface support is needed */
|
||||||
|
int (*get_interface)(int interface);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PACK_DATA(dest, data) pack_data(dest, &(data), sizeof(data))
|
#define PACK_DATA(dest, data) pack_data(dest, &(data), sizeof(data))
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,11 @@
|
||||||
#include "usb_hid.h"
|
#include "usb_hid.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
#include "usb_audio.h"
|
||||||
|
#include "usb_audio_def.h" // DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
/* TODO: Move target-specific stuff somewhere else (serial number reading) */
|
/* TODO: Move target-specific stuff somewhere else (serial number reading) */
|
||||||
|
|
||||||
#if defined(IPOD_ARCH) && defined(CPU_PP)
|
#if defined(IPOD_ARCH) && defined(CPU_PP)
|
||||||
|
|
@ -166,12 +171,14 @@ static int usb_no_host_callback(struct timeout *tmo)
|
||||||
static int usb_core_num_interfaces;
|
static int usb_core_num_interfaces;
|
||||||
|
|
||||||
typedef void (*completion_handler_t)(int ep, int dir, int status, int length);
|
typedef void (*completion_handler_t)(int ep, int dir, int status, int length);
|
||||||
|
typedef bool (*fast_completion_handler_t)(int ep, int dir, int status, int length);
|
||||||
typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, void* reqdata,
|
typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, void* reqdata,
|
||||||
unsigned char* dest);
|
unsigned char* dest);
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
completion_handler_t completion_handler[2];
|
completion_handler_t completion_handler[2];
|
||||||
|
fast_completion_handler_t fast_completion_handler[2];
|
||||||
control_handler_t control_handler[2];
|
control_handler_t control_handler[2];
|
||||||
struct usb_transfer_completion_event_data completion_event[2];
|
struct usb_transfer_completion_event_data completion_event[2];
|
||||||
} ep_data[USB_NUM_ENDPOINTS];
|
} ep_data[USB_NUM_ENDPOINTS];
|
||||||
|
|
@ -254,6 +261,28 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
|
||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USB_ENABLE_AUDIO
|
||||||
|
[USB_DRIVER_AUDIO] = {
|
||||||
|
.enabled = false,
|
||||||
|
.needs_exclusive_storage = false,
|
||||||
|
.first_interface = 0,
|
||||||
|
.last_interface = 0,
|
||||||
|
.request_endpoints = usb_audio_request_endpoints,
|
||||||
|
.set_first_interface = usb_audio_set_first_interface,
|
||||||
|
.get_config_descriptor = usb_audio_get_config_descriptor,
|
||||||
|
.init_connection = usb_audio_init_connection,
|
||||||
|
.init = usb_audio_init,
|
||||||
|
.disconnect = usb_audio_disconnect,
|
||||||
|
.transfer_complete = usb_audio_transfer_complete,
|
||||||
|
.fast_transfer_complete = usb_audio_fast_transfer_complete,
|
||||||
|
.control_request = usb_audio_control_request,
|
||||||
|
#ifdef HAVE_HOTSWAP
|
||||||
|
.notify_hotswap = NULL,
|
||||||
|
#endif
|
||||||
|
.set_interface = usb_audio_set_interface,
|
||||||
|
.get_interface = usb_audio_get_interface,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USB_LEGACY_CONTROL_API
|
#ifdef USB_LEGACY_CONTROL_API
|
||||||
|
|
@ -542,6 +571,7 @@ int usb_core_request_endpoint(int type, int dir, struct usb_class_driver* drv)
|
||||||
ep = EP_NUM(ret);
|
ep = EP_NUM(ret);
|
||||||
|
|
||||||
ep_data[ep].completion_handler[dir] = drv->transfer_complete;
|
ep_data[ep].completion_handler[dir] = drv->transfer_complete;
|
||||||
|
ep_data[ep].fast_completion_handler[dir] = drv->fast_transfer_complete;
|
||||||
ep_data[ep].control_handler[dir] = drv->control_request;
|
ep_data[ep].control_handler[dir] = drv->control_request;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -598,16 +628,46 @@ static void control_request_handler_drivers(struct usb_ctrlrequest* req, void* r
|
||||||
if(drivers[i].enabled &&
|
if(drivers[i].enabled &&
|
||||||
drivers[i].control_request &&
|
drivers[i].control_request &&
|
||||||
drivers[i].first_interface <= interface &&
|
drivers[i].first_interface <= interface &&
|
||||||
drivers[i].last_interface > interface)
|
drivers[i].last_interface > interface) {
|
||||||
{
|
/* Check for SET_INTERFACE and GET_INTERFACE */
|
||||||
|
if((req->bRequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE &&
|
||||||
|
(req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
|
||||||
|
|
||||||
|
if(req->bRequest == USB_REQ_SET_INTERFACE) {
|
||||||
|
logf("usb_core: SET INTERFACE 0x%x 0x%x", req->wValue, req->wIndex);
|
||||||
|
if(drivers[i].set_interface &&
|
||||||
|
drivers[i].set_interface(req->wIndex, req->wValue) >= 0) {
|
||||||
|
|
||||||
|
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(req->bRequest == USB_REQ_GET_INTERFACE) {
|
||||||
|
int alt = -1;
|
||||||
|
logf("usb_core: GET INTERFACE 0x%x", req->wIndex);
|
||||||
|
|
||||||
|
if(drivers[i].get_interface)
|
||||||
|
alt = drivers[i].get_interface(req->wIndex);
|
||||||
|
|
||||||
|
if(alt >= 0 && alt < 255) {
|
||||||
|
response_data[0] = alt;
|
||||||
|
usb_drv_control_response(USB_CONTROL_ACK, response_data, 1);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fallback */
|
||||||
|
}
|
||||||
|
|
||||||
handled = drivers[i].control_request(req, reqdata, response_data);
|
handled = drivers[i].control_request(req, reqdata, response_data);
|
||||||
if(handled)
|
break; /* no other driver can handle it because it's interface specific */
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!handled) {
|
if(!handled) {
|
||||||
/* nope. flag error */
|
/* nope. flag error */
|
||||||
logf("bad req:desc %d:%d", req->bRequest, req->wValue >> 8);
|
logf("bad req 0x%x:0x%x:0x%x:0x%x:0x%x", req->bRequestType,req->bRequest,
|
||||||
|
req->wValue, req->wIndex, req->wLength);
|
||||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -804,13 +864,9 @@ static void request_handler_interface_standard(struct usb_ctrlrequest* req, void
|
||||||
{
|
{
|
||||||
case USB_REQ_SET_INTERFACE:
|
case USB_REQ_SET_INTERFACE:
|
||||||
logf("usb_core: SET_INTERFACE");
|
logf("usb_core: SET_INTERFACE");
|
||||||
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_GET_INTERFACE:
|
case USB_REQ_GET_INTERFACE:
|
||||||
logf("usb_core: GET_INTERFACE");
|
control_request_handler_drivers(req, reqdata);
|
||||||
response_data[0] = 0;
|
break;
|
||||||
usb_drv_control_response(USB_CONTROL_ACK, response_data, 1);
|
|
||||||
break;
|
break;
|
||||||
case USB_REQ_GET_STATUS:
|
case USB_REQ_GET_STATUS:
|
||||||
response_data[0] = 0;
|
response_data[0] = 0;
|
||||||
|
|
@ -860,7 +916,8 @@ static void request_handler_endpoint_drivers(struct usb_ctrlrequest* req, void*
|
||||||
|
|
||||||
if(!handled) {
|
if(!handled) {
|
||||||
/* nope. flag error */
|
/* nope. flag error */
|
||||||
logf("usb bad req %d", req->bRequest);
|
logf("bad req 0x%x:0x%x:0x%x:0x%x:0x%x", req->bRequestType,req->bRequest,
|
||||||
|
req->wValue, req->wIndex, req->wLength);
|
||||||
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
usb_drv_control_response(USB_CONTROL_STALL, NULL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -970,6 +1027,10 @@ void usb_core_transfer_complete(int endpoint, int dir, int status, int length)
|
||||||
{
|
{
|
||||||
struct usb_transfer_completion_event_data* completion_event =
|
struct usb_transfer_completion_event_data* completion_event =
|
||||||
&ep_data[endpoint].completion_event[EP_DIR(dir)];
|
&ep_data[endpoint].completion_event[EP_DIR(dir)];
|
||||||
|
/* Fast notification */
|
||||||
|
fast_completion_handler_t handler = ep_data[endpoint].fast_completion_handler[EP_DIR(dir)];
|
||||||
|
if(handler != NULL && handler(endpoint, dir, status, length))
|
||||||
|
return; /* do not dispatch to the queue if handled */
|
||||||
|
|
||||||
void* data0 = NULL;
|
void* data0 = NULL;
|
||||||
void* data1 = NULL;
|
void* data1 = NULL;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue