From fcb38436193a46f93f21512836cfa6be065bdc85 Mon Sep 17 00:00:00 2001 From: gevaerts Date: Tue, 11 Aug 2009 17:54:47 +0000 Subject: [PATCH] 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 --- firmware/common/timefuncs.c | 39 ++++++++++++++++++++++++++++++++++++++ firmware/include/timefuncs.h | 2 ++ firmware/usbstack/usb_storage.c | 42 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/firmware/common/timefuncs.c b/firmware/common/timefuncs.c index 6fdc0b724..f5097c8e5 100644 --- a/firmware/common/timefuncs.c +++ b/firmware/common/timefuncs.c @@ -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; + } + } + } +} diff --git a/firmware/include/timefuncs.h b/firmware/include/timefuncs.h index 45978f4e2..52d460828 100644 --- a/firmware/include/timefuncs.h +++ b/firmware/include/timefuncs.h @@ -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 diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index d29e731d5..a6c960422 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c @@ -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); -- 2.11.4.GIT