summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2009-08-11 17:54:47 +0000
committerFrank Gevaerts <frank@gevaerts.be>2009-08-11 17:54:47 +0000
commited73a3274ca4bb3dec0cf067732bcdf4fe1a7d62 (patch)
tree8ac2786b04bc7149ced718b8c80e98010b7164fc /firmware
parent6cea3308d05c21aabe073f77c3d013485b0429a0 (diff)
downloadrockbox-ed73a3274ca4bb3dec0cf067732bcdf4fe1a7d62.tar.gz
rockbox-ed73a3274ca4bb3dec0cf067732bcdf4fe1a7d62.tar.bz2
rockbox-ed73a3274ca4bb3dec0cf067732bcdf4fe1a7d62.zip
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
Diffstat (limited to 'firmware')
-rw-r--r--firmware/common/timefuncs.c39
-rw-r--r--firmware/include/timefuncs.h2
-rw-r--r--firmware/usbstack/usb_storage.c42
3 files changed, 81 insertions, 2 deletions
diff --git a/firmware/common/timefuncs.c b/firmware/common/timefuncs.c
index 6fdc0b7240..f5097c8e52 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 45978f4e2e..52d4608287 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 d29e731d5a..a6c960422d 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);