2010-02-22 22:29:47 +01:00
|
|
|
/*-------------------------------------------------------------
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
usbstorage_starlet.c -- USB mass storage support, inside starlet
|
2011-02-05 22:06:52 +01:00
|
|
|
Copyright (C) 2011 Dimok
|
|
|
|
Copyright (C) 2011 Rodries
|
2010-09-24 02:48:03 +02:00
|
|
|
Copyright (C) 2009 Kwiirk
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
If this driver is linked before libogc, this will replace the original
|
|
|
|
usbstorage driver by svpe from libogc
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any
|
|
|
|
damages arising from the use of this software.
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
Permission is granted to anyone to use this software for any
|
|
|
|
purpose, including commercial applications, and to alter it and
|
|
|
|
redistribute it freely, subject to the following restrictions:
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
1. The origin of this software must not be misrepresented; you
|
|
|
|
must not claim that you wrote the original software. If you use
|
|
|
|
this software in a product, an acknowledgment in the product
|
|
|
|
documentation would be appreciated but is not required.
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
2. Altered source versions must be plainly marked as such, and
|
|
|
|
must not be misrepresented as being the original software.
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
3. This notice may not be removed or altered from any source
|
|
|
|
distribution.
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
-------------------------------------------------------------*/
|
2010-02-22 22:29:47 +01:00
|
|
|
|
|
|
|
#include <gccore.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "usbstorage2.h"
|
2010-09-28 22:55:42 +02:00
|
|
|
#include "memory/mem2.h"
|
2011-02-05 22:06:52 +01:00
|
|
|
#include "gecko.h"
|
2010-09-28 22:55:42 +02:00
|
|
|
|
2010-02-22 22:29:47 +01:00
|
|
|
|
|
|
|
/* IOCTL commands */
|
2010-09-19 01:16:05 +02:00
|
|
|
#define UMS_BASE (('U'<<24)|('M'<<16)|('S'<<8))
|
|
|
|
#define USB_IOCTL_UMS_INIT (UMS_BASE+0x1)
|
2010-02-22 22:29:47 +01:00
|
|
|
#define USB_IOCTL_UMS_GET_CAPACITY (UMS_BASE+0x2)
|
|
|
|
#define USB_IOCTL_UMS_READ_SECTORS (UMS_BASE+0x3)
|
2010-09-19 01:16:05 +02:00
|
|
|
#define USB_IOCTL_UMS_WRITE_SECTORS (UMS_BASE+0x4)
|
|
|
|
#define USB_IOCTL_UMS_READ_STRESS (UMS_BASE+0x5)
|
|
|
|
#define USB_IOCTL_UMS_SET_VERBOSE (UMS_BASE+0x6)
|
|
|
|
#define USB_IOCTL_UMS_UMOUNT (UMS_BASE+0x10)
|
|
|
|
#define USB_IOCTL_UMS_WATCHDOG (UMS_BASE+0x80)
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
#define USB_IOCTL_UMS_TESTMODE (UMS_BASE+0x81)
|
2011-02-05 22:06:52 +01:00
|
|
|
#define USB_IOCTL_SET_PORT (UMS_BASE+0x83)
|
2010-02-22 22:29:47 +01:00
|
|
|
|
|
|
|
#define WBFS_BASE (('W'<<24)|('F'<<16)|('S'<<8))
|
2010-09-19 01:16:05 +02:00
|
|
|
#define USB_IOCTL_WBFS_OPEN_DISC (WBFS_BASE+0x1)
|
|
|
|
#define USB_IOCTL_WBFS_READ_DISC (WBFS_BASE+0x2)
|
|
|
|
#define USB_IOCTL_WBFS_SET_DEVICE (WBFS_BASE+0x50)
|
2010-05-29 09:38:54 +02:00
|
|
|
#define USB_IOCTL_WBFS_SET_FRAGLIST (WBFS_BASE+0x51)
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-10-01 17:01:19 +02:00
|
|
|
#define isMEM2Buffer(p) (((u32) p & 0x10000000) != 0)
|
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
#define MAX_SECTOR_SIZE 4096
|
|
|
|
#define MAX_BUFFER_SECTORS 128
|
|
|
|
#define UMS_HEAPSIZE 2*1024
|
2010-10-01 17:01:19 +02:00
|
|
|
|
2010-02-22 22:29:47 +01:00
|
|
|
/* Variables */
|
2010-10-01 17:01:19 +02:00
|
|
|
static char fs[] ATTRIBUTE_ALIGN(32) = "/dev/usb2";
|
|
|
|
static char fs2[] ATTRIBUTE_ALIGN(32) = "/dev/usb123";
|
|
|
|
static char fs3[] ATTRIBUTE_ALIGN(32) = "/dev/usb/ehc";
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-09-28 22:55:42 +02:00
|
|
|
static u8 * mem2_ptr = NULL;
|
2010-02-22 22:29:47 +01:00
|
|
|
static s32 hid = -1, fd = -1;
|
2011-06-22 19:57:37 +02:00
|
|
|
static u32 usb2_port = -1; //current USB port
|
|
|
|
bool hddInUse[2] = { false, false };
|
|
|
|
u32 hdd_sector_size[2] = { 512, 512 };
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
s32 USBStorage2_Init(u32 port)
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2011-06-22 19:57:37 +02:00
|
|
|
if(hddInUse[port])
|
|
|
|
return 0;
|
2010-09-19 01:16:05 +02:00
|
|
|
|
|
|
|
/* Create heap */
|
2010-09-24 02:48:03 +02:00
|
|
|
if (hid < 0)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
hid = iosCreateHeap(UMS_HEAPSIZE);
|
|
|
|
if (hid < 0) return IPC_ENOMEM;
|
2010-09-19 01:16:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Open USB device */
|
2011-06-22 19:57:37 +02:00
|
|
|
if (fd < 0) fd = IOS_Open(fs, 0);
|
2010-09-24 02:48:03 +02:00
|
|
|
if (fd < 0) fd = IOS_Open(fs2, 0);
|
2010-10-01 17:01:19 +02:00
|
|
|
if (fd < 0) fd = IOS_Open(fs3, 0);
|
2010-09-24 02:48:03 +02:00
|
|
|
if (fd < 0) return fd;
|
2010-09-19 01:16:05 +02:00
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
USBStorage2_SetPort(port);
|
2011-02-05 22:06:52 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Initialize USB storage */
|
2011-06-22 19:57:37 +02:00
|
|
|
IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_INIT, ":");
|
2010-09-19 01:16:05 +02:00
|
|
|
|
|
|
|
/* Get device capacity */
|
2011-06-22 19:57:37 +02:00
|
|
|
if (USBStorage2_GetCapacity(port, &hdd_sector_size[port]) == 0)
|
|
|
|
return IPC_ENOENT;
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
hddInUse[port] = true;
|
2010-02-25 13:08:03 +01:00
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
return 0; // 0->HDD, 1->DVD
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
void USBStorage2_Deinit()
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Close USB device */
|
2010-09-24 02:48:03 +02:00
|
|
|
if (fd >= 0)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2011-06-22 19:57:37 +02:00
|
|
|
IOS_Close(fd); // not sure to close the fd is needed
|
2010-09-19 01:16:05 +02:00
|
|
|
fd = -1;
|
|
|
|
}
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2011-02-05 22:06:52 +01:00
|
|
|
s32 USBStorage2_SetPort(u32 port)
|
|
|
|
{
|
2011-02-06 10:34:06 +01:00
|
|
|
//! Port = 2 is handle in the loader, no need to handle it in cIOS
|
2011-02-06 19:36:32 +01:00
|
|
|
if(port > 1)
|
2011-02-05 22:06:52 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if(port == usb2_port)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
s32 ret = -1;
|
|
|
|
usb2_port = port;
|
|
|
|
|
|
|
|
gprintf("Changing USB port to port %i....\n", port);
|
|
|
|
//must be called before USBStorage2_Init (default port 0)
|
|
|
|
if (fd >= 0)
|
|
|
|
ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_SET_PORT, "i:", usb2_port);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 USBStorage2_GetPort()
|
|
|
|
{
|
|
|
|
return usb2_port;
|
|
|
|
}
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
s32 USBStorage2_GetCapacity(u32 port, u32 *_sector_size)
|
2010-09-28 22:55:42 +02:00
|
|
|
{
|
|
|
|
if (fd >= 0)
|
|
|
|
{
|
|
|
|
s32 ret;
|
2011-06-22 19:57:37 +02:00
|
|
|
u32 sector_size = 0;
|
|
|
|
USBStorage2_SetPort(port);
|
2010-09-28 22:55:42 +02:00
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_GET_CAPACITY, ":i", §or_size);
|
2010-09-28 22:55:42 +02:00
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
if (ret && _sector_size) *_sector_size = sector_size;
|
2010-09-28 22:55:42 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return IPC_ENOENT;
|
|
|
|
}
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
s32 USBStorage2_ReadSectors(u32 port, u32 sector, u32 numSectors, void *buffer)
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2010-09-28 22:55:42 +02:00
|
|
|
u8 *buf = (u8 *) buffer;
|
|
|
|
s32 ret = -1;
|
2010-09-19 01:16:05 +02:00
|
|
|
|
|
|
|
/* Device not opened */
|
2010-09-24 02:48:03 +02:00
|
|
|
if (fd < 0) return fd;
|
2010-09-28 22:55:42 +02:00
|
|
|
|
|
|
|
if (!mem2_ptr)
|
2011-06-22 19:57:37 +02:00
|
|
|
mem2_ptr = (u8 *) MEM2_alloc(MAX_SECTOR_SIZE * MAX_BUFFER_SECTORS);
|
|
|
|
|
|
|
|
USBStorage2_SetPort(port);
|
2010-09-28 22:55:42 +02:00
|
|
|
|
2010-12-05 20:09:32 +01:00
|
|
|
s32 read_secs, read_size;
|
|
|
|
|
|
|
|
while(numSectors > 0)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-12-05 20:09:32 +01:00
|
|
|
read_secs = numSectors > MAX_BUFFER_SECTORS ? MAX_BUFFER_SECTORS : numSectors;
|
2011-06-22 19:57:37 +02:00
|
|
|
read_size = read_secs*hdd_sector_size[port];
|
2010-09-19 01:16:05 +02:00
|
|
|
|
2010-12-05 20:09:32 +01:00
|
|
|
// Do not read more than MAX_BUFFER_SECTORS sectors at once and create a mem overflow!
|
|
|
|
if (!isMEM2Buffer(buffer))
|
2010-09-28 22:55:42 +02:00
|
|
|
{
|
2010-12-05 20:09:32 +01:00
|
|
|
ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", sector, read_secs, mem2_ptr, read_size);
|
2010-09-28 22:55:42 +02:00
|
|
|
if(ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2010-12-05 20:09:32 +01:00
|
|
|
memcpy(buf, mem2_ptr, read_size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Read data */
|
|
|
|
ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", sector, read_secs, buf, read_size);
|
|
|
|
if(ret < 0)
|
|
|
|
return ret;
|
2010-09-28 22:55:42 +02:00
|
|
|
}
|
2010-09-19 01:16:05 +02:00
|
|
|
|
2010-12-05 20:09:32 +01:00
|
|
|
sector += read_secs;
|
|
|
|
numSectors -= read_secs;
|
|
|
|
buf += read_size;
|
|
|
|
}
|
2010-09-28 22:55:42 +02:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
return ret;
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
s32 USBStorage2_WriteSectors(u32 port, u32 sector, u32 numSectors, const void *buffer)
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2010-09-28 22:55:42 +02:00
|
|
|
u8 *buf = (u8 *) buffer;
|
|
|
|
s32 ret = -1;
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Device not opened */
|
2010-09-24 02:48:03 +02:00
|
|
|
if (fd < 0) return fd;
|
2010-09-28 22:55:42 +02:00
|
|
|
|
|
|
|
/* Device not opened */
|
|
|
|
if (!mem2_ptr)
|
2011-06-22 19:57:37 +02:00
|
|
|
mem2_ptr = (u8 *) MEM2_alloc(MAX_SECTOR_SIZE * MAX_BUFFER_SECTORS);
|
|
|
|
|
|
|
|
USBStorage2_SetPort(port);
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-12-05 20:09:32 +01:00
|
|
|
s32 write_size, write_secs;
|
|
|
|
|
|
|
|
while(numSectors > 0)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-12-05 20:09:32 +01:00
|
|
|
write_secs = numSectors > MAX_BUFFER_SECTORS ? MAX_BUFFER_SECTORS : numSectors;
|
2011-06-22 19:57:37 +02:00
|
|
|
write_size = write_secs*hdd_sector_size[port];
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-12-05 20:09:32 +01:00
|
|
|
/* MEM1 buffer */
|
|
|
|
if (!isMEM2Buffer(buffer))
|
2010-09-28 22:55:42 +02:00
|
|
|
{
|
2010-12-05 20:09:32 +01:00
|
|
|
// Do not read more than MAX_BUFFER_SECTORS sectors at once and create a mem overflow!
|
|
|
|
memcpy(mem2_ptr, buf, write_size);
|
2010-02-22 22:29:47 +01:00
|
|
|
|
2010-12-05 20:09:32 +01:00
|
|
|
ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WRITE_SECTORS, "ii:d", sector, write_secs, mem2_ptr, write_size);
|
2010-09-28 22:55:42 +02:00
|
|
|
if(ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
2010-12-05 20:09:32 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Write data */
|
|
|
|
ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WRITE_SECTORS, "ii:d", sector, write_secs, buf, write_size);
|
|
|
|
if(ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
sector += write_secs;
|
|
|
|
numSectors -= write_secs;
|
|
|
|
buf += write_size;
|
2010-09-28 22:55:42 +02:00
|
|
|
}
|
2010-02-25 15:55:42 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
return ret;
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
static bool __usbstorage_Startup(void)
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2011-06-22 19:57:37 +02:00
|
|
|
return USBStorage2_Init(0) >= 0;
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
static bool __usbstorage_IsInserted(void)
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2011-06-22 19:57:37 +02:00
|
|
|
return (USBStorage2_GetCapacity(0, NULL) != 0);
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
static bool __usbstorage_ReadSectors(u32 sector, u32 numSectors, void *buffer)
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2011-06-22 19:57:37 +02:00
|
|
|
return (USBStorage2_ReadSectors(0, sector, numSectors, buffer) >= 0);
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
static bool __usbstorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer)
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2011-06-22 19:57:37 +02:00
|
|
|
return (USBStorage2_WriteSectors(0, sector, numSectors, buffer) >= 0);
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
static bool __usbstorage_ClearStatus(void)
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
return true;
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
static bool __usbstorage_Shutdown(void)
|
2010-02-22 22:29:47 +01:00
|
|
|
{
|
2011-06-22 19:57:37 +02:00
|
|
|
hddInUse[0] = false;
|
|
|
|
hdd_sector_size[0] = 512;
|
2010-09-19 01:16:05 +02:00
|
|
|
return true;
|
2010-02-22 22:29:47 +01:00
|
|
|
}
|
|
|
|
|
2011-06-22 19:57:37 +02:00
|
|
|
const DISC_INTERFACE __io_usbstorage2_port0 = {
|
2010-09-28 22:55:42 +02:00
|
|
|
DEVICE_TYPE_WII_UMS, FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB,
|
|
|
|
(FN_MEDIUM_STARTUP) &__usbstorage_Startup,
|
|
|
|
(FN_MEDIUM_ISINSERTED) &__usbstorage_IsInserted,
|
|
|
|
(FN_MEDIUM_READSECTORS) &__usbstorage_ReadSectors,
|
|
|
|
(FN_MEDIUM_WRITESECTORS) &__usbstorage_WriteSectors,
|
|
|
|
(FN_MEDIUM_CLEARSTATUS) &__usbstorage_ClearStatus,
|
|
|
|
(FN_MEDIUM_SHUTDOWN) &__usbstorage_Shutdown
|
|
|
|
};
|
2011-06-22 19:57:37 +02:00
|
|
|
|
|
|
|
static bool __usbstorage_Startup2(void)
|
|
|
|
{
|
|
|
|
return USBStorage2_Init(1) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool __usbstorage_IsInserted2(void)
|
|
|
|
{
|
|
|
|
return (USBStorage2_GetCapacity(1, NULL) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool __usbstorage_ReadSectors2(u32 sector, u32 numSectors, void *buffer)
|
|
|
|
{
|
|
|
|
return (USBStorage2_ReadSectors(1, sector, numSectors, buffer) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool __usbstorage_WriteSectors2(u32 sector, u32 numSectors, const void *buffer)
|
|
|
|
{
|
|
|
|
return (USBStorage2_WriteSectors(1, sector, numSectors, buffer) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool __usbstorage_Shutdown2(void)
|
|
|
|
{
|
|
|
|
hddInUse[1] = false;
|
|
|
|
hdd_sector_size[1] = 512;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const DISC_INTERFACE __io_usbstorage2_port1 = {
|
|
|
|
DEVICE_TYPE_WII_UMS, FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB,
|
|
|
|
(FN_MEDIUM_STARTUP) &__usbstorage_Startup2,
|
|
|
|
(FN_MEDIUM_ISINSERTED) &__usbstorage_IsInserted2,
|
|
|
|
(FN_MEDIUM_READSECTORS) &__usbstorage_ReadSectors2,
|
|
|
|
(FN_MEDIUM_WRITESECTORS) &__usbstorage_WriteSectors2,
|
|
|
|
(FN_MEDIUM_CLEARSTATUS) &__usbstorage_ClearStatus,
|
|
|
|
(FN_MEDIUM_SHUTDOWN) &__usbstorage_Shutdown2
|
|
|
|
};
|