PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
usb_mass.c
1/*
2 * usb_driver.c - USB Mass Storage Driver
3 * See usbmass-ufi10.pdf and usbmassbulk_10.pdf
4 */
5
6#include <errno.h>
7#include <stdio.h>
8#include <sysclib.h>
9#include <thbase.h>
10#include <thsemap.h>
11#include <usbd.h>
12#include <usbd_macro.h>
13
14#include "scsi.h"
15#include <usbhdfsd-common.h>
16
17// #define ASYNC
18// #define DEBUG //comment out this line when not debugging
19#include "module_debug.h"
20
21#define USB_SUBCLASS_MASS_RBC 0x01
22#define USB_SUBCLASS_MASS_ATAPI 0x02
23#define USB_SUBCLASS_MASS_QIC 0x03
24#define USB_SUBCLASS_MASS_UFI 0x04
25#define USB_SUBCLASS_MASS_SFF_8070I 0x05
26#define USB_SUBCLASS_MASS_SCSI 0x06
27
28#define USB_PROTOCOL_MASS_CBI 0x00
29#define USB_PROTOCOL_MASS_CBI_NO_CCI 0x01
30#define USB_PROTOCOL_MASS_BULK_ONLY 0x50
31
32#define USB_BLK_EP_IN 0
33#define USB_BLK_EP_OUT 1
34
35#define USB_XFER_MAX_RETRIES 8
36
37#define CBW_TAG 0x43425355
38#define CSW_TAG 0x53425355
39
40typedef struct _mass_dev
41{
42 int controlEp; // config endpoint id
43 int bulkEpI; // in endpoint id
44 int bulkEpO; // out endpoint id
45 int devId; // device id
46 unsigned char configId; // configuration id
47 unsigned char status;
48 unsigned char interfaceNumber; // interface number
49 unsigned char interfaceAlt; // interface alternate setting
50 int ioSema;
51 struct scsi_interface scsi;
52} mass_dev;
53
54typedef struct _cbw_packet
55{
56 unsigned int signature;
57 unsigned int tag;
58 unsigned int dataTransferLength;
59 unsigned char flags; // 80->data in, 00->out
60 unsigned char lun;
61 unsigned char comLength; // command data length
62 unsigned char comData[16]; // command data
64
65typedef struct _csw_packet
66{
67 unsigned int signature;
68 unsigned int tag;
69 unsigned int dataResidue;
70 unsigned char status;
72
73static sceUsbdLddOps driver;
74
75typedef struct _usb_callback_data
76{
77 int sema;
78 int returnCode;
79 int returnSize;
81
82#define USB_BLOCK_SIZE 4096 // Maximum single USB 1.1 transfer length.
83
84typedef struct _usb_transfer_callback_data
85{
86 int sema;
87 int pipe;
88 u8 *buffer;
89 int returnCode;
90 unsigned int remaining;
92
93#define NUM_DEVICES 2
94static mass_dev g_mass_device[NUM_DEVICES];
95static int usb_mass_update_sema;
96
97static void usb_callback(int resultCode, int bytes, void *arg);
98#ifndef ASYNC
99static int perform_bulk_transfer(usb_transfer_callback_data *data);
100static void usb_transfer_callback(int resultCode, int bytes, void *arg);
101#endif
102static void usb_mass_release(mass_dev *dev);
103
104static void usb_callback(int resultCode, int bytes, void *arg)
105{
107 data->returnCode = resultCode;
108 data->returnSize = bytes;
109 M_DEBUG("callback: res %d, bytes %d, arg %p \n", resultCode, bytes, arg);
110 SignalSema(data->sema);
111}
112
113#ifndef ASYNC
114static int perform_bulk_transfer(usb_transfer_callback_data *data)
115{
116 int ret, len;
117
118 len = data->remaining > USB_BLOCK_SIZE ? USB_BLOCK_SIZE : data->remaining;
119 ret = sceUsbdBulkTransfer(
120 data->pipe, // bulk pipe epI (Read) or epO (Write)
121 data->buffer, // data ptr
122 len, // data length
123 &usb_transfer_callback,
124 (void *)data);
125 return ret;
126}
127
128static void usb_transfer_callback(int resultCode, int bytes, void *arg)
129{
131
132 data->returnCode = resultCode;
133 if (resultCode == USB_RC_OK) { // Update transfer progress if successful.
134 data->remaining -= bytes;
135 data->buffer += bytes;
136 }
137
138 if ((resultCode == USB_RC_OK) && (data->remaining > 0)) { // OK to continue.
139 int ret;
140
141 ret = perform_bulk_transfer(data);
142 if (ret != USB_RC_OK) {
143 data->returnCode = ret;
144 SignalSema(data->sema);
145 }
146 } else {
147 SignalSema(data->sema);
148 }
149}
150#endif
151
152static int usb_set_configuration(mass_dev *dev, int configNumber)
153{
154 int ret;
155 usb_callback_data cb_data;
156
157 cb_data.sema = dev->ioSema;
158
159 M_DEBUG("setting configuration controlEp=%i, confNum=%i \n", dev->controlEp, configNumber);
160 ret = sceUsbdSetConfiguration(dev->controlEp, configNumber, usb_callback, (void *)&cb_data);
161
162 if (ret == USB_RC_OK) {
163 WaitSema(cb_data.sema);
164 ret = cb_data.returnCode;
165 }
166
167 return ret;
168}
169
170static int usb_set_interface(mass_dev *dev, int interface, int altSetting)
171{
172 int ret;
173 usb_callback_data cb_data;
174
175 cb_data.sema = dev->ioSema;
176
177 M_DEBUG("setting interface controlEp=%i, interface=%i altSetting=%i\n", dev->controlEp, interface, altSetting);
178 ret = sceUsbdSetInterface(dev->controlEp, interface, altSetting, usb_callback, (void *)&cb_data);
179
180 if (ret == USB_RC_OK) {
181 WaitSema(cb_data.sema);
182 ret = cb_data.returnCode;
183 }
184
185 return ret;
186}
187
188static int usb_bulk_clear_halt(mass_dev *dev, int endpoint)
189{
190 int ret;
191 usb_callback_data cb_data;
192
193 cb_data.sema = dev->ioSema;
194
195 ret = sceUsbdClearEndpointFeature(
196 dev->controlEp, // Config pipe
197 0, // HALT feature
198 (endpoint == USB_BLK_EP_IN) ? dev->bulkEpI : dev->bulkEpO,
199 usb_callback,
200 (void *)&cb_data);
201
202 if (ret == USB_RC_OK) {
203 WaitSema(cb_data.sema);
204 ret = cb_data.returnCode;
205 }
206 if (ret != USB_RC_OK) {
207 M_DEBUG("ERROR: sending clear halt %d\n", ret);
208 }
209
210 return ret;
211}
212
213#ifndef ASYNC
214static void usb_bulk_reset(mass_dev *dev, int mode)
215{
216 int ret;
217 usb_callback_data cb_data;
218
219 cb_data.sema = dev->ioSema;
220
221 // Call Bulk only mass storage reset
222 ret = sceUsbdControlTransfer(
223 dev->controlEp, // default pipe
224 0x21, // bulk reset
225 0xFF,
226 0,
227 dev->interfaceNumber, // interface number
228 0, // length
229 NULL, // data
230 usb_callback,
231 (void *)&cb_data);
232
233 if (ret == USB_RC_OK) {
234 WaitSema(cb_data.sema);
235 ret = cb_data.returnCode;
236 }
237 if (ret == USB_RC_OK) {
238 // clear bulk-in endpoint
239 if (mode & 0x01)
240 ret = usb_bulk_clear_halt(dev, USB_BLK_EP_IN);
241 }
242 if (ret == USB_RC_OK) {
243 // clear bulk-out endpoint
244 if (mode & 0x02)
245 ret = usb_bulk_clear_halt(dev, USB_BLK_EP_OUT);
246 }
247 if (ret != USB_RC_OK) {
248 M_DEBUG("ERROR: sending reset %d to device %d.\n", ret, dev->devId);
249 dev->status |= USBMASS_DEV_STAT_ERR;
250 }
251}
252
253static int usb_bulk_status(mass_dev *dev, csw_packet *csw, unsigned int tag)
254{
255 int ret;
256 usb_callback_data cb_data;
257
258 cb_data.sema = dev->ioSema;
259
260 csw->signature = CSW_TAG;
261 csw->tag = tag;
262 csw->dataResidue = 0;
263 csw->status = 0;
264
265 ret = sceUsbdBulkTransfer(
266 dev->bulkEpI, // bulk input pipe
267 csw, // data ptr
268 13, // data length
269 usb_callback,
270 (void *)&cb_data);
271
272 if (ret == USB_RC_OK) {
273 WaitSema(cb_data.sema);
274 ret = cb_data.returnCode;
275
276#ifdef DEBUG
277 if (cb_data.returnSize != 13)
278 M_DEBUG("bulk csw.status returnSize: %i != 13\n", cb_data.returnSize);
279 if (csw->dataResidue != 0)
280 M_DEBUG("bulk csw.status residue: %i\n", csw->dataResidue);
281 M_DEBUG("bulk csw result: %d, csw.status: %i\n", ret, csw->status);
282#endif
283 }
284
285 return ret;
286}
287
288/* see flow chart in the usbmassbulk_10.pdf doc (page 15)
289
290 Returned values:
291 <0 Low-level USBD error.
292 0 = Command completed successfully.
293 1 = Command failed.
294 2 = Phase error.
295*/
296static int usb_bulk_manage_status(mass_dev *dev, unsigned int tag)
297{
298 int ret;
299 csw_packet csw;
300
301 // XPRINTF("USBHDFSD: usb_bulk_manage_status 1 ...\n");
302 ret = usb_bulk_status(dev, &csw, tag); /* Attempt to read CSW from bulk in endpoint */
303 if (ret != USB_RC_OK) { /* STALL bulk in -OR- Bulk error */
304 usb_bulk_clear_halt(dev, USB_BLK_EP_IN); /* clear the stall condition for bulk in */
305
306 M_DEBUG("ERROR: usb_bulk_manage_status error %d ...\n", ret);
307 ret = usb_bulk_status(dev, &csw, tag); /* Attempt to read CSW from bulk in endpoint */
308 }
309
310 /* CSW not valid or stalled or phase error */
311 if (ret != USB_RC_OK || csw.signature != CSW_TAG || csw.tag != tag || csw.status == 2) {
312 M_DEBUG("ERROR: usb_bulk_manage_status call reset recovery ...\n");
313 usb_bulk_reset(dev, 3); /* Perform reset recovery */
314 }
315
316 return ((ret == USB_RC_OK && csw.signature == CSW_TAG && csw.tag == tag) ? csw.status : -1);
317}
318#endif
319
320static int usb_bulk_get_max_lun(struct scsi_interface *scsi)
321{
322 mass_dev *dev = (mass_dev *)scsi->priv;
323 int ret;
324 usb_callback_data cb_data;
325 char max_lun;
326
327 cb_data.sema = dev->ioSema;
328
329 // Call Bulk only mass storage reset
330 ret = sceUsbdControlTransfer(
331 dev->controlEp, // default pipe
332 0xA1,
333 0xFE,
334 0,
335 dev->interfaceNumber, // interface number
336 1, // length
337 &max_lun, // data
338 usb_callback,
339 (void *)&cb_data);
340
341 if (ret == USB_RC_OK) {
342 WaitSema(cb_data.sema);
343 ret = cb_data.returnCode;
344 }
345 if (ret == USB_RC_OK) {
346 ret = max_lun;
347 } else {
348 // Devices that do not support multiple LUNs may STALL this command.
349 usb_bulk_clear_halt(dev, USB_BLK_EP_IN);
350 usb_bulk_clear_halt(dev, USB_BLK_EP_OUT);
351
352 ret = -ret;
353 }
354
355 return ret;
356}
357
359{
360 mass_dev *dev;
361
362 cbw_packet cbw;
363 csw_packet csw;
364 int cmd_count;
365
366 int returnCode;
367};
368
369#ifndef ASYNC
370static int usb_bulk_command(mass_dev *dev, cbw_packet *packet)
371{
372 int ret;
373 usb_callback_data cb_data;
374
375 if (dev->status & USBMASS_DEV_STAT_ERR) {
376 M_DEBUG("Rejecting I/O to offline device %d.\n", dev->devId);
377 return -1;
378 }
379
380 cb_data.sema = dev->ioSema;
381
382 ret = sceUsbdBulkTransfer(
383 dev->bulkEpO, // bulk output pipe
384 packet, // data ptr
385 31, // data length
386 usb_callback,
387 (void *)&cb_data);
388
389 if (ret == USB_RC_OK) {
390 WaitSema(cb_data.sema);
391 ret = cb_data.returnCode;
392 }
393 if (ret != USB_RC_OK) {
394 M_DEBUG("ERROR: sending bulk command %d. Calling reset recovery.\n", ret);
395 usb_bulk_reset(dev, 3);
396 }
397
398 return ret;
399}
400
401static int usb_bulk_transfer(mass_dev *dev, int direction, void *buffer, unsigned int transferSize)
402{
403 int ret;
405
406 cb_data.sema = dev->ioSema;
407 cb_data.pipe = (direction == USB_BLK_EP_IN) ? dev->bulkEpI : dev->bulkEpO;
408 cb_data.buffer = buffer;
409 cb_data.returnCode = 0;
410 cb_data.remaining = transferSize;
411
412 ret = perform_bulk_transfer(&cb_data);
413 if (ret == USB_RC_OK) {
414 WaitSema(cb_data.sema);
415 ret = cb_data.returnCode;
416 }
417
418 if (ret != USB_RC_OK) {
419 M_DEBUG("ERROR: bulk data transfer %d. Clearing HALT state.\n", ret);
420 usb_bulk_clear_halt(dev, direction);
421 }
422
423 return ret;
424}
425
426#else
427
428static void scsi_cmd_callback(int resultCode, int bytes, void *arg)
429{
430 struct usbmass_cmd *ucmd = (struct usbmass_cmd *)arg;
431 mass_dev *dev = (mass_dev *)ucmd->dev;
432
433 M_DEBUG("%s, result=%d\n", __func__, resultCode);
434
435 ucmd->cmd_count--;
436 if ((resultCode != USB_RC_OK) || (ucmd->cmd_count == 0)) {
437 // TODO: handle error in an async way (cannot block in usb callback)
438 ucmd->returnCode = resultCode;
439 SignalSema(dev->ioSema);
440 }
441}
442#endif
443
444int usb_queue_cmd(struct scsi_interface *scsi, const unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int data_len, unsigned int data_wr)
445{
446 mass_dev *dev = (mass_dev *)scsi->priv;
447 static struct usbmass_cmd ucmd;
448 int result;
449#ifndef ASYNC
450 int rcode;
451#endif
452 static unsigned int tag = 0;
453
454 M_DEBUG("%s\n", __func__);
455
456 tag++;
457
458 // Create USB command
459 ucmd.dev = dev;
460 ucmd.cmd_count = 0;
461
462 // Create CBW
463 ucmd.cbw.signature = CBW_TAG;
464 ucmd.cbw.tag = tag;
465 ucmd.cbw.dataTransferLength = data_len;
466 ucmd.cbw.flags = data_wr ? 0 : 0x80;
467 ucmd.cbw.lun = 0;
468 ucmd.cbw.comLength = cmd_len;
469 memcpy(ucmd.cbw.comData, cmd, cmd_len);
470
471 // Create CSW
472 ucmd.csw.signature = CSW_TAG;
473 ucmd.csw.tag = tag;
474 ucmd.csw.dataResidue = 0;
475 ucmd.csw.status = 0;
476
477#ifndef ASYNC
478 result = -EIO;
479 if (usb_bulk_command(dev, &ucmd.cbw) == USB_RC_OK) {
480 if (data_len > 0)
481 rcode = usb_bulk_transfer(dev, data_wr ? USB_BLK_EP_OUT : USB_BLK_EP_IN, data, data_len);
482 else
483 rcode = USB_RC_OK;
484
485 result = usb_bulk_manage_status(dev, tag);
486
487 if (rcode != USB_RC_OK)
488 result = -EIO;
489 }
490
491 return result;
492#else
493 // Send the CBW (command)
494 ucmd.cmd_count++;
495 result = sceUsbdBulkTransfer(dev->bulkEpO, &ucmd.cbw, 31, scsi_cmd_callback, (void *)&ucmd);
496 if (result != USB_RC_OK)
497 return -EIO;
498
499 // Send/Receive data
500 while (data_len > 0) {
501 unsigned int tr_len = (data_len < USB_BLOCK_SIZE) ? data_len : USB_BLOCK_SIZE;
502 ucmd.cmd_count++;
503 result = sceUsbdBulkTransfer(data_wr ? dev->bulkEpO : dev->bulkEpI, data, tr_len, scsi_cmd_callback, (void *)&ucmd);
504 if (result != USB_RC_OK)
505 return -EIO;
506 data_len -= tr_len;
507 data += tr_len;
508 }
509
510 // Receive CSW (status)
511 ucmd.cmd_count++;
512 result = sceUsbdBulkTransfer(dev->bulkEpI, &ucmd.csw, 13, scsi_cmd_callback, (void *)&ucmd);
513 if (result != USB_RC_OK)
514 return -EIO;
515
516 // Wait for SCSI command to finish
517 WaitSema(dev->ioSema);
518 if (ucmd.returnCode != USB_RC_OK)
519 return -EIO;
520
521 return 0;
522#endif
523}
524
525static mass_dev *usb_mass_findDevice(int devId, int create)
526{
527 mass_dev *dev = NULL;
528 int i;
529 M_DEBUG("usb_mass_findDevice devId %i\n", devId);
530 for (i = 0; i < NUM_DEVICES; ++i) {
531 if (g_mass_device[i].devId == devId) {
532 M_DEBUG("usb_mass_findDevice exists %i\n", i);
533 dev = &g_mass_device[i];
534 break;
535 } else if (create && dev == NULL && g_mass_device[i].devId == -1) {
536 dev = &g_mass_device[i];
537 break;
538 }
539 }
540 return dev;
541}
542
543/* test that endpoint is bulk endpoint and if so, update device info */
544static void usb_bulk_probeEndpoint(int devId, mass_dev *dev, UsbEndpointDescriptor *endpoint)
545{
546 if (endpoint->bmAttributes == USB_ENDPOINT_XFER_BULK) {
547 if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT && dev->bulkEpO < 0) {
548 /* When sceUsbdOpenPipe() is used to work around the hardware errata that occurs when an unaligned memory address is specified,
549 some USB devices become incompatible. Hence it is preferable to do alignment correction in software instead. */
550 dev->bulkEpO = sceUsbdOpenPipeAligned(devId, endpoint);
551 M_DEBUG("register Output endpoint id =%i addr=%02X packetSize=%i\n", dev->bulkEpO, endpoint->bEndpointAddress, (unsigned short int)endpoint->wMaxPacketSizeHB << 8 | endpoint->wMaxPacketSizeLB);
552 } else
553 /* Open this pipe with sceUsbdOpenPipe, to allow unaligned addresses to be used.
554 According to the Sony documentation and the USBD code,
555 there is always an alignment check if the pipe is opened with the sceUsbdOpenPipeAligned(),
556 even when there is never any correction for the bulk out pipe. */
557 if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN && dev->bulkEpI < 0) {
558 dev->bulkEpI = sceUsbdOpenPipe(devId, endpoint);
559 M_DEBUG("register Input endpoint id =%i addr=%02X packetSize=%i\n", dev->bulkEpI, endpoint->bEndpointAddress, (unsigned short int)endpoint->wMaxPacketSizeHB << 8 | endpoint->wMaxPacketSizeLB);
560 }
561 }
562}
563
564static int usb_mass_probe(int devId)
565{
566 UsbDeviceDescriptor *device = NULL;
567 UsbConfigDescriptor *config = NULL;
568 UsbInterfaceDescriptor *intf = NULL;
569
570 M_DEBUG("probe: devId=%i\n", devId);
571
572 mass_dev *mass_device = usb_mass_findDevice(devId, 0);
573
574 /* only one device supported */
575 if ((mass_device != NULL) && (mass_device->status & USBMASS_DEV_STAT_CONN)) {
576 M_PRINTF("ERROR: Only one mass storage device allowed!\n");
577 return 0;
578 }
579
580 /* get device descriptor */
581 device = (UsbDeviceDescriptor *)sceUsbdScanStaticDescriptor(devId, NULL, USB_DT_DEVICE);
582 if (device == NULL) {
583 M_DEBUG("ERROR: Couldn't get device descriptor\n");
584 return 0;
585 }
586
587 /* Check if the device has at least one configuration */
588 if (device->bNumConfigurations < 1) {
589 return 0;
590 }
591
592 /* read configuration */
593 config = (UsbConfigDescriptor *)sceUsbdScanStaticDescriptor(devId, device, USB_DT_CONFIG);
594 if (config == NULL) {
595 M_DEBUG("ERROR: Couldn't get configuration descriptor\n");
596 return 0;
597 }
598 /* check that at least one interface exists */
599 M_DEBUG("bNumInterfaces %d\n", config->bNumInterfaces);
600 if ((config->bNumInterfaces < 1) || (config->wTotalLength < (sizeof(UsbConfigDescriptor) + sizeof(UsbInterfaceDescriptor)))) {
601 M_DEBUG("ERROR: No interfaces available\n");
602 return 0;
603 }
604 /* get interface */
605 intf = (UsbInterfaceDescriptor *)((char *)config + config->bLength); /* Get first interface */
606 M_DEBUG("bInterfaceClass %X bInterfaceSubClass %X bInterfaceProtocol %X\n",
607 intf->bInterfaceClass, intf->bInterfaceSubClass, intf->bInterfaceProtocol);
608
609 if ((intf->bInterfaceClass != USB_CLASS_MASS_STORAGE) || (intf->bInterfaceSubClass != USB_SUBCLASS_MASS_SCSI && intf->bInterfaceSubClass != USB_SUBCLASS_MASS_SFF_8070I) || (intf->bInterfaceProtocol != USB_PROTOCOL_MASS_BULK_ONLY) || (intf->bNumEndpoints < 2)) { // one bulk endpoint is not enough because
610 return 0; // we send the CBW to te bulk out endpoint
611 }
612
613 return 1;
614}
615
616static int usb_mass_connect(int devId)
617{
618 int i;
619 int epCount;
620 UsbDeviceDescriptor *device;
621 UsbConfigDescriptor *config;
622 UsbInterfaceDescriptor *interface;
623 UsbEndpointDescriptor *endpoint;
624 iop_sema_t SemaData;
625 mass_dev *dev;
626
627 M_PRINTF("connect: devId=%i\n", devId);
628 dev = usb_mass_findDevice(devId, 1);
629
630 if (dev == NULL) {
631 M_PRINTF("ERROR: Unable to allocate space!\n");
632 return 1;
633 }
634
635 /* only one mass device allowed */
636 if (dev->devId != -1) {
637 M_PRINTF("ERROR: Only one mass storage device allowed!\n");
638 return 1;
639 }
640
641 dev->status = 0;
642 dev->bulkEpI = -1;
643 dev->bulkEpO = -1;
644
645 /* open the config endpoint */
646 dev->controlEp = sceUsbdOpenPipe(devId, NULL);
647
648 device = (UsbDeviceDescriptor *)sceUsbdScanStaticDescriptor(devId, NULL, USB_DT_DEVICE);
649
650 config = (UsbConfigDescriptor *)sceUsbdScanStaticDescriptor(devId, device, USB_DT_CONFIG);
651
652 interface = (UsbInterfaceDescriptor *)((char *)config + config->bLength); /* Get first interface */
653
654 // store interface numbers
655 dev->interfaceNumber = interface->bInterfaceNumber;
656 dev->interfaceAlt = interface->bAlternateSetting;
657
658 epCount = interface->bNumEndpoints;
659 endpoint = (UsbEndpointDescriptor *)sceUsbdScanStaticDescriptor(devId, NULL, USB_DT_ENDPOINT);
660 usb_bulk_probeEndpoint(devId, dev, endpoint);
661
662 for (i = 1; i < epCount; i++) {
663 endpoint = (UsbEndpointDescriptor *)((char *)endpoint + endpoint->bLength);
664 usb_bulk_probeEndpoint(devId, dev, endpoint);
665 }
666
667 // Bail out if we do NOT have enough bulk endpoints.
668 if (dev->bulkEpI < 0 || dev->bulkEpO < 0) {
669 usb_mass_release(dev);
670 M_PRINTF("ERROR: connect failed: not enough bulk endpoints!\n");
671 return -1;
672 }
673
674 SemaData.initial = 0;
675 SemaData.max = 1;
676 SemaData.option = 0;
677 SemaData.attr = 0;
678 if ((dev->ioSema = CreateSema(&SemaData)) < 0) {
679 M_PRINTF("ERROR: Failed to allocate I/O semaphore\n");
680 return -1;
681 }
682
683 /*store current configuration id - can't call set_configuration here */
684 dev->configId = config->bConfigurationValue;
685 dev->status = USBMASS_DEV_STAT_CONN;
686 // Set this last, with a memory barrier, in order to avoid a race condition in usb_mass_update with partially updated data
687 __asm__ __volatile__("" : : : "memory");
688 dev->devId = devId;
689 M_DEBUG("connect ok: epI=%i, epO=%i\n", dev->bulkEpI, dev->bulkEpO);
690
691 SignalSema(usb_mass_update_sema);
692
693 return 0;
694}
695
696static void usb_mass_release(mass_dev *dev)
697{
698 if (dev->bulkEpI >= 0)
699 sceUsbdClosePipe(dev->bulkEpI);
700
701 if (dev->bulkEpO >= 0)
702 sceUsbdClosePipe(dev->bulkEpO);
703
704 dev->bulkEpI = -1;
705 dev->bulkEpO = -1;
706 dev->controlEp = -1;
707 dev->status = 0;
708}
709
710static int usb_mass_disconnect(int devId)
711{
712 mass_dev *dev;
713 dev = usb_mass_findDevice(devId, 0);
714
715 M_PRINTF("disconnect: devId=%i\n", devId);
716
717 if (dev == NULL) {
718 M_PRINTF("ERROR: disconnect: no device storage!\n");
719 return 0;
720 }
721
722 if (dev->status & USBMASS_DEV_STAT_CONN) {
723 usb_mass_release(dev);
724 dev->devId = -1;
725
726 DeleteSema(dev->ioSema);
727
728 // Should this move to the thread
729 // just like the scsi_connect?
730 scsi_disconnect(&dev->scsi);
731 }
732
733 return 0;
734}
735
736static void usb_mass_update(void *arg)
737{
738 int i;
739
740 (void)arg;
741
742 M_DEBUG("update thread running\n");
743
744 while (1) {
745 mass_dev *new_devs[NUM_DEVICES];
746 int new_devs_count;
747
748 // Wait for event from USBD thread
749 WaitSema(usb_mass_update_sema);
750
751 // Determine which devices are new and need to be connected.
752 {
753 new_devs_count = 0;
754 for (i = 0; i < NUM_DEVICES; i += 1) {
755 mass_dev *dev = &g_mass_device[i];
756 if (dev->devId != -1 && (dev->status & USBMASS_DEV_STAT_CONN) && !(dev->status & USBMASS_DEV_STAT_CONF)) {
757 new_devs[new_devs_count] = dev;
758 new_devs_count += 1;
759 }
760 }
761 }
762
763 // Connect new devices
764 for (i = 0; i < new_devs_count; i += 1) {
765 mass_dev *dev = new_devs[i];
766 {
767 int ret;
768 if ((ret = usb_set_configuration(dev, dev->configId)) != USB_RC_OK) {
769 M_PRINTF("ERROR: sending set_configuration %d\n", ret);
770 usb_mass_release(dev);
771 continue;
772 }
773
774 if ((ret = usb_set_interface(dev, dev->interfaceNumber, dev->interfaceAlt)) != USB_RC_OK) {
775 M_PRINTF("ERROR: sending set_interface %d\n", ret);
776 if (ret == USB_RC_STALL) {
777 /* USB Specification 1.1, section 9.4.10: Devices that only support a default setting for the specified interface may return a STALL.
778 As with Linux, we shall clear the halt state of the interface's pipes and continue. */
779 usb_bulk_clear_halt(dev, USB_BLK_EP_IN);
780 usb_bulk_clear_halt(dev, USB_BLK_EP_OUT);
781 } else {
782 usb_mass_release(dev);
783 continue;
784 }
785 }
786
787 dev->status |= USBMASS_DEV_STAT_CONF;
788 scsi_connect(&dev->scsi);
789
790 // This is the same wait amount as done in fat_getData in usbhdfsd.
791 // This is a workaround to avoid incorrect initialization when attaching multiple drives at the same time.
792 DelayThread(5000);
793 }
794 }
795 }
796}
797
798int usb_mass_init(void)
799{
801 iop_sema_t sema;
802 int ret;
803 int i;
804
805 M_DEBUG("%s\n", __func__);
806
807 for (i = 0; i < NUM_DEVICES; ++i) {
808 g_mass_device[i].status = 0;
809 g_mass_device[i].devId = -1;
810
811 g_mass_device[i].scsi.priv = &g_mass_device[i];
812 g_mass_device[i].scsi.name = "usb";
813 // The maximum number of sectors should be 0xffff but
814 // some usb drives seem to freeze above 128 sectors (64Kib)
815 g_mass_device[i].scsi.max_sectors = 128; // 0xffff
816 g_mass_device[i].scsi.get_max_lun = usb_bulk_get_max_lun;
817 g_mass_device[i].scsi.queue_cmd = usb_queue_cmd;
818 }
819
820 sema.attr = 0;
821 sema.option = 0;
822 sema.initial = 0;
823 sema.max = 1;
824 usb_mass_update_sema = CreateSema(&sema);
825
826 driver.next = NULL;
827 driver.prev = NULL;
828 driver.name = "mass-stor";
829 driver.probe = usb_mass_probe;
830 driver.connect = usb_mass_connect;
831 driver.disconnect = usb_mass_disconnect;
832
833 ret = sceUsbdRegisterLdd(&driver);
834 M_DEBUG("sceUsbdRegisterLdd=%i\n", ret);
835 if (ret < 0) {
836 M_PRINTF("ERROR: register driver failed! ret=%d\n", ret);
837 return -1;
838 }
839
840 thread.attr = TH_C;
841 thread.option = 0;
842 thread.thread = usb_mass_update;
843 thread.stacksize = 2 * 1024;
844 thread.priority = 0x10;
845
846 ret = CreateThread(&thread);
847 if (ret < 0) {
848 M_PRINTF("ERROR: CreateThread failed! ret=%d\n", ret);
849 return -1;
850 }
851
852 ret = StartThread(ret, 0);
853 if (ret < 0) {
854 M_PRINTF("ERROR: StartThread failed! ret=%d\n", ret);
855 DeleteThread(ret);
856 return -1;
857 }
858
859 return 0;
860}
#define EIO
Definition errno.h:29
#define USB_RC_STALL
Definition usbd.h:246
#define USB_RC_OK
Definition usbd.h:238
char * name
Definition usbd.h:51
#define USBMASS_DEV_STAT_CONN
#define USBMASS_DEV_STAT_ERR
#define USBMASS_DEV_STAT_CONF