2013-06-22 09:08:23 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2014-12-06 22:27:01 +00:00
|
|
|
device.auth.version = (buf[2] << 8) | buf[3];
|
|
|
|
|
|
|
|
/* We support authentication versions 1.0 and 2.0 */
|
|
|
|
if (device.auth.version == 0x100) {
|
|
|
|
/* 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
|
|
|
|
*
|
|
|
|
* Skip GetAccessoryInfo process, this command together with
|
|
|
|
* authentication level 2 were added in iAP release 24, it is
|
|
|
|
* not be supported by devices authenticating at level 1.
|
|
|
|
*/
|
|
|
|
IAP_TX_INIT(0x00, 0x16);
|
|
|
|
IAP_TX_PUT(0x00);
|
|
|
|
|
|
|
|
iap_send_tx();
|
|
|
|
device.auth.state = AUST_CERTDONE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (device.auth.version != 0x200) {
|
2013-06-22 09:08:23 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|