Add support for setting the clock using a special SCSI command. This is the same method that itunes uses, and there are host-side tools for it (e.g. libgpod)

Flyspray: FS#10514
Author: Laurent Papier and myself



git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22255 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Frank Gevaerts 2009-08-11 17:54:47 +00:00
parent 6cea3308d0
commit ed73a3274c
3 changed files with 81 additions and 2 deletions

View file

@ -193,3 +193,42 @@ time_t mktime(struct tm *t)
return(result);
}
#endif
int day_of_week(int m, int d, int y)
{
char mo[12] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
if(m == 0 || m == 1) y--;
return (d + mo[m] + y + y/4 - y/100 + y/400) % 7;
}
void yearday_to_daymonth(int yd, int y, int *d, int *m)
{
short t[12] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
int i;
if((y%4 == 0 && y%100 != 0) || y%400 == 0)
{
for(i=1;i<12;i++)
t[i]++;
}
yd++;
if(yd <= 31)
{
*d = yd;
*m = 0;
}
else
{
for(i=1;i<12;i++)
{
if(yd <= t[i])
{
*d = yd - t[i-1];
*m = i;
break;
}
}
}
}

View file

@ -29,6 +29,8 @@
struct tm *get_time(void);
int set_time(const struct tm *tm);
bool valid_time(const struct tm *tm);
int day_of_week(int m, int d, int y);
void yearday_to_daymonth(int yd, int y, int *d, int *m);
#if CONFIG_RTC
time_t mktime(struct tm *t);
#endif

View file

@ -31,6 +31,7 @@
/* Needed to get at the audio buffer */
#include "audio.h"
#include "usb_storage.h"
#include "timefuncs.h"
/* Enable the following define to export only the SD card slot. This
@ -68,8 +69,8 @@
#define USB_BULK_RESET_REQUEST 0xff
#define USB_BULK_GET_MAX_LUN 0xfe
#define DIRECT_ACCESS_DEVICE 0x00 /* disks */
#define DEVICE_REMOVABLE 0x80
#define DIRECT_ACCESS_DEVICE 0x00 /* disks */
#define DEVICE_REMOVABLE 0x80
#define CBW_SIGNATURE 0x43425355
#define CSW_SIGNATURE 0x53425355
@ -86,6 +87,7 @@
#define SCSI_WRITE_10 0x2a
#define SCSI_START_STOP_UNIT 0x1b
#define SCSI_REPORT_LUNS 0xa0
#define SCSI_WRITE_BUFFER 0x3b
#define UMS_STATUS_GOOD 0x00
#define UMS_STATUS_FAIL 0x01
@ -270,6 +272,7 @@ static void send_command_result(void *data,int size);
static void send_command_failed_result(void);
static void send_block_data(void *data,int size);
static void receive_block_data(void *data,int size);
static void receive_time(void);
static void fill_inquiry(IF_MD_NONVOID(int lun));
static void send_and_read_next(void);
static bool ejected[NUM_DRIVES];
@ -288,6 +291,7 @@ static enum {
SENDING_RESULT,
SENDING_FAILED_RESULT,
RECEIVING_BLOCKS,
RECEIVING_TIME,
SENDING_CSW
} state = WAITING_FOR_COMMAND;
@ -459,6 +463,7 @@ void usb_storage_transfer_complete(int ep,int dir,int status,int length)
{
(void)ep;
struct command_block_wrapper* cbw = (void*)cbw_buffer;
struct tm tm;
//logf("transfer result %X %d", status, length);
switch(state) {
@ -602,6 +607,19 @@ void usb_storage_transfer_complete(int ep,int dir,int status,int length)
cur_sense_data.ascq=0;
}
break;
case RECEIVING_TIME:
tm.tm_year=(tb.transfer_buffer[0]<<8)+tb.transfer_buffer[1];
tm.tm_yday=(tb.transfer_buffer[2]<<8)+tb.transfer_buffer[3];
tb.transfer_buffer[8];
tm.tm_hour=tb.transfer_buffer[5];
tm.tm_min=tb.transfer_buffer[6];
tm.tm_sec=tb.transfer_buffer[7];
yearday_to_daymonth(tm.tm_yday,tm.tm_year,&tm.tm_mday,&tm.tm_mon);
tm.tm_wday=day_of_week(tm.tm_mon,tm.tm_mday,tm.tm_year);
tm.tm_year -= 1900;
set_time(&tm);
send_csw(UMS_STATUS_GOOD);
break;
}
}
@ -1063,6 +1081,21 @@ static void handle_scsi(struct command_block_wrapper* cbw)
}
break;
case SCSI_WRITE_BUFFER:
if(cbw->command_block[1]==1
&& cbw->command_block[2]==0
&& cbw->command_block[3]==0x0c
&& cbw->command_block[4]==0
&& cbw->command_block[5]==0
&& cbw->command_block[6]==0
&& cbw->command_block[7]==0
/* Some versions of itunes set the next byte to 0. Technically
* it should be 0x0c */
&& (cbw->command_block[8]==0 || cbw->command_block[8]==0x0c)
&& cbw->command_block[9]==0)
receive_time();
break;
default:
logf("scsi unknown cmd %x",cbw->command_block[0x0]);
send_csw(UMS_STATUS_FAIL);
@ -1091,6 +1124,11 @@ static void send_command_failed_result(void)
state = SENDING_FAILED_RESULT;
}
static void receive_time(void)
{
usb_drv_recv(ep_out, tb.transfer_buffer, 12);
state = RECEIVING_TIME;
}
static void receive_block_data(void *data,int size)
{
usb_drv_recv(ep_out, data, size);