From b170c73f922e3457b923b4e7fcbec794a8885c77 Mon Sep 17 00:00:00 2001 From: Ralf Ertzinger Date: Sat, 22 Jun 2013 10:08:23 +0100 Subject: Updated IAP commands. Originally written and uploaded by Lalufu (Ralf Ertzinger) in Feb 2012. They have been condensed into a single patch and some further additions by Andy Potter. Currently includes Authentication V2 support from iPod to Accessory, RF/BlueTooth transmitter support, selecting a playlist and selecting a track from the current playlist. Does not support uploading Album Art or podcasts. Has been tested on the following iPods, 4th Gen Grayscale, 4th Gen Color/Photo, Mini 2nd Gen, Nano 1st Gen and Video 5.5Gen. Change-Id: Ie8fc098361844132f0228ecbe3c48da948726f5e Co-Authored by: Andy Potter Reviewed-on: http://gerrit.rockbox.org/533 Reviewed-by: Frank Gevaerts --- apps/iap/iap-lingo0.c | 1035 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1035 insertions(+) create mode 100644 apps/iap/iap-lingo0.c (limited to 'apps/iap/iap-lingo0.c') 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; + } + } +} -- cgit v1.2.3