summaryrefslogtreecommitdiffstats
path: root/apps/iap/iap-lingo0.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/iap/iap-lingo0.c')
-rw-r--r--apps/iap/iap-lingo0.c1035
1 files changed, 1035 insertions, 0 deletions
diff --git a/apps/iap/iap-lingo0.c b/apps/iap/iap-lingo0.c
new file mode 100644
index 0000000000..9e0355cb3f
--- /dev/null
+++ b/apps/iap/iap-lingo0.c
@@ -0,0 +1,1035 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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.
+ *
+ ****************************************************************************/
+
+#include "iap-core.h"
+#include "iap-lingo.h"
+#include "kernel.h"
+#include "system.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(0x00, 0x02);
+ IAP_TX_PUT(status);
+ IAP_TX_PUT(cmd);
+ iap_send_tx();
+}
+
+#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK)
+
+static void cmd_pending(const unsigned char cmd, const uint32_t msdelay)
+{
+ IAP_TX_INIT(0x00, 0x02);
+ IAP_TX_PUT(0x06);
+ IAP_TX_PUT(cmd);
+ IAP_TX_PUT_U32(msdelay);
+ iap_send_tx();
+}
+
+void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
+{
+ unsigned int cmd = buf[1];
+
+ /* We expect at least two bytes in the buffer, one for the
+ * lingo, one for the command
+ */
+ CHECKLEN(2);
+
+ switch (cmd) {
+ /* RequestIdentify (0x00)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* Identify (0x01)
+ * This command is deprecated.
+ *
+ * It is used by a device to inform the iPod of the devices
+ * presence and of the lingo the device supports.
+ *
+ * Also, it is used to negotiate power for RF transmitters
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x01
+ * 0x02: Lingo supported by the device
+ *
+ * Some RF transmitters use an extended version of this
+ * command:
+ *
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x01
+ * 0x02: Lingo supported by the device, always 0x05 (RF Transmitter)
+ * 0x03: Reserved, always 0x00
+ * 0x04: Number of valid bits in the following fields
+ * 0x05-N: Datafields holding the number of bits specified in 0x04
+ *
+ * Returns: (none)
+ *
+ * TODO:
+ * BeginHighPower/EndHighPower should be send in the periodic handler,
+ * depending on the current play status
+ */
+ case 0x01:
+ {
+ unsigned char lingo = buf[2];
+
+ /* This is sufficient even for Lingo 0x05, as we are
+ * not actually reading from the extended bits for now
+ */
+ CHECKLEN(3);
+
+ /* Issuing this command exits any extended interface states
+ * and resets authentication
+ */
+ iap_interface_state_change(IST_STANDARD);
+ iap_reset_device(&device);
+
+ switch (lingo) {
+ case 0x04:
+ {
+ /* A single lingo device negotiating the
+ * extended interface lingo. This causes an interface
+ * state change.
+ */
+ iap_interface_state_change(IST_EXTENDED);
+ break;
+ }
+
+ case 0x05:
+ {
+ /* FM transmitter sends this: */
+ /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
+ sleep(HZ/3);
+ /* RF Transmitter: Begin transmission */
+ IAP_TX_INIT(0x05, 0x02);
+
+ iap_send_tx();
+ break;
+ }
+ }
+
+ if (lingo < 32) {
+ /* All devices that Identify get access to Lingoes 0x00 and 0x02 */
+ device.lingoes = BIT_N(0x00) | BIT_N(0x02);
+
+ device.lingoes |= BIT_N(lingo);
+
+ /* Devices that Identify with Lingo 0x04 also gain access
+ * to Lingo 0x03
+ */
+ if (lingo == 0x04)
+ device.lingoes |= BIT_N(0x03);
+ } else {
+ device.lingoes = 0;
+ }
+ break;
+ }
+
+ /* ACK (0x02)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* RequestRemoteUIMode (0x03)
+ *
+ * Request the current Extended Interface Mode state
+ * This command may be used only if the accessory requests Lingo 0x04
+ * during its identification process.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x03
+ *
+ * Returns on success:
+ * ReturnRemoteUIMode
+ *
+ * Packet format (offset in data[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x04
+ * 0x02: Current Extended Interface Mode (zero: false, non-zero: true)
+ *
+ * Returns on failure:
+ * IAP_ACK_BAD_PARAM
+ */
+ case 0x03:
+ {
+ if (!DEVICE_LINGO_SUPPORTED(0x04)) {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ break;
+ }
+
+ IAP_TX_INIT(0x00, 0x04);
+ if (interface_state == IST_EXTENDED)
+ IAP_TX_PUT(0x01);
+ else
+ IAP_TX_PUT(0x00);
+
+ iap_send_tx();
+ break;
+ }
+
+ /* ReturnRemoteUIMode (0x04)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* EnterRemoteUIMode (0x05)
+ *
+ * Request Extended Interface Mode
+ * This command may be used only if the accessory requests Lingo 0x04
+ * during its identification process.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x05
+ *
+ * Returns on success:
+ * IAP_ACK_PENDING
+ * IAP_ACK_OK
+ *
+ * Returns on failure:
+ * IAP_ACK_BAD_PARAM
+ */
+ case 0x05:
+ {
+ if (!DEVICE_LINGO_SUPPORTED(0x04)) {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ break;
+ }
+
+ cmd_pending(cmd, 1000);
+ iap_interface_state_change(IST_EXTENDED);
+ cmd_ok(cmd);
+ break;
+ }
+
+ /* ExitRemoteUIMode (0x06)
+ *
+ * Leave Extended Interface Mode
+ * This command may be used only if the accessory requests Lingo 0x04
+ * during its identification process.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x06
+ *
+ * Returns on success:
+ * IAP_ACK_PENDING
+ * IAP_ACK_OK
+ *
+ * Returns on failure:
+ * IAP_ACK_BAD_PARAM
+ */
+ case 0x06:
+ {
+ if (!DEVICE_LINGO_SUPPORTED(0x04)) {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ break;
+ }
+
+ cmd_pending(cmd, 1000);
+ iap_interface_state_change(IST_STANDARD);
+ cmd_ok(cmd);
+ break;
+ }
+
+ /* RequestiPodName (0x07)
+ *
+ * Retrieves the name of the iPod
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x07
+ *
+ * Returns:
+ * ReturniPodName
+ *
+ * Packet format (offset in data[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x08
+ * 0x02-0xNN: iPod name as NULL-terminated UTF8 string
+ */
+ case 0x07:
+ {
+ IAP_TX_INIT(0x00, 0x08);
+ IAP_TX_PUT_STRING("ROCKBOX");
+
+ iap_send_tx();
+ break;
+ }
+
+ /* ReturniPodName (0x08)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* RequestiPodSoftwareVersion (0x09)
+ *
+ * Returns the major, minor and revision numbers of the iPod
+ * software version. This not any Lingo protocol version.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x09
+ *
+ * Returns:
+ * ReturniPodSoftwareVersion
+ *
+ * Packet format (offset in data[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x0A
+ * 0x02: iPod major software version
+ * 0x03: iPod minor software version
+ * 0x04: iPod revision software version
+ */
+ case 0x09:
+ {
+ IAP_TX_INIT(0x00, 0x0A);
+ IAP_TX_PUT(IAP_IPOD_FIRMWARE_MAJOR);
+ IAP_TX_PUT(IAP_IPOD_FIRMWARE_MINOR);
+ IAP_TX_PUT(IAP_IPOD_FIRMWARE_REV);
+
+ iap_send_tx();
+ break;
+ }
+
+ /* ReturniPodSoftwareVersion (0x0A)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* RequestiPodSerialNum (0x0B)
+ *
+ * Returns the iPod serial number
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x0B
+ *
+ * Returns:
+ * ReturniPodSerialNumber
+ *
+ * Packet format (offset in data[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x0C
+ * 0x02-0xNN: Serial number as NULL-terminated UTF8 string
+ */
+ case 0x0B:
+ {
+ IAP_TX_INIT(0x00, 0x0C);
+ IAP_TX_PUT_STRING("0123456789");
+
+ iap_send_tx();
+ break;
+ }
+
+ /* ReturniPodSerialNum (0x0C)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* RequestiPodModelNum (0x0D)
+ *
+ * Returns the model number as a 32bit unsigned integer and
+ * as a string.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x0D
+ *
+ * Returns:
+ * ReturniPodModelNum
+ *
+ * Packet format (offset in data[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x0E
+ * 0x02-0x05: Model number as 32bit integer
+ * 0x06-0xNN: Model number as NULL-terminated UTF8 string
+ */
+ case 0x0D:
+ {
+ IAP_TX_INIT(0x00, 0x0E);
+ IAP_TX_PUT_U32(IAP_IPOD_MODEL);
+ IAP_TX_PUT_STRING("ROCKBOX");
+
+ iap_send_tx();
+ break;
+ }
+
+ /* ReturniPodSerialNum (0x0E)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* RequestLingoProtocolVersion (0x0F)
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x0F
+ * 0x02: Lingo for which to request version information
+ *
+ * Returns on success:
+ * ReturnLingoProtocolVersion
+ *
+ * Packet format (offset in data[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x10
+ * 0x02: Lingo for which version information is returned
+ * 0x03: Major protocol version for the given lingo
+ * 0x04: Minor protocol version for the given lingo
+ *
+ * Returns on failure:
+ * IAP_ACK_BAD_PARAM
+ */
+ case 0x0F:
+ {
+ unsigned char lingo = buf[2];
+
+ CHECKLEN(3);
+
+ /* Supported lingos and versions are read from the lingo_versions
+ * array
+ */
+ if (LINGO_SUPPORTED(lingo)) {
+ IAP_TX_INIT(0x00, 0x10);
+ IAP_TX_PUT(lingo);
+ IAP_TX_PUT(LINGO_MAJOR(lingo));
+ IAP_TX_PUT(LINGO_MINOR(lingo));
+
+ iap_send_tx();
+ } else {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ }
+ break;
+ }
+
+ /* ReturnLingoProtocolVersion (0x10)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* IdentifyDeviceLingoes (0x13);
+ *
+ * Used by a device to inform the iPod of the devices
+ * presence and of the lingoes the device supports.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x13
+ * 0x02-0x05: Device lingoes spoken
+ * 0x06-0x09: Device options
+ * 0x0A-0x0D: Device ID. Only important for authentication
+ *
+ * Returns on success:
+ * IAP_ACK_OK
+ *
+ * Returns on failure:
+ * IAP_ACK_CMD_FAILED
+ */
+ case 0x13:
+ {
+ uint32_t lingoes = get_u32(&buf[2]);
+ uint32_t options = get_u32(&buf[6]);
+ uint32_t deviceid = get_u32(&buf[0x0A]);
+ bool seen_unsupported = false;
+ unsigned char i;
+
+ CHECKLEN(14);
+
+ /* Issuing this command exits any extended interface states */
+ iap_interface_state_change(IST_STANDARD);
+
+ /* Loop through the lingoes advertised by the device.
+ * If it tries to use a lingo we do not support, return
+ * a Command Failed ACK.
+ */
+ for(i=0; i<32; i++) {
+ if (lingoes & BIT_N(i)) {
+ /* Bit set by device */
+ if (!LINGO_SUPPORTED(i)) {
+ seen_unsupported = true;
+ }
+ }
+ }
+
+ /* Bit 0 _must_ be set by the device */
+ if (!(lingoes & 1)) {
+ seen_unsupported = true;
+ }
+
+ /* Specifying a deviceid without requesting authentication is
+ * an error
+ */
+ if (deviceid && !(options & 0x03))
+ seen_unsupported = true;
+
+ /* Specifying authentication without a deviceid is an error */
+ if (!deviceid && (options & 0x03))
+ seen_unsupported = true;
+
+ device.lingoes = 0;
+ if (seen_unsupported) {
+ cmd_ack(cmd, IAP_ACK_CMD_FAILED);
+ break;
+ }
+ iap_reset_device(&device);
+ device.lingoes = lingoes;
+
+ /* Devices using IdentifyDeviceLingoes get power off notifications */
+ device.do_power_notify = true;
+
+ /* If a new authentication is requested, start the auth
+ * process.
+ * The periodic handler will take care of sending out the
+ * GetDevAuthenticationInfo packet
+ *
+ * If no authentication is requested, schedule the start of
+ * GetAccessoryInfo
+ */
+ if (deviceid && (options & 0x03) && !DEVICE_AUTH_RUNNING) {
+ device.auth.state = AUST_INIT;
+ } else {
+ device.accinfo = ACCST_INIT;
+ }
+
+ cmd_ok(cmd);
+
+ /* Bit 5: RF Transmitter lingo */
+ if (lingoes & (1 << 5))
+ {
+ /* FM transmitter sends this: */
+ /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
+
+ /* GetAccessoryInfo */
+ unsigned char data2[] = {0x00, 0x27, 0x00};
+ iap_send_pkt(data2, sizeof(data2));
+ /* RF Transmitter: Begin transmission */
+ unsigned char data3[] = {0x05, 0x02};
+ iap_send_pkt(data3, sizeof(data3));
+ }
+
+
+#if 0
+ /* Bit 7: RF Tuner lingo */
+ if (lingoes & (1 << 7))
+ {
+ /* ipod fm remote sends this: */
+ /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
+ radio_present = 1;
+ /* GetDevAuthenticationInfo */
+ unsigned char data4[] = {0x00, 0x14};
+ iap_send_pkt(data4, sizeof(data4));
+ }
+#endif
+ break;
+ }
+
+ /* GetDevAuthenticationInfo (0x14)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* RetDevAuthenticationInfo (0x15)
+ *
+ * Send certificate information from the device to the iPod.
+ * The certificate may come in multiple parts and has
+ * to be reassembled.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x15
+ * 0x02: Authentication major version
+ * 0x03: Authentication minor version
+ * 0x04: Certificate current section index
+ * 0x05: Certificate maximum section index
+ * 0x06-0xNN: Certificate data
+ *
+ * Returns on success:
+ * IAP_ACK_OK for intermediate sections
+ * AckDevAuthenticationInfo for the last section
+ *
+ * Returns on failure:
+ * IAP_ACK_BAD_PARAMETER
+ * AckDevAuthenticationInfo for version mismatches
+ *
+ */
+ case 0x15:
+ {
+ /* There are two formats of this packet. One with only
+ * the version information bytes (for Auth version 1.0)
+ * and the long form shown above
+ */
+ CHECKLEN(4);
+
+ if (!DEVICE_AUTH_RUNNING) {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ break;
+ }
+
+ /* We only support version 2.0 */
+ if ((buf[2] != 2) || (buf[3] != 0)) {
+ /* Version mismatches are signalled by AckDevAuthenticationInfo
+ * with the status set to Authentication Information unsupported
+ */
+ iap_reset_auth(&(device.auth));
+
+ IAP_TX_INIT(0x00, 0x16);
+ IAP_TX_PUT(0x08);
+
+ iap_send_tx();
+ break;
+ }
+
+ /* There must be at least one byte of certificate data
+ * in the packet
+ */
+ CHECKLEN(7);
+
+ switch (device.auth.state)
+ {
+ /* This is the first packet. Note the maximum section number
+ * so we can check it later.
+ */
+ case AUST_CERTREQ:
+ {
+ device.auth.max_section = buf[5];
+ device.auth.state = AUST_CERTBEG;
+
+ /* Intentional fall-through */
+ }
+ /* All following packets */
+ case AUST_CERTBEG:
+ {
+ /* Check if this is the expected section */
+ if (buf[4] != device.auth.next_section) {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ break;
+ }
+
+ /* Is this the last section? */
+ if (device.auth.next_section == device.auth.max_section) {
+ /* If we could really do authentication we'd have to
+ * check the certificate here. Since we can't, just acknowledge
+ * the packet with an "everything OK" AckDevAuthenticationInfo
+ *
+ * Also, start GetAccessoryInfo process
+ */
+ IAP_TX_INIT(0x00, 0x16);
+ IAP_TX_PUT(0x00);
+
+ iap_send_tx();
+ device.auth.state = AUST_CERTDONE;
+ device.accinfo = ACCST_INIT;
+ } else {
+ device.auth.next_section++;
+ cmd_ok(cmd);
+ }
+ break;
+ }
+
+ default:
+ {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ break;
+ }
+ }
+
+ break;
+ }
+
+ /* AckDevAuthenticationInfo (0x16)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* GetDevAuthenticationSignature (0x17)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* RetDevAuthenticationSignature (0x18)
+ *
+ * Return a calculated signature based on the device certificate
+ * and the challenge sent with GetDevAuthenticationSignature
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x17
+ * 0x02-0xNN: Certificate data
+ *
+ * Returns on success:
+ * AckDevAuthenticationStatus
+ *
+ * Packet format (offset in data[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x19
+ * 0x02: Status (0x00: OK)
+ *
+ * Returns on failure:
+ * IAP_ACK_BAD_PARAM
+ *
+ * TODO:
+ * There is a timeout of 75 seconds between GetDevAuthenticationSignature
+ * and RetDevAuthenticationSignature for Auth 2.0. This is currently not
+ * checked.
+ */
+ case 0x18:
+ {
+ if (device.auth.state != AUST_CHASENT) {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ break;
+ }
+
+ /* Here we could check the signature. Since we can't, just
+ * acknowledge and go to authenticated status
+ */
+ IAP_TX_INIT(0x00, 0x19);
+ IAP_TX_PUT(0x00);
+
+ iap_send_tx();
+ device.auth.state = AUST_AUTH;
+ break;
+ }
+
+ /* AckDevAuthenticationStatus (0x19)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* GetiPodAuthenticationInfo (0x1A)
+ *
+ * Obtain authentication information from the iPod.
+ * This cannot be implemented without posessing an Apple signed
+ * certificate and the corresponding private key.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x1A
+ *
+ * This command requires authentication
+ *
+ * Returns:
+ * IAP_ACK_CMD_FAILED
+ */
+ case 0x1A:
+ {
+ CHECKAUTH;
+
+ cmd_ack(cmd, IAP_ACK_CMD_FAILED);
+ break;
+ }
+
+ /* RetiPodAuthenticationInfo (0x1B)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* AckiPodAuthenticationInfo (0x1C)
+ *
+ * Confirm authentication information from the iPod.
+ * This cannot be implemented without posessing an Apple signed
+ * certificate and the corresponding private key.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x1C
+ * 0x02: Authentication state (0x00: OK)
+ *
+ * This command requires authentication
+ *
+ * Returns: (none)
+ */
+ case 0x1C:
+ {
+ CHECKAUTH;
+
+ break;
+ }
+
+ /* GetiPodAuthenticationSignature (0x1D)
+ *
+ * Send challenge information to the iPod.
+ * This cannot be implemented without posessing an Apple signed
+ * certificate and the corresponding private key.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x1D
+ * 0x02-0x15: Challenge
+ *
+ * This command requires authentication
+ *
+ * Returns:
+ * IAP_ACK_CMD_FAILED
+ */
+ case 0x1D:
+ {
+ CHECKAUTH;
+
+ cmd_ack(cmd, IAP_ACK_CMD_FAILED);
+ break;
+ }
+
+ /* RetiPodAuthenticationSignature (0x1E)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* AckiPodAuthenticationStatus (0x1F)
+ *
+ * Confirm chellenge information from the iPod.
+ * This cannot be implemented without posessing an Apple signed
+ * certificate and the corresponding private key.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x1C
+ * 0x02: Challenge state (0x00: OK)
+ *
+ * This command requires authentication
+ *
+ * Returns: (none)
+ */
+ case 0x1F:
+ {
+ CHECKAUTH;
+
+ break;
+ }
+
+ /* NotifyiPodStateChange (0x23)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* GetIpodOptions (0x24)
+ *
+ * Request supported features of the iPod
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x24
+ *
+ * Retuns:
+ * RetiPodOptions
+ *
+ * Packet format (offset in data[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x25
+ * 0x02-0x09: Options as a bitfield
+ */
+ case 0x24:
+ {
+ /* There are only two features that can be communicated via this
+ * function, video support and the ability to control line-out usage.
+ * Rockbox supports neither
+ */
+ IAP_TX_INIT(0x00, 0x25);
+ IAP_TX_PUT_U32(0x00);
+ IAP_TX_PUT_U32(0x00);
+
+ iap_send_tx();
+ break;
+ }
+
+ /* RetiPodOptions (0x25)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* GetAccessoryInfo (0x27)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* RetAccessoryInfo (0x28)
+ *
+ * Send information about the device
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x28
+ * 0x02: Accessory info type
+ * 0x03-0xNN: Accessory information (depends on 0x02)
+ *
+ * Returns: (none)
+ *
+ * TODO: Actually do something with the information received here.
+ * Some devices actually expect us to request the data they
+ * offer, so completely ignoring this does not work, either.
+ */
+ case 0x28:
+ {
+ CHECKLEN(3);
+
+ switch (buf[0x02])
+ {
+ /* Info capabilities */
+ case 0x00:
+ {
+ CHECKLEN(7);
+
+ device.capabilities = get_u32(&buf[0x03]);
+ /* Type 0x00 was already queried, that's where this information comes from */
+ device.capabilities_queried = 0x01;
+ device.capabilities &= ~0x01;
+ break;
+ }
+
+ /* For now, ignore all other information */
+ default:
+ {
+ break;
+ }
+ }
+
+ /* If there are any unqueried capabilities left, do so */
+ if (device.capabilities)
+ device.accinfo = ACCST_DATA;
+
+ break;
+ }
+
+ /* GetiPodPreferences (0x29)
+ *
+ * Retrieve information about the current state of the
+ * iPod.
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x29
+ * 0x02: Information class requested
+ *
+ * This command requires authentication
+ *
+ * Returns on success:
+ * RetiPodPreferences
+ *
+ * Packet format (offset in data[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x2A
+ * 0x02: Information class provided
+ * 0x03: Information
+ *
+ * Returns on failure:
+ * IAP_ACK_BAD_PARAM
+ */
+ case 0x29:
+ {
+ CHECKLEN(3);
+ CHECKAUTH;
+
+ IAP_TX_INIT(0x00, 0x2A);
+ /* The only information really supported is 0x03, Line-out usage.
+ * All others are video related
+ */
+ if (buf[2] == 0x03) {
+ IAP_TX_PUT(0x03);
+ IAP_TX_PUT(0x01); /* Line-out enabled */
+
+ iap_send_tx();
+ } else {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ }
+
+ break;
+ }
+
+ /* RetiPodPreference (0x2A)
+ *
+ * Sent from the iPod to the device
+ */
+
+ /* SetiPodPreferences (0x2B)
+ *
+ * Set preferences on the iPod
+ *
+ * Packet format (offset in buf[]: Description)
+ * 0x00: Lingo ID: General Lingo, always 0x00
+ * 0x01: Command, always 0x29
+ * 0x02: Prefecence class requested
+ * 0x03: Preference setting
+ * 0x04: Restore on exit
+ *
+ * This command requires authentication
+ *
+ * Returns on success:
+ * IAP_ACK_OK
+ *
+ * Returns on failure:
+ * IAP_ACK_BAD_PARAM
+ * IAP_ACK_CMD_FAILED
+ */
+ case 0x2B:
+ {
+ CHECKLEN(5);
+ CHECKAUTH;
+
+ /* The only information really supported is 0x03, Line-out usage.
+ * All others are video related
+ */
+ if (buf[2] == 0x03) {
+ /* If line-out disabled is requested, reply with IAP_ACK_CMD_FAILED,
+ * otherwise with IAP_ACK_CMD_OK
+ */
+ if (buf[3] == 0x00) {
+ cmd_ack(cmd, IAP_ACK_CMD_FAILED);
+ } else {
+ cmd_ok(cmd);
+ }
+ } else {
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+ }
+
+ break;
+ }
+
+ /* The default response is IAP_ACK_BAD_PARAM */
+ default:
+ {
+#ifdef LOGF_ENABLE
+ logf("iap: Unsupported Mode00 Command");
+#else
+ cmd_ack(cmd, IAP_ACK_BAD_PARAM);
+#endif
+ break;
+ }
+ }
+}