diff options
author | Cástor Muñoz <cmvidal@gmail.com> | 2014-12-06 23:28:31 +0100 |
---|---|---|
committer | Cástor Muñoz <cmvidal@gmail.com> | 2015-10-07 06:15:04 +0200 |
commit | be5fc0ff7f01ad2e5b964ca437674c15a7a8bd71 (patch) | |
tree | 67224c1d0e40d1e053cb2f41fc751ba1c95149bd | |
parent | b2d650f511d1eef08138f09ecd4e96656eef173b (diff) | |
download | rockbox-be5fc0ff7f01ad2e5b964ca437674c15a7a8bd71.tar.gz rockbox-be5fc0ff7f01ad2e5b964ca437674c15a7a8bd71.zip |
iAP: lingo 1 (microphone)
Change-Id: I65da2064951972368a2880d271280e5b5ae878fe
-rw-r--r-- | apps/SOURCES | 3 | ||||
-rw-r--r-- | apps/audio_path.c | 10 | ||||
-rw-r--r-- | apps/iap/iap-core.c | 9 | ||||
-rw-r--r-- | apps/iap/iap-lingo.h | 3 | ||||
-rw-r--r-- | apps/iap/iap-lingo1.c | 218 | ||||
-rw-r--r-- | apps/iap/iap-lingo2.c | 26 | ||||
-rw-r--r-- | firmware/export/iap.h | 3 |
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 |
65 | iap/iap-core.c | 65 | iap/iap-core.c |
66 | iap/iap-lingo0.c | 66 | iap/iap-lingo0.c |
67 | #ifdef HAVE_LINE_REC | ||
68 | iap/iap-lingo1.c | ||
69 | #endif | ||
67 | iap/iap-lingo2.c | 70 | iap/iap-lingo2.c |
68 | iap/iap-lingo3.c | 71 | iap/iap-lingo3.c |
69 | iap/iap-lingo4.c | 72 | 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 @@ | |||
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 | */ |
155 | unsigned char lingo_versions[32][2] = { | 155 | unsigned 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 | ||
20 | void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf); | 20 | void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf); |
21 | #ifdef HAVE_LINE_REC | ||
22 | void iap_handlepkt_mode1(const unsigned int len, const unsigned char *buf); | ||
23 | #endif | ||
21 | void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf); | 24 | void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf); |
22 | void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf); | 25 | void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf); |
23 | void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf); | 26 | 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 @@ | |||
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 | |||
47 | static 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 */ | ||
57 | bool 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 | |||
70 | void 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 | ||
57 | void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf) | 57 | void 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); | |||
34 | extern void iap_handlepkt(void); | 34 | extern void iap_handlepkt(void); |
35 | extern void iap_send_pkt(const unsigned char * data, int len); | 35 | extern void iap_send_pkt(const unsigned char * data, int len); |
36 | const unsigned char *iap_get_serbuf(void); | 36 | const unsigned char *iap_get_serbuf(void); |
37 | #ifdef HAVE_LINE_REC | ||
38 | extern bool iap_record(bool onoff); | ||
39 | #endif | ||
37 | 40 | ||
38 | #endif | 41 | #endif |