summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-10-09 13:06:41 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-10-09 13:06:41 +0200
commit468aa959c79be818b8866a8eb03896effde74f41 (patch)
tree9d6e65847feec7e5b7bb4349ab446d6ba1d7a033
parent1c63993e05d177a0793b02ee0cd5762bb293e86c (diff)
downloadrockbox-468aa959c79be818b8866a8eb03896effde74f41.tar.gz
rockbox-468aa959c79be818b8866a8eb03896effde74f41.zip
imxtools/sbloader: rewrite hid code
Rewrite code with proper documentation: it uses a UMS like CBW/CSW to wrap commands and status. Change-Id: I10476c87aaea96d4b9e54f8c1c266835c8e89721
-rw-r--r--utils/imxtools/sbtools/sbloader.c158
1 files changed, 121 insertions, 37 deletions
diff --git a/utils/imxtools/sbtools/sbloader.c b/utils/imxtools/sbtools/sbloader.c
index 91c4fc952f..0a82a66a0c 100644
--- a/utils/imxtools/sbtools/sbloader.c
+++ b/utils/imxtools/sbtools/sbloader.c
@@ -36,14 +36,6 @@ bool g_debug = false;
36#define MAX(a,b) ((a) > (b) ? (a) : (b)) 36#define MAX(a,b) ((a) > (b) ? (a) : (b))
37#endif 37#endif
38 38
39static void put32le(uint8_t *buf, uint32_t i)
40{
41 *buf++ = i & 0xff;
42 *buf++ = (i >> 8) & 0xff;
43 *buf++ = (i >> 16) & 0xff;
44 *buf++ = (i >> 24) & 0xff;
45}
46
47static void put32be(uint8_t *buf, uint32_t i) 39static void put32be(uint8_t *buf, uint32_t i)
48{ 40{
49 *buf++ = (i >> 24) & 0xff; 41 *buf++ = (i >> 24) & 0xff;
@@ -75,44 +67,101 @@ struct dev_info_t g_dev_info[] =
75 {0x066f, 0x3600, 4096, RECOVERY_DEVICE}, /* STMP36xx */ 67 {0x066f, 0x3600, 4096, RECOVERY_DEVICE}, /* STMP36xx */
76}; 68};
77 69
70/* Command Block Descriptor (CDB) */
71struct hid_cdb_t
72{
73 uint8_t command;
74 uint32_t length; // big-endian!
75 uint8_t reserved[11];
76} __attribute__((packed));
77
78// command
79#define BLTC_DOWNLOAD_FW 2
80
81/* Command Block Wrapper (CBW) */
82struct hid_cbw_t
83{
84 uint32_t signature; // BLTC or PITC
85 uint32_t tag; // returned in CSW
86 uint32_t length; // number of bytes to transfer
87 uint8_t flags;
88 uint8_t reserved[2];
89 struct hid_cdb_t cdb;
90} __attribute__((packed));
91
92/* HID Command Report */
93struct hid_cmd_report_t
94{
95 uint8_t report_id;
96 struct hid_cbw_t cbw;
97} __attribute__((packed));
98
99// report id
100#define HID_BLTC_DATA_REPORT 2
101#define HID_BLTC_CMD_REPORT 1
102
103// signature
104#define CBW_BLTC 0x43544C42 /* "BLTC" */
105#define CBW_PITC 0x43544950 /* "PITC" */
106// flags
107#define CBW_DIR_IN 0x80
108#define CBW_DIR_OUT 0x00
109
110/* Command Status Wrapper (CSW) */
111struct hid_csw_t
112{
113 uint32_t signature; // BLTS or PITS
114 uint32_t tag; // given in CBW
115 uint32_t residue; // number of bytes not transferred
116 uint8_t status;
117} __attribute__((packed));
118// signature
119#define CSW_BLTS 0x53544C42 /* "BLTS" */
120#define CSW_PITS 0x53544950 /* "PITS" */
121// status
122#define CSW_PASSED 0x00
123#define CSW_FAILED 0x01
124#define CSW_PHASE_ERROR 0x02
125
126/* HID Status Report */
127struct hid_status_report_t
128{
129 uint8_t report_id;
130 struct hid_csw_t csw;
131} __attribute__((packed));
132
133#define HID_BLTC_STATUS_REPORT 4
134
78static int send_hid(libusb_device_handle *dev, int xfer_size, uint8_t *data, int size, int nr_xfers) 135static int send_hid(libusb_device_handle *dev, int xfer_size, uint8_t *data, int size, int nr_xfers)
79{ 136{
80 libusb_detach_kernel_driver(dev, 0); 137 libusb_detach_kernel_driver(dev, 0);
81 libusb_claim_interface(dev, 0); 138 libusb_claim_interface(dev, 0);
82 139
140 int recv_size;
141 uint32_t my_tag = 0xcafebabe;
83 uint8_t *xfer_buf = malloc(1 + xfer_size); 142 uint8_t *xfer_buf = malloc(1 + xfer_size);
84 uint8_t *p = xfer_buf; 143 struct hid_cmd_report_t cmd;
85 144 memset(&cmd, 0, sizeof(cmd));
86 *p++ = 0x01; /* Report id */ 145 cmd.report_id = HID_BLTC_CMD_REPORT;
87 146 cmd.cbw.signature = CBW_BLTC;
88 /* Command block wrapper */ 147 cmd.cbw.tag = my_tag;
89 *p++ = 'B'; /* Signature */ 148 cmd.cbw.length = size;
90 *p++ = 'L'; 149 cmd.cbw.flags = CBW_DIR_OUT;
91 *p++ = 'T'; 150 cmd.cbw.cdb.command = BLTC_DOWNLOAD_FW;
92 *p++ = 'C'; 151 put32be((void *)&cmd.cbw.cdb.length, size);
93 put32le(p, 0x1); /* Tag */
94 p += 4;
95 put32le(p, size); /* Payload size */
96 p += 4;
97 *p++ = 0; /* Flags (host to device) */
98 p += 2; /* Reserved */
99
100 /* Command descriptor block */
101 *p++ = 0x02; /* Firmware download */
102 put32be(p, size); /* Download size */
103 152
104 int ret = libusb_control_transfer(dev, 153 int ret = libusb_control_transfer(dev,
105 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 0x9, 0x201, 0, 154 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 0x9, 0x201, 0,
106 xfer_buf, xfer_size + 1, 1000); 155 (void *)&cmd, sizeof(cmd), 1000);
107 if(ret < 0) 156 if(ret < 0)
108 { 157 {
109 printf("transfer error at init step\n"); 158 printf("transfer error at init step\n");
110 return 1; 159 goto Lstatus;
111 } 160 }
112 161
113 for(int i = 0; i < nr_xfers; i++) 162 for(int i = 0; i < nr_xfers; i++)
114 { 163 {
115 xfer_buf[0] = 0x2; 164 xfer_buf[0] = HID_BLTC_DATA_REPORT;
116 memcpy(&xfer_buf[1], &data[i * xfer_size], xfer_size); 165 memcpy(&xfer_buf[1], &data[i * xfer_size], xfer_size);
117 166
118 ret = libusb_control_transfer(dev, 167 ret = libusb_control_transfer(dev,
@@ -121,18 +170,53 @@ static int send_hid(libusb_device_handle *dev, int xfer_size, uint8_t *data, int
121 if(ret < 0) 170 if(ret < 0)
122 { 171 {
123 printf("transfer error at send step %d\n", i); 172 printf("transfer error at send step %d\n", i);
124 return 1; 173 goto Lstatus;
125 } 174 }
126 } 175 }
127 176
128 int recv_size; 177 Lstatus:
129 ret = libusb_interrupt_transfer(dev, 0x81, xfer_buf, xfer_size, &recv_size, 178 ret = libusb_interrupt_transfer(dev, 0x81, xfer_buf, xfer_size,
130 1000); 179 &recv_size, 1000);
131 if(ret < 0) 180 if(ret == 0 && recv_size == sizeof(struct hid_status_report_t))
132 { 181 {
133 printf("transfer error at final stage\n"); 182 struct hid_status_report_t *report = (void *)xfer_buf;
134 return 1; 183 if(report->report_id != HID_BLTC_STATUS_REPORT)
184 {
185 printf("Error: got non-status report\n");
186 return -1;
187 }
188 if(report->csw.signature != CSW_BLTS)
189 {
190 printf("Error: status report signature mismatch\n");
191 return -2;
192 }
193 if(report->csw.tag != my_tag)
194 {
195 printf("Error: status report tag mismtahc\n");
196 return -3;
197 }
198 if(report->csw.residue != 0)
199 printf("Warning: %d byte were not transferred\n", report->csw.residue);
200 switch(report->csw.status)
201 {
202 case CSW_PASSED:
203 printf("Status: Passed\n");
204 return 0;
205 case CSW_FAILED:
206 printf("Status: Failed\n");
207 return -1;
208 case CSW_PHASE_ERROR:
209 printf("Status: Phase Error\n");
210 return -2;
211 default:
212 printf("Status: Unknown Error\n");
213 return -3;
214 }
135 } 215 }
216 else if(ret < 0)
217 printf("Error: cannot get status report\n");
218 else
219 printf("Error: status report has wrong size\n");
136 220
137 return ret; 221 return ret;
138} 222}