iAP: lingo 1 (microphone)
Change-Id: I65da2064951972368a2880d271280e5b5ae878fe
This commit is contained in:
parent
b2d650f511
commit
be5fc0ff7f
7 changed files with 271 additions and 1 deletions
|
@ -64,6 +64,9 @@ scrobbler.c
|
|||
#ifdef IPOD_ACCESSORY_PROTOCOL
|
||||
iap/iap-core.c
|
||||
iap/iap-lingo0.c
|
||||
#ifdef HAVE_LINE_REC
|
||||
iap/iap-lingo1.c
|
||||
#endif
|
||||
iap/iap-lingo2.c
|
||||
iap/iap-lingo3.c
|
||||
iap/iap-lingo4.c
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
#if CONFIG_TUNER
|
||||
#include "radio.h"
|
||||
#endif
|
||||
#if defined(IPOD_ACCESSORY_PROTOCOL) && defined(HAVE_LINE_REC)
|
||||
#include "iap.h"
|
||||
#endif
|
||||
|
||||
/* Some audio sources may require a boosted CPU */
|
||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||
|
@ -95,6 +98,13 @@ void audio_set_input_source(int source, unsigned flags)
|
|||
radio_start();
|
||||
#endif
|
||||
|
||||
#if defined(IPOD_ACCESSORY_PROTOCOL) && defined(HAVE_LINE_REC)
|
||||
static bool last_rec_onoff = false;
|
||||
bool onoff = (source == AUDIO_SRC_LINEIN) ? true : false;
|
||||
if (last_rec_onoff != onoff)
|
||||
last_rec_onoff = iap_record(onoff);
|
||||
#endif
|
||||
|
||||
/* set hardware inputs */
|
||||
audio_input_mux(source, flags);
|
||||
} /* audio_set_source */
|
||||
|
|
|
@ -154,7 +154,11 @@ unsigned char* iap_txnext;
|
|||
*/
|
||||
unsigned char lingo_versions[32][2] = {
|
||||
{1, 9}, /* General lingo, 0x00 */
|
||||
{0, 0}, /* Microphone lingo, 0x01, unsupported */
|
||||
#ifdef HAVE_LINE_REC
|
||||
{1, 1}, /* Microphone lingo, 0x01 */
|
||||
#else
|
||||
{0, 0}, /* Microphone lingo, 0x01, disabled */
|
||||
#endif
|
||||
{1, 2}, /* Simple remote lingo, 0x02 */
|
||||
{1, 5}, /* Display remote lingo, 0x03 */
|
||||
{1, 12}, /* Extended Interface lingo, 0x04 */
|
||||
|
@ -1262,6 +1266,9 @@ void iap_handlepkt(void)
|
|||
unsigned char mode = *(iap_rxstart+2);
|
||||
switch (mode) {
|
||||
case 0: iap_handlepkt_mode0(length, iap_rxstart+2); break;
|
||||
#ifdef HAVE_LINE_REC
|
||||
case 1: iap_handlepkt_mode1(length, iap_rxstart+2); break;
|
||||
#endif
|
||||
case 2: iap_handlepkt_mode2(length, iap_rxstart+2); break;
|
||||
case 3: iap_handlepkt_mode3(length, iap_rxstart+2); break;
|
||||
case 4: iap_handlepkt_mode4(length, iap_rxstart+2); break;
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
****************************************************************************/
|
||||
|
||||
void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf);
|
||||
#ifdef HAVE_LINE_REC
|
||||
void iap_handlepkt_mode1(const unsigned int len, const unsigned char *buf);
|
||||
#endif
|
||||
void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf);
|
||||
void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf);
|
||||
void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf);
|
||||
|
|
218
apps/iap/iap-lingo1.c
Normal file
218
apps/iap/iap-lingo1.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 by Alan Korr & Nick Robinson
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Lingo 0x01: Microphone Lingo
|
||||
*/
|
||||
|
||||
#include "iap-core.h"
|
||||
#include "iap-lingo.h"
|
||||
|
||||
/*
|
||||
* This macro is meant to be used inside an IAP mode message handler.
|
||||
* It is passed the expected minimum length of the message buffer.
|
||||
* If the buffer does not have the required lenght an ACK
|
||||
* packet with a Bad Parameter error is generated.
|
||||
*/
|
||||
#define CHECKLEN(x) do { \
|
||||
if (len < (x)) { \
|
||||
cmd_ack(cmd, IAP_ACK_BAD_PARAM); \
|
||||
return; \
|
||||
}} while(0)
|
||||
|
||||
/* Check for authenticated state, and return an ACK Not
|
||||
* Authenticated on failure.
|
||||
*/
|
||||
#define CHECKAUTH do { \
|
||||
if (!DEVICE_AUTHENTICATED) { \
|
||||
cmd_ack(cmd, IAP_ACK_NO_AUTHEN); \
|
||||
return; \
|
||||
}} while(0)
|
||||
|
||||
static void cmd_ack(const unsigned char cmd, const unsigned char status)
|
||||
{
|
||||
IAP_TX_INIT(0x03, 0x00);
|
||||
IAP_TX_PUT(status);
|
||||
IAP_TX_PUT(cmd);
|
||||
|
||||
iap_send_tx();
|
||||
}
|
||||
|
||||
/* returns record status */
|
||||
bool iap_record(bool onoff)
|
||||
{
|
||||
if (!DEVICE_LINGO_SUPPORTED(0x01))
|
||||
return false;
|
||||
|
||||
/* iPodModeChange */
|
||||
IAP_TX_INIT(0x01, 0x06);
|
||||
IAP_TX_PUT(onoff ? 0x00 : 0x01);
|
||||
iap_send_tx();
|
||||
|
||||
return onoff;
|
||||
}
|
||||
|
||||
void iap_handlepkt_mode1(const unsigned int len, const unsigned char *buf)
|
||||
{
|
||||
unsigned int cmd = buf[1];
|
||||
|
||||
/* Lingo 0x04 commands are at least 4 bytes in length */
|
||||
CHECKLEN(4);
|
||||
|
||||
/* Lingo 0x01 must have been negotiated */
|
||||
if (!DEVICE_LINGO_SUPPORTED(0x01)) {
|
||||
cmd_ack(cmd, IAP_ACK_BAD_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Authentication required for all commands */
|
||||
CHECKAUTH;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
/* BeginRecord (0x00) Deprecated
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* EndRecord (0x01) Deprecated
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* BeginPlayback (0x02) Deprecated
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* EndPlayback (0x03) Deprecated
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* ACK (0x04)
|
||||
*
|
||||
* The device sends an ACK response when a command
|
||||
* that does not return any data has completed.
|
||||
*
|
||||
* Packet format (offset in buf[]: Description)
|
||||
* 0x00: Lingo ID: Microphone Lingo, always 0x01
|
||||
* 0x01: Command, always 0x04
|
||||
* 0x02: The command result status
|
||||
* 0x03: The ID of the command for which the
|
||||
* response is being sent
|
||||
*
|
||||
* Returns: (none)
|
||||
*/
|
||||
case 0x04:
|
||||
#ifdef LOGF_ENABLE
|
||||
if (buf[2] != 0x00)
|
||||
logf("iap: Mode1 Command ACK error: "
|
||||
"0x%02x 0x%02x", buf[2], buf[3]);
|
||||
#endif
|
||||
break;
|
||||
|
||||
/* GetDevAck (0x05)
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* iPodModeChange (0x06)
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* GetDevCaps (0x07)
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* RetDevCaps (0x08)
|
||||
*
|
||||
* The microphone device returns the payload
|
||||
* indicating which capabilities it supports.
|
||||
*
|
||||
* Packet format (offset in buf[]: Description)
|
||||
* 0x00: Lingo ID: Microphone Lingo, always 0x01
|
||||
* 0x01: Command, always 0x08
|
||||
* 0x02: Device capabilities (bits 31:24)
|
||||
* 0x03: Device capabilities (bits 23:16)
|
||||
* 0x04: Device capabilities (bits 15:8)
|
||||
* 0x05: Device capabilities (bits 7:0)
|
||||
*
|
||||
* Returns:
|
||||
* SetDevCtrl, sets stereo line input when supported
|
||||
*/
|
||||
case 0x08:
|
||||
CHECKLEN(6);
|
||||
|
||||
if ((buf[5] & 3) == 3) {
|
||||
/* SetDevCtrl, set stereo line-in */
|
||||
IAP_TX_INIT(0x01, 0x0B);
|
||||
IAP_TX_PUT(0x01);
|
||||
IAP_TX_PUT(0x01);
|
||||
|
||||
iap_send_tx();
|
||||
}
|
||||
|
||||
/* TODO?: configure recording level/limiter controls
|
||||
when supported by the device */
|
||||
|
||||
break;
|
||||
|
||||
/* GetDevCtrl (0x09)
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* RetDevCaps (0x0A)
|
||||
*
|
||||
* The device returns the current control state
|
||||
* for the specified control type.
|
||||
*
|
||||
* Packet format (offset in buf[]: Description)
|
||||
* 0x00: Lingo ID: Microphone Lingo, always 0x01
|
||||
* 0x01: Command, always 0x0A
|
||||
* 0x02: The control type
|
||||
* 0x03: The control data
|
||||
*/
|
||||
case 0x0A:
|
||||
switch (buf[2])
|
||||
{
|
||||
case 0x01: /* stereo/mono line-in control */
|
||||
case 0x02: /* recording level control */
|
||||
case 0x03: /* recording level limiter control */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* SetDevCtrl (0x0B)
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* The default response is IAP_ACK_BAD_PARAM */
|
||||
default:
|
||||
{
|
||||
#ifdef LOGF_ENABLE
|
||||
logf("iap: Unsupported Mode1 Command");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,7 @@ static void cmd_ack(const unsigned char cmd, const unsigned char status)
|
|||
|
||||
void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
|
||||
{
|
||||
static bool poweron_pressed = false;
|
||||
unsigned int cmd = buf[1];
|
||||
|
||||
/* We expect at least three bytes in the buffer, one for the
|
||||
|
@ -136,6 +137,11 @@ void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
|
|||
}
|
||||
}
|
||||
|
||||
if (buf[4] & 2) /* power on */
|
||||
{
|
||||
poweron_pressed = true;
|
||||
}
|
||||
|
||||
/* Power off
|
||||
* Not quite sure how to react to this, but stopping playback
|
||||
* is a good start.
|
||||
|
@ -152,6 +158,26 @@ void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
|
|||
REMOTE_BUTTON(BUTTON_RC_LEFT);
|
||||
}
|
||||
|
||||
/* power on released */
|
||||
if (poweron_pressed && len >= 5 && !(buf[4] & 2))
|
||||
{
|
||||
poweron_pressed = false;
|
||||
#ifdef HAVE_LINE_REC
|
||||
/* Belkin TuneTalk microphone sends power-on press+release
|
||||
* events once authentication sequence is finished,
|
||||
* GetDevCaps command is ignored by the device when it is
|
||||
* sent before power-on release event is received.
|
||||
* XXX: It is unknown if other microphone devices are
|
||||
* sending the power-on events.
|
||||
*/
|
||||
if (DEVICE_LINGO_SUPPORTED(0x01)) {
|
||||
/* GetDevCaps */
|
||||
IAP_TX_INIT(0x01, 0x07);
|
||||
iap_send_tx();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
/* ACK (0x01)
|
||||
|
|
|
@ -34,5 +34,8 @@ extern void iap_periodic(void);
|
|||
extern void iap_handlepkt(void);
|
||||
extern void iap_send_pkt(const unsigned char * data, int len);
|
||||
const unsigned char *iap_get_serbuf(void);
|
||||
#ifdef HAVE_LINE_REC
|
||||
extern bool iap_record(bool onoff);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue