summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/SOURCES3
-rw-r--r--apps/audio_path.c10
-rw-r--r--apps/iap/iap-core.c9
-rw-r--r--apps/iap/iap-lingo.h3
-rw-r--r--apps/iap/iap-lingo1.c218
-rw-r--r--apps/iap/iap-lingo2.c26
-rw-r--r--firmware/export/iap.h3
7 files changed, 271 insertions, 1 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 0965c498b6..c2d591a18b 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -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
diff --git a/apps/audio_path.c b/apps/audio_path.c
index c4a4d1b277..6709d4421d 100644
--- a/apps/audio_path.c
+++ b/apps/audio_path.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 */
diff --git a/apps/iap/iap-core.c b/apps/iap/iap-core.c
index 9e5771ab50..e41660392c 100644
--- a/apps/iap/iap-core.c
+++ b/apps/iap/iap-core.c
@@ -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;
diff --git a/apps/iap/iap-lingo.h b/apps/iap/iap-lingo.h
index 0c0a9e633d..888490c26a 100644
--- a/apps/iap/iap-lingo.h
+++ b/apps/iap/iap-lingo.h
@@ -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);
diff --git a/apps/iap/iap-lingo1.c b/apps/iap/iap-lingo1.c
new file mode 100644
index 0000000000..5702500f23
--- /dev/null
+++ b/apps/iap/iap-lingo1.c
@@ -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;
+ }
+ }
+}
diff --git a/apps/iap/iap-lingo2.c b/apps/iap/iap-lingo2.c
index 4fbf730192..d4c2f18c2f 100644
--- a/apps/iap/iap-lingo2.c
+++ b/apps/iap/iap-lingo2.c
@@ -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)
diff --git a/firmware/export/iap.h b/firmware/export/iap.h
index 22f36083d1..2626f48355 100644
--- a/firmware/export/iap.h
+++ b/firmware/export/iap.h
@@ -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