summaryrefslogtreecommitdiff
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
64#ifdef IPOD_ACCESSORY_PROTOCOL 64#ifdef IPOD_ACCESSORY_PROTOCOL
65iap/iap-core.c 65iap/iap-core.c
66iap/iap-lingo0.c 66iap/iap-lingo0.c
67#ifdef HAVE_LINE_REC
68iap/iap-lingo1.c
69#endif
67iap/iap-lingo2.c 70iap/iap-lingo2.c
68iap/iap-lingo3.c 71iap/iap-lingo3.c
69iap/iap-lingo4.c 72iap/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 @@
34#if CONFIG_TUNER 34#if CONFIG_TUNER
35#include "radio.h" 35#include "radio.h"
36#endif 36#endif
37#if defined(IPOD_ACCESSORY_PROTOCOL) && defined(HAVE_LINE_REC)
38#include "iap.h"
39#endif
37 40
38/* Some audio sources may require a boosted CPU */ 41/* Some audio sources may require a boosted CPU */
39#ifdef HAVE_ADJUSTABLE_CPU_FREQ 42#ifdef HAVE_ADJUSTABLE_CPU_FREQ
@@ -95,6 +98,13 @@ void audio_set_input_source(int source, unsigned flags)
95 radio_start(); 98 radio_start();
96#endif 99#endif
97 100
101#if defined(IPOD_ACCESSORY_PROTOCOL) && defined(HAVE_LINE_REC)
102 static bool last_rec_onoff = false;
103 bool onoff = (source == AUDIO_SRC_LINEIN) ? true : false;
104 if (last_rec_onoff != onoff)
105 last_rec_onoff = iap_record(onoff);
106#endif
107
98 /* set hardware inputs */ 108 /* set hardware inputs */
99 audio_input_mux(source, flags); 109 audio_input_mux(source, flags);
100} /* audio_set_source */ 110} /* 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;
154 */ 154 */
155unsigned char lingo_versions[32][2] = { 155unsigned char lingo_versions[32][2] = {
156 {1, 9}, /* General lingo, 0x00 */ 156 {1, 9}, /* General lingo, 0x00 */
157 {0, 0}, /* Microphone lingo, 0x01, unsupported */ 157#ifdef HAVE_LINE_REC
158 {1, 1}, /* Microphone lingo, 0x01 */
159#else
160 {0, 0}, /* Microphone lingo, 0x01, disabled */
161#endif
158 {1, 2}, /* Simple remote lingo, 0x02 */ 162 {1, 2}, /* Simple remote lingo, 0x02 */
159 {1, 5}, /* Display remote lingo, 0x03 */ 163 {1, 5}, /* Display remote lingo, 0x03 */
160 {1, 12}, /* Extended Interface lingo, 0x04 */ 164 {1, 12}, /* Extended Interface lingo, 0x04 */
@@ -1262,6 +1266,9 @@ void iap_handlepkt(void)
1262 unsigned char mode = *(iap_rxstart+2); 1266 unsigned char mode = *(iap_rxstart+2);
1263 switch (mode) { 1267 switch (mode) {
1264 case 0: iap_handlepkt_mode0(length, iap_rxstart+2); break; 1268 case 0: iap_handlepkt_mode0(length, iap_rxstart+2); break;
1269#ifdef HAVE_LINE_REC
1270 case 1: iap_handlepkt_mode1(length, iap_rxstart+2); break;
1271#endif
1265 case 2: iap_handlepkt_mode2(length, iap_rxstart+2); break; 1272 case 2: iap_handlepkt_mode2(length, iap_rxstart+2); break;
1266 case 3: iap_handlepkt_mode3(length, iap_rxstart+2); break; 1273 case 3: iap_handlepkt_mode3(length, iap_rxstart+2); break;
1267 case 4: iap_handlepkt_mode4(length, iap_rxstart+2); break; 1274 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 @@
18 ****************************************************************************/ 18 ****************************************************************************/
19 19
20void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf); 20void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf);
21#ifdef HAVE_LINE_REC
22void iap_handlepkt_mode1(const unsigned int len, const unsigned char *buf);
23#endif
21void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf); 24void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf);
22void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf); 25void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf);
23void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf); 26void 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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
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/* Lingo 0x01: Microphone Lingo
21 */
22
23#include "iap-core.h"
24#include "iap-lingo.h"
25
26/*
27 * This macro is meant to be used inside an IAP mode message handler.
28 * It is passed the expected minimum length of the message buffer.
29 * If the buffer does not have the required lenght an ACK
30 * packet with a Bad Parameter error is generated.
31 */
32#define CHECKLEN(x) do { \
33 if (len < (x)) { \
34 cmd_ack(cmd, IAP_ACK_BAD_PARAM); \
35 return; \
36 }} while(0)
37
38/* Check for authenticated state, and return an ACK Not
39 * Authenticated on failure.
40 */
41#define CHECKAUTH do { \
42 if (!DEVICE_AUTHENTICATED) { \
43 cmd_ack(cmd, IAP_ACK_NO_AUTHEN); \
44 return; \
45 }} while(0)
46
47static void cmd_ack(const unsigned char cmd, const unsigned char status)
48{
49 IAP_TX_INIT(0x03, 0x00);
50 IAP_TX_PUT(status);
51 IAP_TX_PUT(cmd);
52
53 iap_send_tx();
54}
55
56/* returns record status */
57bool iap_record(bool onoff)
58{
59 if (!DEVICE_LINGO_SUPPORTED(0x01))
60 return false;
61
62 /* iPodModeChange */
63 IAP_TX_INIT(0x01, 0x06);
64 IAP_TX_PUT(onoff ? 0x00 : 0x01);
65 iap_send_tx();
66
67 return onoff;
68}
69
70void iap_handlepkt_mode1(const unsigned int len, const unsigned char *buf)
71{
72 unsigned int cmd = buf[1];
73
74 /* Lingo 0x04 commands are at least 4 bytes in length */
75 CHECKLEN(4);
76
77 /* Lingo 0x01 must have been negotiated */
78 if (!DEVICE_LINGO_SUPPORTED(0x01)) {
79 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
80 return;
81 }
82
83 /* Authentication required for all commands */
84 CHECKAUTH;
85
86 switch (cmd)
87 {
88 /* BeginRecord (0x00) Deprecated
89 *
90 * Sent from the iPod to the device
91 */
92
93 /* EndRecord (0x01) Deprecated
94 *
95 * Sent from the iPod to the device
96 */
97
98 /* BeginPlayback (0x02) Deprecated
99 *
100 * Sent from the iPod to the device
101 */
102
103 /* EndPlayback (0x03) Deprecated
104 *
105 * Sent from the iPod to the device
106 */
107
108 /* ACK (0x04)
109 *
110 * The device sends an ACK response when a command
111 * that does not return any data has completed.
112 *
113 * Packet format (offset in buf[]: Description)
114 * 0x00: Lingo ID: Microphone Lingo, always 0x01
115 * 0x01: Command, always 0x04
116 * 0x02: The command result status
117 * 0x03: The ID of the command for which the
118 * response is being sent
119 *
120 * Returns: (none)
121 */
122 case 0x04:
123#ifdef LOGF_ENABLE
124 if (buf[2] != 0x00)
125 logf("iap: Mode1 Command ACK error: "
126 "0x%02x 0x%02x", buf[2], buf[3]);
127#endif
128 break;
129
130 /* GetDevAck (0x05)
131 *
132 * Sent from the iPod to the device
133 */
134
135 /* iPodModeChange (0x06)
136 *
137 * Sent from the iPod to the device
138 */
139
140 /* GetDevCaps (0x07)
141 *
142 * Sent from the iPod to the device
143 */
144
145 /* RetDevCaps (0x08)
146 *
147 * The microphone device returns the payload
148 * indicating which capabilities it supports.
149 *
150 * Packet format (offset in buf[]: Description)
151 * 0x00: Lingo ID: Microphone Lingo, always 0x01
152 * 0x01: Command, always 0x08
153 * 0x02: Device capabilities (bits 31:24)
154 * 0x03: Device capabilities (bits 23:16)
155 * 0x04: Device capabilities (bits 15:8)
156 * 0x05: Device capabilities (bits 7:0)
157 *
158 * Returns:
159 * SetDevCtrl, sets stereo line input when supported
160 */
161 case 0x08:
162 CHECKLEN(6);
163
164 if ((buf[5] & 3) == 3) {
165 /* SetDevCtrl, set stereo line-in */
166 IAP_TX_INIT(0x01, 0x0B);
167 IAP_TX_PUT(0x01);
168 IAP_TX_PUT(0x01);
169
170 iap_send_tx();
171 }
172
173 /* TODO?: configure recording level/limiter controls
174 when supported by the device */
175
176 break;
177
178 /* GetDevCtrl (0x09)
179 *
180 * Sent from the iPod to the device
181 */
182
183 /* RetDevCaps (0x0A)
184 *
185 * The device returns the current control state
186 * for the specified control type.
187 *
188 * Packet format (offset in buf[]: Description)
189 * 0x00: Lingo ID: Microphone Lingo, always 0x01
190 * 0x01: Command, always 0x0A
191 * 0x02: The control type
192 * 0x03: The control data
193 */
194 case 0x0A:
195 switch (buf[2])
196 {
197 case 0x01: /* stereo/mono line-in control */
198 case 0x02: /* recording level control */
199 case 0x03: /* recording level limiter control */
200 break;
201 }
202 break;
203
204 /* SetDevCtrl (0x0B)
205 *
206 * Sent from the iPod to the device
207 */
208
209 /* The default response is IAP_ACK_BAD_PARAM */
210 default:
211 {
212#ifdef LOGF_ENABLE
213 logf("iap: Unsupported Mode1 Command");
214#endif
215 break;
216 }
217 }
218}
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)
56 56
57void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf) 57void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
58{ 58{
59 static bool poweron_pressed = false;
59 unsigned int cmd = buf[1]; 60 unsigned int cmd = buf[1];
60 61
61 /* We expect at least three bytes in the buffer, one for the 62 /* 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)
136 } 137 }
137 } 138 }
138 139
140 if (buf[4] & 2) /* power on */
141 {
142 poweron_pressed = true;
143 }
144
139 /* Power off 145 /* Power off
140 * Not quite sure how to react to this, but stopping playback 146 * Not quite sure how to react to this, but stopping playback
141 * is a good start. 147 * is a good start.
@@ -152,6 +158,26 @@ void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
152 REMOTE_BUTTON(BUTTON_RC_LEFT); 158 REMOTE_BUTTON(BUTTON_RC_LEFT);
153 } 159 }
154 160
161 /* power on released */
162 if (poweron_pressed && len >= 5 && !(buf[4] & 2))
163 {
164 poweron_pressed = false;
165#ifdef HAVE_LINE_REC
166 /* Belkin TuneTalk microphone sends power-on press+release
167 * events once authentication sequence is finished,
168 * GetDevCaps command is ignored by the device when it is
169 * sent before power-on release event is received.
170 * XXX: It is unknown if other microphone devices are
171 * sending the power-on events.
172 */
173 if (DEVICE_LINGO_SUPPORTED(0x01)) {
174 /* GetDevCaps */
175 IAP_TX_INIT(0x01, 0x07);
176 iap_send_tx();
177 }
178#endif
179 }
180
155 break; 181 break;
156 } 182 }
157 /* ACK (0x01) 183 /* 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);
34extern void iap_handlepkt(void); 34extern void iap_handlepkt(void);
35extern void iap_send_pkt(const unsigned char * data, int len); 35extern void iap_send_pkt(const unsigned char * data, int len);
36const unsigned char *iap_get_serbuf(void); 36const unsigned char *iap_get_serbuf(void);
37#ifdef HAVE_LINE_REC
38extern bool iap_record(bool onoff);
39#endif
37 40
38#endif 41#endif