diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/imxtools/sbtools/sbloader.c | 158 |
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 | ||
39 | static 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 | |||
47 | static void put32be(uint8_t *buf, uint32_t i) | 39 | static 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) */ | ||
71 | struct 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) */ | ||
82 | struct 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 */ | ||
93 | struct 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) */ | ||
111 | struct 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 */ | ||
127 | struct 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 | |||
78 | static int send_hid(libusb_device_handle *dev, int xfer_size, uint8_t *data, int size, int nr_xfers) | 135 | static 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 | } |