diff options
author | Ryan <fauxpark@gmail.com> | 2021-08-18 18:20:25 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-18 18:20:25 +1000 |
commit | b16091659cc9a724a8800f77e631643b4ab089ad (patch) | |
tree | e44933472c6d100bd4fc5d8a693d9d21e3c32f6f /lib/usbhost/USB_Host_Shield_2.0/masstorage.cpp | |
parent | cf5e40c25139ff64ff246f1c6280e983ef75551c (diff) | |
download | qmk_firmware-b16091659cc9a724a8800f77e631643b4ab089ad.tar.gz qmk_firmware-b16091659cc9a724a8800f77e631643b4ab089ad.zip |
Move USB Host Shield and Arduino core to `lib/` (#13973)
Diffstat (limited to 'lib/usbhost/USB_Host_Shield_2.0/masstorage.cpp')
-rw-r--r-- | lib/usbhost/USB_Host_Shield_2.0/masstorage.cpp | 1266 |
1 files changed, 1266 insertions, 0 deletions
diff --git a/lib/usbhost/USB_Host_Shield_2.0/masstorage.cpp b/lib/usbhost/USB_Host_Shield_2.0/masstorage.cpp new file mode 100644 index 000000000..9299f71a4 --- /dev/null +++ b/lib/usbhost/USB_Host_Shield_2.0/masstorage.cpp | |||
@@ -0,0 +1,1266 @@ | |||
1 | /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. | ||
2 | |||
3 | This software may be distributed and modified under the terms of the GNU | ||
4 | General Public License version 2 (GPL2) as published by the Free Software | ||
5 | Foundation and appearing in the file GPL2.TXT included in the packaging of | ||
6 | this file. Please note that GPL2 Section 2[b] requires that all works based | ||
7 | on this software must also be made publicly available under the terms of | ||
8 | the GPL2 ("Copyleft"). | ||
9 | |||
10 | Contact information | ||
11 | ------------------- | ||
12 | |||
13 | Circuits At Home, LTD | ||
14 | Web : http://www.circuitsathome.com | ||
15 | e-mail : support@circuitsathome.com | ||
16 | */ | ||
17 | |||
18 | #include "masstorage.h" | ||
19 | |||
20 | const uint8_t BulkOnly::epDataInIndex = 1; | ||
21 | const uint8_t BulkOnly::epDataOutIndex = 2; | ||
22 | const uint8_t BulkOnly::epInterruptInIndex = 3; | ||
23 | |||
24 | //////////////////////////////////////////////////////////////////////////////// | ||
25 | |||
26 | // Interface code | ||
27 | |||
28 | //////////////////////////////////////////////////////////////////////////////// | ||
29 | |||
30 | /** | ||
31 | * Get the capacity of the media | ||
32 | * | ||
33 | * @param lun Logical Unit Number | ||
34 | * @return media capacity | ||
35 | */ | ||
36 | uint32_t BulkOnly::GetCapacity(uint8_t lun) { | ||
37 | if(LUNOk[lun]) | ||
38 | return CurrentCapacity[lun]; | ||
39 | return 0LU; | ||
40 | } | ||
41 | |||
42 | /** | ||
43 | * Get the sector (block) size used on the media | ||
44 | * | ||
45 | * @param lun Logical Unit Number | ||
46 | * @return media sector size | ||
47 | */ | ||
48 | uint16_t BulkOnly::GetSectorSize(uint8_t lun) { | ||
49 | if(LUNOk[lun]) | ||
50 | return CurrentSectorSize[lun]; | ||
51 | return 0U; | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * Test if LUN is ready for use | ||
56 | * | ||
57 | * @param lun Logical Unit Number | ||
58 | * @return true if LUN is ready for use | ||
59 | */ | ||
60 | bool BulkOnly::LUNIsGood(uint8_t lun) { | ||
61 | return LUNOk[lun]; | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * Test if LUN is write protected | ||
66 | * | ||
67 | * @param lun Logical Unit Number | ||
68 | * @return cached status of write protect switch | ||
69 | */ | ||
70 | bool BulkOnly::WriteProtected(uint8_t lun) { | ||
71 | return WriteOk[lun]; | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * Wrap and execute a SCSI CDB with length of 6 | ||
76 | * | ||
77 | * @param cdb CDB to execute | ||
78 | * @param buf_size Size of expected transaction | ||
79 | * @param buf Buffer | ||
80 | * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT | ||
81 | * @return | ||
82 | */ | ||
83 | uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { | ||
84 | // promote buf_size to 32bits. | ||
85 | CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); | ||
86 | //SetCurLUN(cdb->LUN); | ||
87 | return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * Wrap and execute a SCSI CDB with length of 10 | ||
92 | * | ||
93 | * @param cdb CDB to execute | ||
94 | * @param buf_size Size of expected transaction | ||
95 | * @param buf Buffer | ||
96 | * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT | ||
97 | * @return | ||
98 | */ | ||
99 | uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { | ||
100 | // promote buf_size to 32bits. | ||
101 | CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); | ||
102 | //SetCurLUN(cdb->LUN); | ||
103 | return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * Lock or Unlock the tray or door on device. | ||
108 | * Caution: Some devices with buggy firmware will lock up. | ||
109 | * | ||
110 | * @param lun Logical Unit Number | ||
111 | * @param lock 1 to lock, 0 to unlock | ||
112 | * @return | ||
113 | */ | ||
114 | uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) { | ||
115 | Notify(PSTR("\r\nLockMedia\r\n"), 0x80); | ||
116 | Notify(PSTR("---------\r\n"), 0x80); | ||
117 | |||
118 | CDB6_t cdb = CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock); | ||
119 | return SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_IN); | ||
120 | } | ||
121 | |||
122 | /** | ||
123 | * Media control, for spindle motor and media tray or door. | ||
124 | * This includes CDROM, TAPE and anything with a media loader. | ||
125 | * | ||
126 | * @param lun Logical Unit Number | ||
127 | * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media | ||
128 | * @return 0 on success | ||
129 | */ | ||
130 | uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) { | ||
131 | Notify(PSTR("\r\nMediaCTL\r\n"), 0x80); | ||
132 | Notify(PSTR("-----------------\r\n"), 0x80); | ||
133 | |||
134 | uint8_t rcode = MASS_ERR_UNIT_NOT_READY; | ||
135 | if(bAddress) { | ||
136 | CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0); | ||
137 | rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT); | ||
138 | } else { | ||
139 | SetCurLUN(lun); | ||
140 | } | ||
141 | return rcode; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * Read data from media | ||
146 | * | ||
147 | * @param lun Logical Unit Number | ||
148 | * @param addr LBA address on media to read | ||
149 | * @param bsize size of a block (we should probably use the cached size) | ||
150 | * @param blocks how many blocks to read | ||
151 | * @param buf memory that is able to hold the requested data | ||
152 | * @return 0 on success | ||
153 | */ | ||
154 | uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) { | ||
155 | if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; | ||
156 | Notify(PSTR("\r\nRead LUN:\t"), 0x80); | ||
157 | D_PrintHex<uint8_t > (lun, 0x90); | ||
158 | Notify(PSTR("\r\nLBA:\t\t"), 0x90); | ||
159 | D_PrintHex<uint32_t > (addr, 0x90); | ||
160 | Notify(PSTR("\r\nblocks:\t\t"), 0x90); | ||
161 | D_PrintHex<uint8_t > (blocks, 0x90); | ||
162 | Notify(PSTR("\r\nblock size:\t"), 0x90); | ||
163 | D_PrintHex<uint16_t > (bsize, 0x90); | ||
164 | Notify(PSTR("\r\n---------\r\n"), 0x80); | ||
165 | CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr); | ||
166 | |||
167 | again: | ||
168 | uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN); | ||
169 | |||
170 | if(er == MASS_ERR_STALL) { | ||
171 | MediaCTL(lun, 1); | ||
172 | delay(150); | ||
173 | if(!TestUnitReady(lun)) goto again; | ||
174 | } | ||
175 | return er; | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * Write data to media | ||
180 | * | ||
181 | * @param lun Logical Unit Number | ||
182 | * @param addr LBA address on media to write | ||
183 | * @param bsize size of a block (we should probably use the cached size) | ||
184 | * @param blocks how many blocks to write | ||
185 | * @param buf memory that contains the data to write | ||
186 | * @return 0 on success | ||
187 | */ | ||
188 | uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) { | ||
189 | if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; | ||
190 | if(!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED; | ||
191 | Notify(PSTR("\r\nWrite LUN:\t"), 0x80); | ||
192 | D_PrintHex<uint8_t > (lun, 0x90); | ||
193 | Notify(PSTR("\r\nLBA:\t\t"), 0x90); | ||
194 | D_PrintHex<uint32_t > (addr, 0x90); | ||
195 | Notify(PSTR("\r\nblocks:\t\t"), 0x90); | ||
196 | D_PrintHex<uint8_t > (blocks, 0x90); | ||
197 | Notify(PSTR("\r\nblock size:\t"), 0x90); | ||
198 | D_PrintHex<uint16_t > (bsize, 0x90); | ||
199 | Notify(PSTR("\r\n---------\r\n"), 0x80); | ||
200 | CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr); | ||
201 | |||
202 | again: | ||
203 | uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT); | ||
204 | |||
205 | if(er == MASS_ERR_WRITE_STALL) { | ||
206 | MediaCTL(lun, 1); | ||
207 | delay(150); | ||
208 | if(!TestUnitReady(lun)) goto again; | ||
209 | } | ||
210 | return er; | ||
211 | } | ||
212 | |||
213 | // End of user functions, the remaining code below is driver internals. | ||
214 | // Only developer serviceable parts below! | ||
215 | |||
216 | //////////////////////////////////////////////////////////////////////////////// | ||
217 | |||
218 | // Main driver code | ||
219 | |||
220 | //////////////////////////////////////////////////////////////////////////////// | ||
221 | |||
222 | BulkOnly::BulkOnly(USB *p) : | ||
223 | pUsb(p), | ||
224 | bAddress(0), | ||
225 | bIface(0), | ||
226 | bNumEP(1), | ||
227 | qNextPollTime(0), | ||
228 | bPollEnable(false), | ||
229 | //dCBWTag(0), | ||
230 | bLastUsbError(0) { | ||
231 | ClearAllEP(); | ||
232 | dCBWTag = 0; | ||
233 | if(pUsb) | ||
234 | pUsb->RegisterDeviceClass(this); | ||
235 | } | ||
236 | |||
237 | /** | ||
238 | * USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET == success | ||
239 | * We need to standardize either the rcode, or change the API to return values | ||
240 | * so a signal that additional actions are required can be produced. | ||
241 | * Some of these codes do exist already. | ||
242 | * | ||
243 | * TECHNICAL: We could do most of this code elsewhere, with the exception of checking the class instance. | ||
244 | * Doing so would save some program memory when using multiple drivers. | ||
245 | * | ||
246 | * @param parent USB address of parent | ||
247 | * @param port address of port on parent | ||
248 | * @param lowspeed true if device is low speed | ||
249 | * @return | ||
250 | */ | ||
251 | uint8_t BulkOnly::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { | ||
252 | |||
253 | const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); | ||
254 | |||
255 | uint8_t buf[constBufSize]; | ||
256 | USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); | ||
257 | uint8_t rcode; | ||
258 | UsbDevice *p = NULL; | ||
259 | EpInfo *oldep_ptr = NULL; | ||
260 | USBTRACE("MS ConfigureDevice\r\n"); | ||
261 | ClearAllEP(); | ||
262 | AddressPool &addrPool = pUsb->GetAddressPool(); | ||
263 | |||
264 | |||
265 | if(bAddress) | ||
266 | return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; | ||
267 | |||
268 | // <TECHNICAL> | ||
269 | // Get pointer to pseudo device with address 0 assigned | ||
270 | p = addrPool.GetUsbDevicePtr(0); | ||
271 | if(!p) { | ||
272 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
273 | } | ||
274 | |||
275 | if(!p->epinfo) { | ||
276 | USBTRACE("epinfo\r\n"); | ||
277 | return USB_ERROR_EPINFO_IS_NULL; | ||
278 | } | ||
279 | |||
280 | // Save old pointer to EP_RECORD of address 0 | ||
281 | oldep_ptr = p->epinfo; | ||
282 | |||
283 | // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence | ||
284 | p->epinfo = epInfo; | ||
285 | |||
286 | p->lowspeed = lowspeed; | ||
287 | // Get device descriptor | ||
288 | rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); | ||
289 | |||
290 | // Restore p->epinfo | ||
291 | p->epinfo = oldep_ptr; | ||
292 | |||
293 | if(rcode) { | ||
294 | goto FailGetDevDescr; | ||
295 | } | ||
296 | // Allocate new address according to device class | ||
297 | bAddress = addrPool.AllocAddress(parent, false, port); | ||
298 | |||
299 | if(!bAddress) | ||
300 | return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; | ||
301 | |||
302 | // Extract Max Packet Size from the device descriptor | ||
303 | epInfo[0].maxPktSize = udd->bMaxPacketSize0; | ||
304 | // Steal and abuse from epInfo structure to save on memory. | ||
305 | epInfo[1].epAddr = udd->bNumConfigurations; | ||
306 | // </TECHNICAL> | ||
307 | return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET; | ||
308 | |||
309 | FailGetDevDescr: | ||
310 | #ifdef DEBUG_USB_HOST | ||
311 | NotifyFailGetDevDescr(rcode); | ||
312 | #endif | ||
313 | rcode = USB_ERROR_FailGetDevDescr; | ||
314 | |||
315 | Release(); | ||
316 | return rcode; | ||
317 | }; | ||
318 | |||
319 | /** | ||
320 | * | ||
321 | * @param parent (not used) | ||
322 | * @param port (not used) | ||
323 | * @param lowspeed true if device is low speed | ||
324 | * @return 0 for success | ||
325 | */ | ||
326 | uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) { | ||
327 | uint8_t rcode; | ||
328 | uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations | ||
329 | epInfo[1].epAddr = 0; | ||
330 | USBTRACE("MS Init\r\n"); | ||
331 | |||
332 | AddressPool &addrPool = pUsb->GetAddressPool(); | ||
333 | UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); | ||
334 | |||
335 | if(!p) | ||
336 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
337 | |||
338 | // Assign new address to the device | ||
339 | delay(2000); | ||
340 | rcode = pUsb->setAddr(0, 0, bAddress); | ||
341 | |||
342 | if(rcode) { | ||
343 | p->lowspeed = false; | ||
344 | addrPool.FreeAddress(bAddress); | ||
345 | bAddress = 0; | ||
346 | USBTRACE2("setAddr:", rcode); | ||
347 | return rcode; | ||
348 | } | ||
349 | |||
350 | USBTRACE2("Addr:", bAddress); | ||
351 | |||
352 | p->lowspeed = false; | ||
353 | |||
354 | p = addrPool.GetUsbDevicePtr(bAddress); | ||
355 | |||
356 | if(!p) | ||
357 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
358 | |||
359 | p->lowspeed = lowspeed; | ||
360 | |||
361 | // Assign epInfo to epinfo pointer | ||
362 | rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); | ||
363 | |||
364 | if(rcode) | ||
365 | goto FailSetDevTblEntry; | ||
366 | |||
367 | USBTRACE2("NC:", num_of_conf); | ||
368 | |||
369 | for(uint8_t i = 0; i < num_of_conf; i++) { | ||
370 | ConfigDescParser< USB_CLASS_MASS_STORAGE, | ||
371 | MASS_SUBCLASS_SCSI, | ||
372 | MASS_PROTO_BBB, | ||
373 | CP_MASK_COMPARE_CLASS | | ||
374 | CP_MASK_COMPARE_SUBCLASS | | ||
375 | CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this); | ||
376 | |||
377 | rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser); | ||
378 | |||
379 | if(rcode) | ||
380 | goto FailGetConfDescr; | ||
381 | |||
382 | if(bNumEP > 1) | ||
383 | break; | ||
384 | } | ||
385 | |||
386 | if(bNumEP < 3) | ||
387 | return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; | ||
388 | |||
389 | // Assign epInfo to epinfo pointer | ||
390 | pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); | ||
391 | |||
392 | USBTRACE2("Conf:", bConfNum); | ||
393 | |||
394 | // Set Configuration Value | ||
395 | rcode = pUsb->setConf(bAddress, 0, bConfNum); | ||
396 | |||
397 | if(rcode) | ||
398 | goto FailSetConfDescr; | ||
399 | |||
400 | //Linux does a 1sec delay after this. | ||
401 | delay(1000); | ||
402 | |||
403 | rcode = GetMaxLUN(&bMaxLUN); | ||
404 | if(rcode) | ||
405 | goto FailGetMaxLUN; | ||
406 | |||
407 | if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1; | ||
408 | ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN); | ||
409 | |||
410 | delay(1000); // Delay a bit for slow firmware. | ||
411 | |||
412 | for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { | ||
413 | InquiryResponse response; | ||
414 | rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response); | ||
415 | if(rcode) { | ||
416 | ErrorMessage<uint8_t > (PSTR("Inquiry"), rcode); | ||
417 | } else { | ||
418 | #if 0 | ||
419 | printf("LUN %i `", lun); | ||
420 | uint8_t *buf = response.VendorID; | ||
421 | for(int i = 0; i < 28; i++) printf("%c", buf[i]); | ||
422 | printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier); | ||
423 | printf("Device type %2.2X ", response.DeviceType); | ||
424 | printf("RMB %1.1X ", response.Removable); | ||
425 | printf("SSCS %1.1X ", response.SCCS); | ||
426 | uint8_t sv = response.Version; | ||
427 | printf("SCSI version %2.2X\r\nDevice conforms to ", sv); | ||
428 | switch(sv) { | ||
429 | case 0: | ||
430 | printf("No specific"); | ||
431 | break; | ||
432 | case 1: | ||
433 | printf("ANSI X3.131-1986 (ANSI 1)"); | ||
434 | break; | ||
435 | case 2: | ||
436 | printf("ANSI X3.131-1994 (ANSI 2)"); | ||
437 | break; | ||
438 | case 3: | ||
439 | printf("ANSI INCITS 301-1997 (SPC)"); | ||
440 | break; | ||
441 | case 4: | ||
442 | printf("ANSI INCITS 351-2001 (SPC-2)"); | ||
443 | break; | ||
444 | case 5: | ||
445 | printf("ANSI INCITS 408-2005 (SPC-4)"); | ||
446 | break; | ||
447 | case 6: | ||
448 | printf("T10/1731-D (SPC-4)"); | ||
449 | break; | ||
450 | default: | ||
451 | printf("unknown"); | ||
452 | } | ||
453 | printf(" standards.\r\n"); | ||
454 | #endif | ||
455 | uint8_t tries = 0xf0; | ||
456 | while((rcode = TestUnitReady(lun))) { | ||
457 | if(rcode == 0x08) break; // break on no media, this is OK to do. | ||
458 | // try to lock media and spin up | ||
459 | if(tries < 14) { | ||
460 | LockMedia(lun, 1); | ||
461 | MediaCTL(lun, 1); // I actually have a USB stick that needs this! | ||
462 | } else delay(2 * (tries + 1)); | ||
463 | tries++; | ||
464 | if(!tries) break; | ||
465 | } | ||
466 | if(!rcode) { | ||
467 | delay(1000); | ||
468 | LUNOk[lun] = CheckLUN(lun); | ||
469 | if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun); | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | |||
474 | |||
475 | CheckMedia(); | ||
476 | |||
477 | rcode = OnInit(); | ||
478 | |||
479 | if(rcode) | ||
480 | goto FailOnInit; | ||
481 | |||
482 | #ifdef DEBUG_USB_HOST | ||
483 | USBTRACE("MS configured\r\n\r\n"); | ||
484 | #endif | ||
485 | |||
486 | bPollEnable = true; | ||
487 | |||
488 | //USBTRACE("Poll enabled\r\n"); | ||
489 | return 0; | ||
490 | |||
491 | FailSetConfDescr: | ||
492 | #ifdef DEBUG_USB_HOST | ||
493 | NotifyFailSetConfDescr(); | ||
494 | goto Fail; | ||
495 | #endif | ||
496 | |||
497 | FailOnInit: | ||
498 | #ifdef DEBUG_USB_HOST | ||
499 | USBTRACE("OnInit:"); | ||
500 | goto Fail; | ||
501 | #endif | ||
502 | |||
503 | FailGetMaxLUN: | ||
504 | #ifdef DEBUG_USB_HOST | ||
505 | USBTRACE("GetMaxLUN:"); | ||
506 | goto Fail; | ||
507 | #endif | ||
508 | |||
509 | //#ifdef DEBUG_USB_HOST | ||
510 | //FailInvalidSectorSize: | ||
511 | // USBTRACE("Sector Size is NOT VALID: "); | ||
512 | // goto Fail; | ||
513 | //#endif | ||
514 | |||
515 | FailSetDevTblEntry: | ||
516 | #ifdef DEBUG_USB_HOST | ||
517 | NotifyFailSetDevTblEntry(); | ||
518 | goto Fail; | ||
519 | #endif | ||
520 | |||
521 | FailGetConfDescr: | ||
522 | #ifdef DEBUG_USB_HOST | ||
523 | NotifyFailGetConfDescr(); | ||
524 | #endif | ||
525 | |||
526 | #ifdef DEBUG_USB_HOST | ||
527 | Fail: | ||
528 | NotifyFail(rcode); | ||
529 | #endif | ||
530 | Release(); | ||
531 | return rcode; | ||
532 | } | ||
533 | |||
534 | /** | ||
535 | * For driver use only. | ||
536 | * | ||
537 | * @param conf | ||
538 | * @param iface | ||
539 | * @param alt | ||
540 | * @param proto | ||
541 | * @param pep | ||
542 | */ | ||
543 | void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR * pep) { | ||
544 | ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf); | ||
545 | ErrorMessage<uint8_t > (PSTR("Iface Num"), iface); | ||
546 | ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt); | ||
547 | |||
548 | bConfNum = conf; | ||
549 | |||
550 | uint8_t index; | ||
551 | |||
552 | #if 1 | ||
553 | if((pep->bmAttributes & 0x02) == 2) { | ||
554 | index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; | ||
555 | // Fill in the endpoint info structure | ||
556 | epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); | ||
557 | epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; | ||
558 | epInfo[index].epAttribs = 0; | ||
559 | |||
560 | bNumEP++; | ||
561 | |||
562 | PrintEndpointDescriptor(pep); | ||
563 | |||
564 | } | ||
565 | #else | ||
566 | if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) | ||
567 | index = epInterruptInIndex; | ||
568 | else | ||
569 | if((pep->bmAttributes & 0x02) == 2) | ||
570 | index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; | ||
571 | else | ||
572 | return; | ||
573 | |||
574 | // Fill in the endpoint info structure | ||
575 | epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); | ||
576 | epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; | ||
577 | epInfo[index].epAttribs = 0; | ||
578 | |||
579 | bNumEP++; | ||
580 | |||
581 | PrintEndpointDescriptor(pep); | ||
582 | #endif | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * For driver use only. | ||
587 | * | ||
588 | * @return | ||
589 | */ | ||
590 | uint8_t BulkOnly::Release() { | ||
591 | ClearAllEP(); | ||
592 | pUsb->GetAddressPool().FreeAddress(bAddress); | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | /** | ||
597 | * For driver use only. | ||
598 | * | ||
599 | * @param lun Logical Unit Number | ||
600 | * @return true if LUN is ready for use. | ||
601 | */ | ||
602 | bool BulkOnly::CheckLUN(uint8_t lun) { | ||
603 | uint8_t rcode; | ||
604 | Capacity capacity; | ||
605 | for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0; | ||
606 | |||
607 | rcode = ReadCapacity10(lun, (uint8_t*)capacity.data); | ||
608 | if(rcode) { | ||
609 | //printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode); | ||
610 | return false; | ||
611 | } | ||
612 | ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun); | ||
613 | for(uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++) | ||
614 | D_PrintHex<uint8_t > (capacity.data[i], 0x80); | ||
615 | Notify(PSTR("\r\n\r\n"), 0x80); | ||
616 | // Only 512/1024/2048/4096 are valid values! | ||
617 | uint32_t c = BMAKE32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]); | ||
618 | if(c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) { | ||
619 | return false; | ||
620 | } | ||
621 | // Store capacity information. | ||
622 | CurrentSectorSize[lun] = (uint16_t)(c); // & 0xFFFF); | ||
623 | |||
624 | CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1; | ||
625 | if(CurrentCapacity[lun] == /*0xffffffffLU */ 0x01LU || CurrentCapacity[lun] == 0x00LU) { | ||
626 | // Buggy firmware will report 0xffffffff or 0 for no media | ||
627 | if(CurrentCapacity[lun]) | ||
628 | ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun); | ||
629 | return false; | ||
630 | } | ||
631 | delay(20); | ||
632 | Page3F(lun); | ||
633 | if(!TestUnitReady(lun)) return true; | ||
634 | return false; | ||
635 | } | ||
636 | |||
637 | /** | ||
638 | * For driver use only. | ||
639 | * | ||
640 | * Scan for media change on all LUNs | ||
641 | */ | ||
642 | void BulkOnly::CheckMedia() { | ||
643 | for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { | ||
644 | if(TestUnitReady(lun)) { | ||
645 | LUNOk[lun] = false; | ||
646 | continue; | ||
647 | } | ||
648 | if(!LUNOk[lun]) | ||
649 | LUNOk[lun] = CheckLUN(lun); | ||
650 | } | ||
651 | #if 0 | ||
652 | printf("}}}}}}}}}}}}}}}}STATUS "); | ||
653 | for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { | ||
654 | if(LUNOk[lun]) | ||
655 | printf("#"); | ||
656 | else printf("."); | ||
657 | } | ||
658 | printf("\r\n"); | ||
659 | #endif | ||
660 | qNextPollTime = millis() + 2000; | ||
661 | } | ||
662 | |||
663 | /** | ||
664 | * For driver use only. | ||
665 | * | ||
666 | * @return | ||
667 | */ | ||
668 | uint8_t BulkOnly::Poll() { | ||
669 | //uint8_t rcode = 0; | ||
670 | |||
671 | if(!bPollEnable) | ||
672 | return 0; | ||
673 | |||
674 | if((long)(millis() - qNextPollTime) >= 0L) { | ||
675 | CheckMedia(); | ||
676 | } | ||
677 | //rcode = 0; | ||
678 | |||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | //////////////////////////////////////////////////////////////////////////////// | ||
683 | |||
684 | |||
685 | // SCSI code | ||
686 | |||
687 | |||
688 | //////////////////////////////////////////////////////////////////////////////// | ||
689 | |||
690 | /** | ||
691 | * For driver use only. | ||
692 | * | ||
693 | * @param plun | ||
694 | * @return | ||
695 | */ | ||
696 | uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) { | ||
697 | uint8_t ret = pUsb->ctrlReq(bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL); | ||
698 | |||
699 | if(ret == hrSTALL) | ||
700 | *plun = 0; | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | /** | ||
706 | * For driver use only. Used during Driver Init | ||
707 | * | ||
708 | * @param lun Logical Unit Number | ||
709 | * @param bsize | ||
710 | * @param buf | ||
711 | * @return | ||
712 | */ | ||
713 | uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) { | ||
714 | Notify(PSTR("\r\nInquiry\r\n"), 0x80); | ||
715 | Notify(PSTR("---------\r\n"), 0x80); | ||
716 | |||
717 | CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0); | ||
718 | uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN); | ||
719 | |||
720 | return rc; | ||
721 | } | ||
722 | |||
723 | /** | ||
724 | * For driver use only. | ||
725 | * | ||
726 | * @param lun Logical Unit Number | ||
727 | * @return | ||
728 | */ | ||
729 | uint8_t BulkOnly::TestUnitReady(uint8_t lun) { | ||
730 | //SetCurLUN(lun); | ||
731 | if(!bAddress) | ||
732 | return MASS_ERR_UNIT_NOT_READY; | ||
733 | |||
734 | Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80); | ||
735 | Notify(PSTR("-----------------\r\n"), 0x80); | ||
736 | |||
737 | CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint8_t)0, 0); | ||
738 | return SCSITransaction6(&cdb, 0, NULL, (uint8_t)MASS_CMD_DIR_IN); | ||
739 | |||
740 | } | ||
741 | |||
742 | /** | ||
743 | * For driver use only. | ||
744 | * | ||
745 | * @param lun Logical Unit Number | ||
746 | * @param pc | ||
747 | * @param page | ||
748 | * @param subpage | ||
749 | * @param len | ||
750 | * @param pbuf | ||
751 | * @return | ||
752 | */ | ||
753 | uint8_t BulkOnly::ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) { | ||
754 | Notify(PSTR("\r\rModeSense\r\n"), 0x80); | ||
755 | Notify(PSTR("------------\r\n"), 0x80); | ||
756 | |||
757 | CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0); | ||
758 | return SCSITransaction6(&cdb, len, pbuf, (uint8_t)MASS_CMD_DIR_IN); | ||
759 | } | ||
760 | |||
761 | /** | ||
762 | * For driver use only. | ||
763 | * | ||
764 | * @param lun Logical Unit Number | ||
765 | * @param bsize | ||
766 | * @param buf | ||
767 | * @return | ||
768 | */ | ||
769 | uint8_t BulkOnly::ReadCapacity10(uint8_t lun, uint8_t *buf) { | ||
770 | Notify(PSTR("\r\nReadCapacity\r\n"), 0x80); | ||
771 | Notify(PSTR("---------------\r\n"), 0x80); | ||
772 | |||
773 | CDB10_t cdb = CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun); | ||
774 | return SCSITransaction10(&cdb, 8, buf, (uint8_t)MASS_CMD_DIR_IN); | ||
775 | } | ||
776 | |||
777 | /** | ||
778 | * For driver use only. | ||
779 | * | ||
780 | * Page 3F contains write protect status. | ||
781 | * | ||
782 | * @param lun Logical Unit Number to test. | ||
783 | * @return Write protect switch status. | ||
784 | */ | ||
785 | uint8_t BulkOnly::Page3F(uint8_t lun) { | ||
786 | uint8_t buf[192]; | ||
787 | for(int i = 0; i < 192; i++) { | ||
788 | buf[i] = 0x00; | ||
789 | } | ||
790 | WriteOk[lun] = true; | ||
791 | uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf); | ||
792 | if(!rc) { | ||
793 | WriteOk[lun] = ((buf[2] & 0x80) == 0); | ||
794 | Notify(PSTR("Mode Sense: "), 0x80); | ||
795 | for(int i = 0; i < 4; i++) { | ||
796 | D_PrintHex<uint8_t > (buf[i], 0x80); | ||
797 | Notify(PSTR(" "), 0x80); | ||
798 | } | ||
799 | Notify(PSTR("\r\n"), 0x80); | ||
800 | } | ||
801 | return rc; | ||
802 | } | ||
803 | |||
804 | /** | ||
805 | * For driver use only. | ||
806 | * | ||
807 | * @param lun Logical Unit Number | ||
808 | * @param size | ||
809 | * @param buf | ||
810 | * @return | ||
811 | */ | ||
812 | uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) { | ||
813 | Notify(PSTR("\r\nRequestSense\r\n"), 0x80); | ||
814 | Notify(PSTR("----------------\r\n"), 0x80); | ||
815 | |||
816 | CDB6_t cdb = CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0); | ||
817 | CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)MASS_CMD_DIR_IN); | ||
818 | //SetCurLUN(lun); | ||
819 | return Transaction(&cbw, size, buf); | ||
820 | } | ||
821 | |||
822 | |||
823 | //////////////////////////////////////////////////////////////////////////////// | ||
824 | |||
825 | |||
826 | // USB code | ||
827 | |||
828 | |||
829 | //////////////////////////////////////////////////////////////////////////////// | ||
830 | |||
831 | /** | ||
832 | * For driver use only. | ||
833 | * | ||
834 | * @param index | ||
835 | * @return | ||
836 | */ | ||
837 | uint8_t BulkOnly::ClearEpHalt(uint8_t index) { | ||
838 | if(index == 0) | ||
839 | return 0; | ||
840 | |||
841 | uint8_t ret = 0; | ||
842 | |||
843 | while((ret = (pUsb->ctrlReq(bAddress, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT, USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr), 0, 0, NULL, NULL)) == 0x01)) | ||
844 | delay(6); | ||
845 | |||
846 | if(ret) { | ||
847 | ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret); | ||
848 | ErrorMessage<uint8_t > (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr)); | ||
849 | return ret; | ||
850 | } | ||
851 | epInfo[index].bmSndToggle = 0; | ||
852 | epInfo[index].bmRcvToggle = 0; | ||
853 | // epAttribs = 0; | ||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | /** | ||
858 | * For driver use only. | ||
859 | * | ||
860 | */ | ||
861 | void BulkOnly::Reset() { | ||
862 | while(pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL) == 0x01) delay(6); | ||
863 | } | ||
864 | |||
865 | /** | ||
866 | * For driver use only. | ||
867 | * | ||
868 | * @return 0 if successful | ||
869 | */ | ||
870 | uint8_t BulkOnly::ResetRecovery() { | ||
871 | Notify(PSTR("\r\nResetRecovery\r\n"), 0x80); | ||
872 | Notify(PSTR("-----------------\r\n"), 0x80); | ||
873 | |||
874 | delay(6); | ||
875 | Reset(); | ||
876 | delay(6); | ||
877 | ClearEpHalt(epDataInIndex); | ||
878 | delay(6); | ||
879 | bLastUsbError = ClearEpHalt(epDataOutIndex); | ||
880 | delay(6); | ||
881 | return bLastUsbError; | ||
882 | } | ||
883 | |||
884 | /** | ||
885 | * For driver use only. | ||
886 | * | ||
887 | * Clear all EP data and clear all LUN status | ||
888 | */ | ||
889 | void BulkOnly::ClearAllEP() { | ||
890 | for(uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) { | ||
891 | epInfo[i].epAddr = 0; | ||
892 | epInfo[i].maxPktSize = (i) ? 0 : 8; | ||
893 | epInfo[i].epAttribs = 0; | ||
894 | |||
895 | epInfo[i].bmNakPower = USB_NAK_DEFAULT; | ||
896 | } | ||
897 | |||
898 | for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) { | ||
899 | LUNOk[i] = false; | ||
900 | WriteOk[i] = false; | ||
901 | CurrentCapacity[i] = 0lu; | ||
902 | CurrentSectorSize[i] = 0; | ||
903 | } | ||
904 | |||
905 | bIface = 0; | ||
906 | bNumEP = 1; | ||
907 | bAddress = 0; | ||
908 | qNextPollTime = 0; | ||
909 | bPollEnable = false; | ||
910 | bLastUsbError = 0; | ||
911 | bMaxLUN = 0; | ||
912 | bTheLUN = 0; | ||
913 | } | ||
914 | |||
915 | /** | ||
916 | * For driver use only. | ||
917 | * | ||
918 | * @param pcsw | ||
919 | * @param pcbw | ||
920 | * @return | ||
921 | */ | ||
922 | bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) { | ||
923 | if(pcsw->dCSWSignature != MASS_CSW_SIGNATURE) { | ||
924 | Notify(PSTR("CSW:Sig error\r\n"), 0x80); | ||
925 | return false; | ||
926 | } | ||
927 | if(pcsw->dCSWTag != pcbw->dCBWTag) { | ||
928 | Notify(PSTR("CSW:Wrong tag\r\n"), 0x80); | ||
929 | return false; | ||
930 | } | ||
931 | return true; | ||
932 | } | ||
933 | |||
934 | /** | ||
935 | * For driver use only. | ||
936 | * | ||
937 | * @param error | ||
938 | * @param index | ||
939 | * @return | ||
940 | */ | ||
941 | uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) { | ||
942 | uint8_t count = 3; | ||
943 | |||
944 | bLastUsbError = error; | ||
945 | //if (error) | ||
946 | //ClearEpHalt(index); | ||
947 | while(error && count) { | ||
948 | if(error != hrSUCCESS) { | ||
949 | ErrorMessage<uint8_t > (PSTR("USB Error"), error); | ||
950 | ErrorMessage<uint8_t > (PSTR("Index"), index); | ||
951 | } | ||
952 | switch(error) { | ||
953 | // case hrWRONGPID: | ||
954 | case hrSUCCESS: | ||
955 | return MASS_ERR_SUCCESS; | ||
956 | case hrBUSY: | ||
957 | // SIE is busy, just hang out and try again. | ||
958 | return MASS_ERR_UNIT_BUSY; | ||
959 | case hrTIMEOUT: | ||
960 | case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED; | ||
961 | case hrSTALL: | ||
962 | if(index == 0) | ||
963 | return MASS_ERR_STALL; | ||
964 | ClearEpHalt(index); | ||
965 | if(index != epDataInIndex) | ||
966 | return MASS_ERR_WRITE_STALL; | ||
967 | return MASS_ERR_STALL; | ||
968 | |||
969 | case hrNAK: | ||
970 | if(index == 0) | ||
971 | return MASS_ERR_UNIT_BUSY; | ||
972 | return MASS_ERR_UNIT_BUSY; | ||
973 | |||
974 | case hrTOGERR: | ||
975 | // Handle a very super rare corner case, where toggles become de-synched. | ||
976 | // I have only ran into one device that has this firmware bug, and this is | ||
977 | // the only clean way to get back into sync with the buggy device firmware. | ||
978 | // --AJK | ||
979 | if(bAddress && bConfNum) { | ||
980 | error = pUsb->setConf(bAddress, 0, bConfNum); | ||
981 | |||
982 | if(error) | ||
983 | break; | ||
984 | } | ||
985 | return MASS_ERR_SUCCESS; | ||
986 | default: | ||
987 | ErrorMessage<uint8_t > (PSTR("\r\nUSB"), error); | ||
988 | return MASS_ERR_GENERAL_USB_ERROR; | ||
989 | } | ||
990 | count--; | ||
991 | } // while | ||
992 | |||
993 | return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS); | ||
994 | } | ||
995 | |||
996 | #if MS_WANT_PARSER | ||
997 | |||
998 | uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) { | ||
999 | return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0); | ||
1000 | } | ||
1001 | #endif | ||
1002 | |||
1003 | /** | ||
1004 | * For driver use only. | ||
1005 | * | ||
1006 | * @param pcbw | ||
1007 | * @param buf_size | ||
1008 | * @param buf | ||
1009 | * @param flags | ||
1010 | * @return | ||
1011 | */ | ||
1012 | uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf | ||
1013 | #if MS_WANT_PARSER | ||
1014 | , uint8_t flags | ||
1015 | #endif | ||
1016 | ) { | ||
1017 | |||
1018 | #if MS_WANT_PARSER | ||
1019 | uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength; | ||
1020 | printf("Transfersize %i\r\n", bytes); | ||
1021 | delay(1000); | ||
1022 | |||
1023 | bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK; | ||
1024 | #else | ||
1025 | uint16_t bytes = buf_size; | ||
1026 | #endif | ||
1027 | bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN; | ||
1028 | uint8_t ret = 0; | ||
1029 | uint8_t usberr; | ||
1030 | CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles. | ||
1031 | SetCurLUN(pcbw->bmCBWLUN); | ||
1032 | ErrorMessage<uint32_t > (PSTR("CBW.dCBWTag"), pcbw->dCBWTag); | ||
1033 | |||
1034 | while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) delay(1); | ||
1035 | |||
1036 | ret = HandleUsbError(usberr, epDataOutIndex); | ||
1037 | //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex); | ||
1038 | if(ret) { | ||
1039 | ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret); | ||
1040 | } else { | ||
1041 | if(bytes) { | ||
1042 | if(!write) { | ||
1043 | #if MS_WANT_PARSER | ||
1044 | if(callback) { | ||
1045 | uint8_t rbuf[bytes]; | ||
1046 | while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) delay(1); | ||
1047 | if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0); | ||
1048 | } else { | ||
1049 | #endif | ||
1050 | while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) delay(1); | ||
1051 | #if MS_WANT_PARSER | ||
1052 | |||
1053 | } | ||
1054 | #endif | ||
1055 | ret = HandleUsbError(usberr, epDataInIndex); | ||
1056 | } else { | ||
1057 | while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) delay(1); | ||
1058 | ret = HandleUsbError(usberr, epDataOutIndex); | ||
1059 | } | ||
1060 | if(ret) { | ||
1061 | ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret); | ||
1062 | } | ||
1063 | } | ||
1064 | } | ||
1065 | |||
1066 | { | ||
1067 | bytes = sizeof (CommandStatusWrapper); | ||
1068 | int tries = 2; | ||
1069 | while(tries--) { | ||
1070 | while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) delay(1); | ||
1071 | if(!usberr) break; | ||
1072 | ClearEpHalt(epDataInIndex); | ||
1073 | if(tries) ResetRecovery(); | ||
1074 | } | ||
1075 | if(!ret) { | ||
1076 | Notify(PSTR("CBW:\t\tOK\r\n"), 0x80); | ||
1077 | Notify(PSTR("Data Stage:\tOK\r\n"), 0x80); | ||
1078 | } else { | ||
1079 | // Throw away csw, IT IS NOT OF ANY USE. | ||
1080 | ResetRecovery(); | ||
1081 | return ret; | ||
1082 | } | ||
1083 | ret = HandleUsbError(usberr, epDataInIndex); | ||
1084 | if(ret) { | ||
1085 | ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret); | ||
1086 | } | ||
1087 | if(usberr == hrSUCCESS) { | ||
1088 | if(IsValidCSW(&csw, pcbw)) { | ||
1089 | //ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag); | ||
1090 | //ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus); | ||
1091 | //ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue); | ||
1092 | Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80); | ||
1093 | return csw.bCSWStatus; | ||
1094 | } else { | ||
1095 | // NOTE! Sometimes this is caused by the reported residue being wrong. | ||
1096 | // Get a different device. It isn't compliant, and should have never passed Q&A. | ||
1097 | // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter. | ||
1098 | // Other devices that exhibit this behavior exist in the wild too. | ||
1099 | // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk | ||
1100 | Notify(PSTR("Invalid CSW\r\n"), 0x80); | ||
1101 | ResetRecovery(); | ||
1102 | //return MASS_ERR_SUCCESS; | ||
1103 | return MASS_ERR_INVALID_CSW; | ||
1104 | } | ||
1105 | } | ||
1106 | } | ||
1107 | return ret; | ||
1108 | } | ||
1109 | |||
1110 | /** | ||
1111 | * For driver use only. | ||
1112 | * | ||
1113 | * @param lun Logical Unit Number | ||
1114 | * @return | ||
1115 | */ | ||
1116 | uint8_t BulkOnly::SetCurLUN(uint8_t lun) { | ||
1117 | if(lun > bMaxLUN) | ||
1118 | return MASS_ERR_INVALID_LUN; | ||
1119 | bTheLUN = lun; | ||
1120 | return MASS_ERR_SUCCESS; | ||
1121 | }; | ||
1122 | |||
1123 | /** | ||
1124 | * For driver use only. | ||
1125 | * | ||
1126 | * @param status | ||
1127 | * @return | ||
1128 | */ | ||
1129 | uint8_t BulkOnly::HandleSCSIError(uint8_t status) { | ||
1130 | uint8_t ret = 0; | ||
1131 | |||
1132 | switch(status) { | ||
1133 | case 0: return MASS_ERR_SUCCESS; | ||
1134 | |||
1135 | case 2: | ||
1136 | ErrorMessage<uint8_t > (PSTR("Phase Error"), status); | ||
1137 | ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); | ||
1138 | ResetRecovery(); | ||
1139 | return MASS_ERR_GENERAL_SCSI_ERROR; | ||
1140 | |||
1141 | case 1: | ||
1142 | ErrorMessage<uint8_t > (PSTR("SCSI Error"), status); | ||
1143 | ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); | ||
1144 | RequestSenseResponce rsp; | ||
1145 | |||
1146 | ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp); | ||
1147 | |||
1148 | if(ret) { | ||
1149 | return MASS_ERR_GENERAL_SCSI_ERROR; | ||
1150 | } | ||
1151 | ErrorMessage<uint8_t > (PSTR("Response Code"), rsp.bResponseCode); | ||
1152 | if(rsp.bResponseCode & 0x80) { | ||
1153 | Notify(PSTR("Information field: "), 0x80); | ||
1154 | for(int i = 0; i < 4; i++) { | ||
1155 | D_PrintHex<uint8_t > (rsp.CmdSpecificInformation[i], 0x80); | ||
1156 | Notify(PSTR(" "), 0x80); | ||
1157 | } | ||
1158 | Notify(PSTR("\r\n"), 0x80); | ||
1159 | } | ||
1160 | ErrorMessage<uint8_t > (PSTR("Sense Key"), rsp.bmSenseKey); | ||
1161 | ErrorMessage<uint8_t > (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode); | ||
1162 | ErrorMessage<uint8_t > (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier); | ||
1163 | // warning, this is not testing ASQ, only SK and ASC. | ||
1164 | switch(rsp.bmSenseKey) { | ||
1165 | case SCSI_S_UNIT_ATTENTION: | ||
1166 | switch(rsp.bAdditionalSenseCode) { | ||
1167 | case SCSI_ASC_MEDIA_CHANGED: | ||
1168 | return MASS_ERR_MEDIA_CHANGED; | ||
1169 | default: | ||
1170 | return MASS_ERR_UNIT_NOT_READY; | ||
1171 | } | ||
1172 | case SCSI_S_NOT_READY: | ||
1173 | switch(rsp.bAdditionalSenseCode) { | ||
1174 | case SCSI_ASC_MEDIUM_NOT_PRESENT: | ||
1175 | return MASS_ERR_NO_MEDIA; | ||
1176 | default: | ||
1177 | return MASS_ERR_UNIT_NOT_READY; | ||
1178 | } | ||
1179 | case SCSI_S_ILLEGAL_REQUEST: | ||
1180 | switch(rsp.bAdditionalSenseCode) { | ||
1181 | case SCSI_ASC_LBA_OUT_OF_RANGE: | ||
1182 | return MASS_ERR_BAD_LBA; | ||
1183 | default: | ||
1184 | return MASS_ERR_CMD_NOT_SUPPORTED; | ||
1185 | } | ||
1186 | default: | ||
1187 | return MASS_ERR_GENERAL_SCSI_ERROR; | ||
1188 | } | ||
1189 | |||
1190 | // case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later. | ||
1191 | // case 0x05/0x14: we stalled out | ||
1192 | // case 0x15/0x16: we naked out. | ||
1193 | default: | ||
1194 | ErrorMessage<uint8_t > (PSTR("Gen SCSI Err"), status); | ||
1195 | ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); | ||
1196 | return status; | ||
1197 | } // switch | ||
1198 | } | ||
1199 | |||
1200 | |||
1201 | //////////////////////////////////////////////////////////////////////////////// | ||
1202 | |||
1203 | |||
1204 | // Debugging code | ||
1205 | |||
1206 | |||
1207 | //////////////////////////////////////////////////////////////////////////////// | ||
1208 | |||
1209 | /** | ||
1210 | * | ||
1211 | * @param ep_ptr | ||
1212 | */ | ||
1213 | void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) { | ||
1214 | Notify(PSTR("Endpoint descriptor:"), 0x80); | ||
1215 | Notify(PSTR("\r\nLength:\t\t"), 0x80); | ||
1216 | D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80); | ||
1217 | Notify(PSTR("\r\nType:\t\t"), 0x80); | ||
1218 | D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80); | ||
1219 | Notify(PSTR("\r\nAddress:\t"), 0x80); | ||
1220 | D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80); | ||
1221 | Notify(PSTR("\r\nAttributes:\t"), 0x80); | ||
1222 | D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80); | ||
1223 | Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); | ||
1224 | D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80); | ||
1225 | Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); | ||
1226 | D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80); | ||
1227 | Notify(PSTR("\r\n"), 0x80); | ||
1228 | } | ||
1229 | |||
1230 | |||
1231 | //////////////////////////////////////////////////////////////////////////////// | ||
1232 | |||
1233 | |||
1234 | // misc/to kill/to-do | ||
1235 | |||
1236 | |||
1237 | //////////////////////////////////////////////////////////////////////////////// | ||
1238 | |||
1239 | /* We won't be needing this... */ | ||
1240 | uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser * prs) { | ||
1241 | #if MS_WANT_PARSER | ||
1242 | if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; | ||
1243 | Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80); | ||
1244 | Notify(PSTR("---------\r\n"), 0x80); | ||
1245 | |||
1246 | CommandBlockWrapper cbw = CommandBlockWrapper(); | ||
1247 | |||
1248 | cbw.dCBWSignature = MASS_CBW_SIGNATURE; | ||
1249 | cbw.dCBWTag = ++dCBWTag; | ||
1250 | cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks); | ||
1251 | cbw.bmCBWFlags = MASS_CMD_DIR_IN, | ||
1252 | cbw.bmCBWLUN = lun; | ||
1253 | cbw.bmCBWCBLength = 10; | ||
1254 | |||
1255 | cbw.CBWCB[0] = SCSI_CMD_READ_10; | ||
1256 | cbw.CBWCB[8] = blocks; | ||
1257 | cbw.CBWCB[2] = ((addr >> 24) & 0xff); | ||
1258 | cbw.CBWCB[3] = ((addr >> 16) & 0xff); | ||
1259 | cbw.CBWCB[4] = ((addr >> 8) & 0xff); | ||
1260 | cbw.CBWCB[5] = (addr & 0xff); | ||
1261 | |||
1262 | return HandleSCSIError(Transaction(&cbw, bsize, prs, 1)); | ||
1263 | #else | ||
1264 | return MASS_ERR_NOT_IMPLEMENTED; | ||
1265 | #endif | ||
1266 | } | ||