usb:adding usb mass storage driver.
Change-Id: I9e431d56eddfeec21413c290b2fa7ad35b566f6b http://gerrit.minix3.org/#/c/2690/
This commit is contained in:
parent
ed3391fd23
commit
dfb2b8398d
12 changed files with 2308 additions and 0 deletions
20
drivers/usb_storage/Makefile
Executable file
20
drivers/usb_storage/Makefile
Executable file
|
@ -0,0 +1,20 @@
|
|||
# Makefile for Mass Storage driver
|
||||
PROG= usb_storage
|
||||
SRCS= urb_helper.c bulk.c scsi.c usb_storage.c
|
||||
|
||||
FILES= $(PROG).conf
|
||||
FILESNAME= $(PROG)
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
DPADD+= ${LIBBLOCKDRIVER} ${LIBDDEKIT_USB_CLIENT} ${LIBSYS} ${LIBMINLIB} ${LIBDDEKIT} ${LIBUSB}
|
||||
LDADD+= -lblockdriver -lddekit_usb_client -lsys -lminlib -lddekit -lusb
|
||||
|
||||
#For easier debugging, uncomment:
|
||||
#LDADD+= -Wl,-Ttext=0x800000
|
||||
#CPPFLAGS+= -DMASS_DEBUG
|
||||
|
||||
MAN=
|
||||
|
||||
BINDIR?= /usr/sbin
|
||||
|
||||
.include <minix.service.mk>
|
27
drivers/usb_storage/README.txt
Executable file
27
drivers/usb_storage/README.txt
Executable file
|
@ -0,0 +1,27 @@
|
|||
-------------------------------------------------------------------------------
|
||||
* INFORMATION: *
|
||||
-------------------------------------------------------------------------------
|
||||
README file for "USB Mass Storage driver" that uses DDEkit and libblockdriver.
|
||||
|
||||
created march-april 2014, JPEmbedded (info@jpembedded.eu)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
* KNOWN LIMITATIONS: *
|
||||
-------------------------------------------------------------------------------
|
||||
-Hardcoded interface number for bulk-only reset.
|
||||
-Hardcoded configuration number for simple enumeration.
|
||||
-Call to ddekit_minix_create_msg_q in _ddekit_usb_thread uses base that
|
||||
overlaps that of blockdriver's (in mass_storage_task) so initialization
|
||||
must be done in fixed order.
|
||||
-Some of DDEKit's functions are declared in source files as they are missing
|
||||
from headers.
|
||||
-DDEKit has 'init' but no 'deinit' call, so memory is spilled.
|
||||
-Hardcoded geometry.
|
||||
-LUN always set to 0.
|
||||
-SIGTERM handler uses exit instead of DDEkit semaphores.
|
||||
-mass_storage.conf taken from dde-linux26-usb-drivers.
|
||||
-Subpartitioning does not seem to work.
|
||||
-Type ddekit_usb_dev is not defined in any header file but two variants of it
|
||||
should exist (client and server).
|
||||
-Magic number in URB setup buffer assignment as there is no header for that
|
||||
(like usb_ch9.h for descriptors).
|
39
drivers/usb_storage/bulk.c
Executable file
39
drivers/usb_storage/bulk.c
Executable file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* "Bulk only transfer" related implementation
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h> /* memset */
|
||||
|
||||
#include "common.h"
|
||||
#include "bulk.h"
|
||||
|
||||
/*===========================================================================*
|
||||
* init_cbw *
|
||||
*===========================================================================*/
|
||||
void
|
||||
init_cbw(mass_storage_cbw * cbw, unsigned int tag)
|
||||
{
|
||||
assert(NULL != cbw);
|
||||
|
||||
/* Clearing "Command Block Wrapper" */
|
||||
memset(cbw, 0, sizeof(*cbw));
|
||||
|
||||
/* Filling Command Block Wrapper */
|
||||
cbw->dCBWSignature = CBW_SIGNATURE;
|
||||
cbw->dCBWTag = tag;
|
||||
cbw->bCBWLUN = 0;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* init_csw *
|
||||
*===========================================================================*/
|
||||
void
|
||||
init_csw(mass_storage_csw * csw)
|
||||
{
|
||||
assert(NULL != csw);
|
||||
|
||||
/* Clearing "Command Status Wrapper" so we can receive data into it */
|
||||
memset(csw, 0, sizeof(*csw));
|
||||
}
|
52
drivers/usb_storage/bulk.h
Executable file
52
drivers/usb_storage/bulk.h
Executable file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* "Bulk only transfer" related externally visible info
|
||||
*/
|
||||
|
||||
#ifndef _BULK_H_
|
||||
#define _BULK_H_
|
||||
|
||||
/*---------------------------*
|
||||
* declared types *
|
||||
*---------------------------*/
|
||||
#define BULK_PACKED __attribute__((__packed__))
|
||||
|
||||
#define CBW_SIGNATURE (0x43425355)
|
||||
#define CBW_FLAGS_OUT (0x00)
|
||||
#define CBW_FLAGS_IN (0x80)
|
||||
#define CBW_CB_LENGTH (16)
|
||||
|
||||
/* Command Block Wrapper */
|
||||
typedef struct BULK_PACKED mass_storage_cbw {
|
||||
uint32_t dCBWSignature;
|
||||
uint32_t dCBWTag;
|
||||
uint32_t dCBWDataTransferLength;
|
||||
uint8_t bCBWFlags;
|
||||
uint8_t bCBWLUN; /* 4 bits */
|
||||
uint8_t bCDBLength; /* 5 bits */
|
||||
uint8_t CBWCB[CBW_CB_LENGTH];
|
||||
}
|
||||
mass_storage_cbw;
|
||||
|
||||
#define CSW_SIGNATURE (0x53425355)
|
||||
#define CSW_STATUS_GOOD (0x0)
|
||||
#define CSWS_TATUS_FAILED (0x1)
|
||||
#define CSW_STATUS_PHASE (0x2)
|
||||
|
||||
/* Command Status Wrapper */
|
||||
typedef struct BULK_PACKED mass_storage_csw {
|
||||
uint32_t dCSWSignature;
|
||||
uint32_t dCSWTag;
|
||||
uint32_t dCSWDataResidue;
|
||||
uint8_t bCSWStatus;
|
||||
}
|
||||
mass_storage_csw;
|
||||
|
||||
#undef BULK_PACKED
|
||||
|
||||
/*---------------------------*
|
||||
* declared functions *
|
||||
*---------------------------*/
|
||||
void init_cbw(mass_storage_cbw *, unsigned int);
|
||||
void init_csw(mass_storage_csw *);
|
||||
|
||||
#endif /* !_BULK_H_ */
|
35
drivers/usb_storage/common.h
Executable file
35
drivers/usb_storage/common.h
Executable file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Whatever is commonly used in mass_storage driver, should be here
|
||||
*/
|
||||
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
/*---------------------------*
|
||||
* commonly used headers: *
|
||||
*---------------------------*/
|
||||
#include <stdlib.h> /* For things, like EXIT_*, NULL, ... */
|
||||
#include <stdio.h>
|
||||
|
||||
/*---------------------------*
|
||||
* commonly used defines: *
|
||||
*---------------------------*/
|
||||
#define THIS_EXEC_NAME "usb_storage"
|
||||
#define MASS_MSG(...) do { \
|
||||
printf(THIS_EXEC_NAME": "); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("; %s:%d\n", __func__, __LINE__); \
|
||||
} while(0)
|
||||
|
||||
/*---------------------------*
|
||||
* debug helpers: *
|
||||
*---------------------------*/
|
||||
#ifdef MASS_DEBUG
|
||||
#define MASS_DEBUG_MSG MASS_MSG
|
||||
#define MASS_DEBUG_DUMP printf("%s():%d\n", __func__, __LINE__)
|
||||
#else
|
||||
#define MASS_DEBUG_MSG(...)
|
||||
#define MASS_DEBUG_DUMP
|
||||
#endif
|
||||
|
||||
#endif /* !_COMMON_H_ */
|
266
drivers/usb_storage/scsi.c
Executable file
266
drivers/usb_storage/scsi.c
Executable file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* SCSI commands related implementation
|
||||
*/
|
||||
|
||||
#include <minix/blockdriver.h> /* SECTOR_SIZE */
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h> /* strncpy */
|
||||
|
||||
#include "common.h"
|
||||
#include "scsi.h"
|
||||
|
||||
/*---------------------------*
|
||||
* declared functions *
|
||||
*---------------------------*/
|
||||
/* To work correctly cbw->CBWCB must be zeroed before calling these: */
|
||||
static int create_inquiry_scsi_cmd(mass_storage_cbw *);
|
||||
static int create_test_scsi_cmd(mass_storage_cbw *);
|
||||
static int create_read_capacity_scsi_cmd(mass_storage_cbw *);
|
||||
static int create_write_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
|
||||
static int create_read_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
|
||||
static int create_mode_sense_scsi_cmd(mass_storage_cbw *);
|
||||
|
||||
/*---------------------------*
|
||||
* defined functions *
|
||||
*---------------------------*/
|
||||
/*===========================================================================*
|
||||
* create_scsi_cmd *
|
||||
*===========================================================================*/
|
||||
int
|
||||
create_scsi_cmd(mass_storage_cbw * cbw, int cmd, scsi_transfer * info)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
assert(NULL != cbw);
|
||||
|
||||
switch (cmd) {
|
||||
case SCSI_INQUIRY:
|
||||
return create_inquiry_scsi_cmd(cbw);
|
||||
case SCSI_TEST_UNIT_READY:
|
||||
return create_test_scsi_cmd(cbw);
|
||||
case SCSI_READ_CAPACITY:
|
||||
return create_read_capacity_scsi_cmd(cbw);
|
||||
case SCSI_WRITE:
|
||||
return create_write_scsi_cmd(cbw, info);
|
||||
case SCSI_READ:
|
||||
return create_read_scsi_cmd(cbw, info);
|
||||
case SCSI_MODE_SENSE:
|
||||
return create_mode_sense_scsi_cmd(cbw);
|
||||
default:
|
||||
MASS_MSG("Invalid SCSI command!");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* create_inquiry_scsi_cmd *
|
||||
*===========================================================================*/
|
||||
static int
|
||||
create_inquiry_scsi_cmd(mass_storage_cbw * cbw)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
cbw->dCBWDataTransferLength = SCSI_INQUIRY_DATA_LEN;
|
||||
cbw->bCBWFlags = CBW_FLAGS_IN;
|
||||
cbw->bCDBLength = SCSI_INQUIRY_CMD_LEN;
|
||||
|
||||
SCSI_SET_INQUIRY_OP_CODE(cbw->CBWCB);
|
||||
SCSI_SET_INQUIRY_PAGE_CODE(cbw->CBWCB, 0);
|
||||
SCSI_SET_INQUIRY_ALLOC_LEN(cbw->CBWCB, SCSI_INQUIRY_DATA_LEN);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* create_test_scsi_cmd *
|
||||
*===========================================================================*/
|
||||
static int
|
||||
create_test_scsi_cmd(mass_storage_cbw * cbw)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
cbw->bCDBLength = SCSI_TEST_CMD_LEN;
|
||||
|
||||
SCSI_SET_TEST_OP_CODE(cbw->CBWCB);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* create_read_capacity_scsi_cmd *
|
||||
*===========================================================================*/
|
||||
static int
|
||||
create_read_capacity_scsi_cmd(mass_storage_cbw * cbw)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
cbw->dCBWDataTransferLength = SCSI_READ_CAPACITY_DATA_LEN;
|
||||
cbw->bCBWFlags = CBW_FLAGS_IN;
|
||||
cbw->bCDBLength = SCSI_READ_CAPACITY_CMD_LEN;
|
||||
|
||||
SCSI_SET_READ_CAPACITY_OP_CODE(cbw->CBWCB);
|
||||
SCSI_SET_READ_CAPACITY_LBA(cbw->CBWCB, 0x00);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* create_write_scsi_cmd *
|
||||
*===========================================================================*/
|
||||
static int
|
||||
create_write_scsi_cmd(mass_storage_cbw * cbw, scsi_transfer * info)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
assert(NULL != info);
|
||||
assert(0 == (info->length % SECTOR_SIZE));
|
||||
|
||||
cbw->dCBWDataTransferLength = info->length;
|
||||
cbw->bCBWFlags = CBW_FLAGS_OUT;
|
||||
cbw->bCDBLength = SCSI_WRITE_CMD_LEN;
|
||||
|
||||
SCSI_SET_WRITE_OP_CODE(cbw->CBWCB);
|
||||
SCSI_SET_WRITE_LBA(cbw->CBWCB, info->lba);
|
||||
SCSI_SET_WRITE_BLEN(cbw->CBWCB, info->length / SECTOR_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* create_read_scsi_cmd *
|
||||
*===========================================================================*/
|
||||
static int
|
||||
create_read_scsi_cmd(mass_storage_cbw * cbw, scsi_transfer * info)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
assert(NULL != info);
|
||||
assert(0 == (info->length % SECTOR_SIZE));
|
||||
|
||||
cbw->dCBWDataTransferLength = info->length;
|
||||
cbw->bCBWFlags = CBW_FLAGS_IN;
|
||||
cbw->bCDBLength = SCSI_READ_CMD_LEN;
|
||||
|
||||
SCSI_SET_READ_OP_CODE(cbw->CBWCB);
|
||||
SCSI_SET_READ_LBA(cbw->CBWCB, info->lba);
|
||||
SCSI_SET_READ_BLEN(cbw->CBWCB, info->length / SECTOR_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* create_mode_sense_scsi_cmd *
|
||||
*===========================================================================*/
|
||||
static int
|
||||
create_mode_sense_scsi_cmd(mass_storage_cbw * cbw)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
cbw->dCBWDataTransferLength = SCSI_MODE_SENSE_FLEX_DATA_LEN;
|
||||
cbw->bCBWFlags = CBW_FLAGS_IN;
|
||||
cbw->bCDBLength = SCSI_MODE_SENSE_CMD_LEN;
|
||||
|
||||
SCSI_SET_MODE_SENSE_OP_CODE(cbw->CBWCB);
|
||||
SCSI_SET_MODE_SENSE_PAGE_CODE(cbw->CBWCB,
|
||||
SCSI_MODE_SENSE_FLEXIBLE_DISK_PAGE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* check_inquiry_reply *
|
||||
*===========================================================================*/
|
||||
int
|
||||
check_inquiry_reply(uint8_t * scsi_reply)
|
||||
{
|
||||
char vendor_name[SCSI_INQUIRY_VENDOR_NAME_LEN + 1];
|
||||
char product_name[SCSI_INQUIRY_PRODUCT_NAME_LEN + 1];
|
||||
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
/* Stop condition for printing as strncpy() does not add it */
|
||||
vendor_name[SCSI_INQUIRY_VENDOR_NAME_LEN] = '\0';
|
||||
product_name[SCSI_INQUIRY_PRODUCT_NAME_LEN] = '\0';
|
||||
|
||||
if (SCSI_GET_INQUIRY_PERIPH_QUALIF(scsi_reply)) {
|
||||
MASS_MSG("Device not connected");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
strncpy(vendor_name, SCSI_GET_INQUIRY_VENDOR_NAME(scsi_reply),
|
||||
SCSI_INQUIRY_VENDOR_NAME_LEN);
|
||||
strncpy(product_name, SCSI_GET_INQUIRY_PRODUCT_NAME(scsi_reply),
|
||||
SCSI_INQUIRY_PRODUCT_NAME_LEN);
|
||||
|
||||
MASS_DEBUG_MSG("Vendor name: %s", vendor_name);
|
||||
MASS_DEBUG_MSG("Product name %s", product_name);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* check_read_capacity_reply *
|
||||
*===========================================================================*/
|
||||
int
|
||||
check_read_capacity_reply(uint8_t * scsi_reply, uint32_t * lba, uint32_t * blen)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
*lba = SCSI_GET_READ_CAPACITY_LBA(scsi_reply);
|
||||
*blen = SCSI_GET_READ_CAPACITY_BLEN(scsi_reply);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* check_mode_sense_reply *
|
||||
*===========================================================================*/
|
||||
int
|
||||
check_mode_sense_reply(uint8_t * scsi_reply, unsigned * cyl,
|
||||
unsigned * head, unsigned * sect)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
*cyl = SCSI_GET_MODE_SENSE_CYLINDERS(scsi_reply);
|
||||
*head = SCSI_GET_MODE_SENSE_HEADS(scsi_reply);
|
||||
*sect = SCSI_GET_MODE_SENSE_SECTORS(scsi_reply);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* check_csw *
|
||||
*===========================================================================*/
|
||||
int
|
||||
check_csw(mass_storage_csw * csw, unsigned int tag)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
if (csw->dCSWTag != tag) {
|
||||
MASS_MSG("CSW tag mismatch!");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (CSW_SIGNATURE != csw->dCSWSignature) {
|
||||
MASS_MSG("CSW signature mismatch!");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (CSW_STATUS_GOOD != csw->bCSWStatus) {
|
||||
MASS_MSG("CSW status error!");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
143
drivers/usb_storage/scsi.h
Executable file
143
drivers/usb_storage/scsi.h
Executable file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* SCSI commands related definitions
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_H_
|
||||
#define _SCSI_H_
|
||||
|
||||
#if 0
|
||||
#include <sys/endian.h> /* be16dec... */
|
||||
#else
|
||||
#define be16enc(base, val) { \
|
||||
(base)[0] = (((val) >> 8) & 0xff); \
|
||||
(base)[1] = ((val) & 0xff); \
|
||||
}
|
||||
#define be16dec(base) \
|
||||
(((base)[0] << 8) | (base)[1])
|
||||
#define be32enc(base, val) { \
|
||||
(base)[0] = (((val) >> 24) & 0xff); \
|
||||
(base)[1] = (((val) >> 16) & 0xff); \
|
||||
(base)[2] = (((val) >> 8) & 0xff); \
|
||||
(base)[3] = ((val) & 0xff); \
|
||||
}
|
||||
#define be32dec(base) \
|
||||
(((base)[0] << 24) | ((base)[1] << 16) | \
|
||||
((base)[2] << 8) | (base)[3])
|
||||
#endif
|
||||
|
||||
#include "bulk.h"
|
||||
|
||||
#define SCSI_FORMAT_UNIT (0x04)
|
||||
#define SCSI_INQUIRY (0x12)
|
||||
#define SCSI_START_STOP (0x1B)
|
||||
#define SCSI_MODE_SELECT (0x55)
|
||||
#define SCSI_MODE_SENSE (0x5A)
|
||||
#define SCSI_PREVENT_ALLOW (0x1E)
|
||||
#define SCSI_READ (0x28)
|
||||
#define SCSI_READ_12 (0xA8)
|
||||
#define SCSI_READ_CAPACITY (0x25)
|
||||
#define SCSI_READ_FORMAT_CAP (0x23)
|
||||
#define SCSI_REQUEST_SENSE (0x03)
|
||||
#define SCSI_REZERO_UNIT (0x01)
|
||||
#define SCSI_SEEK (0x2B)
|
||||
#define SCSI_SEND_DIAGNOSTIC (0x1D)
|
||||
#define SCSI_TEST_UNIT_READY (0x00)
|
||||
#define SCSI_VERIFY (0x2F)
|
||||
#define SCSI_WRITE (0x2A)
|
||||
#define SCSI_WRITE_12 (0xAA)
|
||||
#define SCSI_WRITE_VERIFY (0x2E)
|
||||
|
||||
#define SCSI_INQUIRY_DATA_LEN (36)
|
||||
#define SCSI_INQUIRY_CMD_LEN (6)
|
||||
|
||||
#define SCSI_MODE_SENSE_FLEX_DATA_LEN (32)
|
||||
#define SCSI_MODE_SENSE_CMD_LEN (12)
|
||||
|
||||
#define SCSI_READ_DATA_LEN (0)
|
||||
#define SCSI_READ_CMD_LEN (10)
|
||||
|
||||
#define SCSI_READ_CAPACITY_DATA_LEN (8)
|
||||
#define SCSI_READ_CAPACITY_CMD_LEN (10)
|
||||
|
||||
#define SCSI_TEST_DATA_LEN (0)
|
||||
#define SCSI_TEST_CMD_LEN (6)
|
||||
|
||||
#define SCSI_WRITE_DATA_LEN (0)
|
||||
#define SCSI_WRITE_CMD_LEN (10)
|
||||
|
||||
/* These macros are immune to unaligned access
|
||||
* so they can be used on any address */
|
||||
/* 1 Byte SCSI operation */
|
||||
#define SCSI_WR1(base, offset, value)\
|
||||
(((uint8_t*)(base))[offset] = value)
|
||||
#define SCSI_RD1(base, offset)\
|
||||
(((uint8_t*)(base))[offset])
|
||||
#define SCSI_SET1(base, offset, value)\
|
||||
(((uint8_t*)(base))[offset] |= value)
|
||||
/* 2 Byte SCSI operation */
|
||||
#define SCSI_WR2(base, offset, value)\
|
||||
be16enc( &(((uint8_t*)(base))[offset]), value )
|
||||
#define SCSI_RD2(base, offset)\
|
||||
be16dec( &(((uint8_t*)(base))[offset]) )
|
||||
/* 4 Byte SCSI operation */
|
||||
#define SCSI_WR4(base, offset, value)\
|
||||
be32enc( &(((uint8_t*)(base))[offset]), value )
|
||||
#define SCSI_RD4(base, offset)\
|
||||
be32dec( &(((uint8_t*)(base))[offset]) )
|
||||
|
||||
#define SCSI_SET_INQUIRY_OP_CODE(x) SCSI_WR1((x), 0, SCSI_INQUIRY)
|
||||
#define SCSI_SET_INQUIRY_EVPD(x) SCSI_SET1((x), 1, 0x01)
|
||||
#define SCSI_SET_INQUIRY_CMDDT(x) SCSI_SET1((x), 1, 0x02)
|
||||
#define SCSI_SET_INQUIRY_PAGE_CODE(x, code) SCSI_WR1((x), 2, code)
|
||||
#define SCSI_SET_INQUIRY_ALLOC_LEN(x, len) SCSI_WR1((x), 4, len)
|
||||
|
||||
#define SCSI_GET_INQUIRY_PERIPH_QUALIF(x) ((SCSI_RD1(x, 0) >> 5) & 0x7)
|
||||
#define SCSI_GET_INQUIRY_VENDOR_NAME(x) ((const char *)(&((x)[8])))
|
||||
#define SCSI_INQUIRY_VENDOR_NAME_LEN (8)
|
||||
#define SCSI_GET_INQUIRY_PRODUCT_NAME(x) ((const char *)(&((x)[16])))
|
||||
#define SCSI_INQUIRY_PRODUCT_NAME_LEN (16)
|
||||
|
||||
#define SCSI_MODE_SENSE_FLEXIBLE_DISK_PAGE (0x5)
|
||||
#define SCSI_SET_MODE_SENSE_OP_CODE(x) SCSI_WR1((x), 0, \
|
||||
SCSI_MODE_SENSE)
|
||||
#define SCSI_SET_MODE_SENSE_PAGE_CODE(x, code) SCSI_SET1((x), 2, \
|
||||
(code)&0x3F)
|
||||
#define SCSI_GET_MODE_SENSE_CYLINDERS(x) SCSI_RD2((x), 8)
|
||||
#define SCSI_GET_MODE_SENSE_HEADS(x) SCSI_RD1((x), 4)
|
||||
#define SCSI_GET_MODE_SENSE_SECTORS(x) SCSI_RD1((x), 5)
|
||||
|
||||
#define SCSI_SET_READ_OP_CODE(x) SCSI_WR1((x), 0, SCSI_READ)
|
||||
#define SCSI_SET_READ_LBA(x, lba) SCSI_WR4((x), 2, (lba))
|
||||
#define SCSI_SET_READ_BLEN(x, len) SCSI_WR2((x), 7, (len))
|
||||
|
||||
#define SCSI_SET_READ_CAPACITY_OP_CODE(x) SCSI_WR1((x), 0, \
|
||||
SCSI_READ_CAPACITY)
|
||||
#define SCSI_SET_READ_CAPACITY_LBA(x, lba) SCSI_WR4((x), 2, (lba))
|
||||
#define SCSI_SET_READ_CAPACITY_PMI(x) SCSI_SET1((x), 8, 0x01)
|
||||
#define SCSI_GET_READ_CAPACITY_LBA(x) SCSI_RD4((x), 0)
|
||||
#define SCSI_GET_READ_CAPACITY_BLEN(x) SCSI_RD4((x), 4)
|
||||
|
||||
#define SCSI_SET_TEST_OP_CODE(x) SCSI_WR1((x), 0, \
|
||||
SCSI_TEST_UNIT_READY)
|
||||
|
||||
#define SCSI_SET_WRITE_OP_CODE(x) SCSI_WR1((x), 0, SCSI_WRITE)
|
||||
#define SCSI_SET_WRITE_LBA(x, lba) SCSI_WR4((x), 2, (lba))
|
||||
#define SCSI_SET_WRITE_BLEN(x, len) SCSI_WR2((x), 7, (len))
|
||||
|
||||
typedef struct scsi_transfer {
|
||||
|
||||
unsigned int lba; /* logical block address */
|
||||
unsigned int length; /* transfer length */
|
||||
}
|
||||
scsi_transfer;
|
||||
|
||||
/*---------------------------*
|
||||
* declared functions *
|
||||
*---------------------------*/
|
||||
int create_scsi_cmd(mass_storage_cbw *, int, struct scsi_transfer *);
|
||||
int check_inquiry_reply(uint8_t *);
|
||||
int check_read_capacity_reply(uint8_t *, uint32_t *, uint32_t *);
|
||||
int check_mode_sense_reply(uint8_t *, unsigned *, unsigned *, unsigned *);
|
||||
int check_csw(mass_storage_csw *, unsigned int);
|
||||
|
||||
#endif /* !_SCSI_H_ */
|
112
drivers/usb_storage/urb_helper.c
Executable file
112
drivers/usb_storage/urb_helper.c
Executable file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* URB formatting related implementation
|
||||
*/
|
||||
|
||||
#include <minix/sysutil.h> /* panic */
|
||||
#include <minix/usb.h> /* struct usb_ctrlrequest */
|
||||
|
||||
#include <string.h> /* memset */
|
||||
#include <assert.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "urb_helper.h"
|
||||
|
||||
/*---------------------------*
|
||||
* defined functions *
|
||||
*---------------------------*/
|
||||
/*===========================================================================*
|
||||
* init_urb *
|
||||
*===========================================================================*/
|
||||
void
|
||||
init_urb(struct ddekit_usb_urb * urb, struct ddekit_usb_dev * dev,
|
||||
ddekit_int32_t urb_type, ddekit_int32_t urb_endpoint,
|
||||
ddekit_int32_t urb_direction, ddekit_uint32_t urb_transfer_flags)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
/* Sanity checks */
|
||||
assert(NULL != urb);
|
||||
assert(NULL != dev);
|
||||
assert((DDEKIT_USB_TRANSFER_BLK == urb_type) ||
|
||||
(DDEKIT_USB_TRANSFER_CTL == urb_type) ||
|
||||
(DDEKIT_USB_TRANSFER_INT == urb_type) ||
|
||||
(DDEKIT_USB_TRANSFER_ISO == urb_type));
|
||||
assert(urb_endpoint < 16);
|
||||
assert((DDEKIT_USB_IN == urb_direction) ||
|
||||
(DDEKIT_USB_OUT == urb_direction));
|
||||
|
||||
/* Clear block first */
|
||||
memset(urb, 0, sizeof(*urb));
|
||||
|
||||
/* Set supplied values */
|
||||
urb->dev = dev;
|
||||
urb->type = urb_type;
|
||||
urb->endpoint = urb_endpoint;
|
||||
urb->direction = urb_direction;
|
||||
urb->transfer_flags = urb_transfer_flags;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* attach_urb_data *
|
||||
*===========================================================================*/
|
||||
void
|
||||
attach_urb_data(struct ddekit_usb_urb * urb, int buf_type,
|
||||
void * buf, ddekit_uint32_t buf_len)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
assert(NULL != urb);
|
||||
assert(NULL != buf);
|
||||
|
||||
/* Mutual exclusion */
|
||||
if (URB_BUF_TYPE_DATA == buf_type) {
|
||||
urb->data = buf;
|
||||
urb->size = buf_len;
|
||||
} else if ( URB_BUF_TYPE_SETUP == buf_type ) {
|
||||
assert(sizeof(struct usb_ctrlrequest) == buf_len);
|
||||
urb->setup_packet = buf;
|
||||
} else
|
||||
panic("Unexpected buffer type!");
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* blocking_urb_submit *
|
||||
*===========================================================================*/
|
||||
int
|
||||
blocking_urb_submit(struct ddekit_usb_urb * urb, ddekit_sem_t * sem,
|
||||
int check_len)
|
||||
{
|
||||
MASS_DEBUG_DUMP;
|
||||
|
||||
assert(NULL != urb);
|
||||
assert(NULL != sem);
|
||||
assert((check_len == URB_SUBMIT_CHECK_LEN) ||
|
||||
(check_len == URB_SUBMIT_ALLOW_MISMATCH));
|
||||
|
||||
/* Submit and block until semaphore gets up */
|
||||
if (ddekit_usb_submit_urb(urb)) {
|
||||
MASS_MSG("Submitting DDEKit URB failed");
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
/* Submitting succeeded so block and wait for reply */
|
||||
ddekit_sem_down(sem);
|
||||
|
||||
/* Check for DDEKit status first */
|
||||
if (urb->status) {
|
||||
MASS_MSG("Invalid DDEKit URB status");
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
if (URB_SUBMIT_CHECK_LEN == check_len) {
|
||||
/* Compare lengths */
|
||||
if (urb->actual_length != urb->size) {
|
||||
MASS_MSG("URB different than expected");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
30
drivers/usb_storage/urb_helper.h
Executable file
30
drivers/usb_storage/urb_helper.h
Executable file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* URB formatting related definitions
|
||||
*/
|
||||
|
||||
#ifndef _URB_HELPER_H_
|
||||
#define _URB_HELPER_H_
|
||||
|
||||
#include <ddekit/usb.h>
|
||||
#include <ddekit/semaphore.h>
|
||||
|
||||
/* Possible values for attach_urb_data's buf_type */
|
||||
/* Both may be used for single URB */
|
||||
#define URB_BUF_TYPE_DATA 0 /* attached buffer is data buffer */
|
||||
#define URB_BUF_TYPE_SETUP 1 /* attached buffer is setup structure */
|
||||
|
||||
/* Possible values for blocking_urb_submit's check_len */
|
||||
/* Use URB_SUBMIT_CHECK_LEN when actual data buffer length returned
|
||||
* by HCD must match expected length, supplied in attach_urb_data */
|
||||
#define URB_SUBMIT_CHECK_LEN 0 /* return error on length mismatch */
|
||||
#define URB_SUBMIT_ALLOW_MISMATCH 1 /* ignore length check */
|
||||
|
||||
/*---------------------------*
|
||||
* declared functions *
|
||||
*---------------------------*/
|
||||
void init_urb(struct ddekit_usb_urb *, struct ddekit_usb_dev *, ddekit_int32_t,
|
||||
ddekit_int32_t, ddekit_int32_t, ddekit_uint32_t);
|
||||
void attach_urb_data(struct ddekit_usb_urb *, int, void *, ddekit_uint32_t);
|
||||
int blocking_urb_submit(struct ddekit_usb_urb *, ddekit_sem_t *, int);
|
||||
|
||||
#endif /* !_URB_HELPER_H_ */
|
1491
drivers/usb_storage/usb_storage.c
Executable file
1491
drivers/usb_storage/usb_storage.c
Executable file
File diff suppressed because it is too large
Load diff
15
drivers/usb_storage/usb_storage.conf
Executable file
15
drivers/usb_storage/usb_storage.conf
Executable file
|
@ -0,0 +1,15 @@
|
|||
service usb_storage
|
||||
{
|
||||
system
|
||||
PRIVCTL # 4
|
||||
UMAP # 14
|
||||
IRQCTL # 19
|
||||
DEVIO # 21
|
||||
SDEVIO # 22
|
||||
;
|
||||
ipc
|
||||
SYSTEM pm rs log tty ds vfs vm amddev devman
|
||||
pci usbd
|
||||
;
|
||||
uid 0;
|
||||
};
|
78
drivers/usb_storage/usb_storage.h
Executable file
78
drivers/usb_storage/usb_storage.h
Executable file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Minix3 USB mass storage driver definitions
|
||||
*/
|
||||
|
||||
#ifndef _USB_STORAGE_H_
|
||||
#define _USB_STORAGE_H_
|
||||
|
||||
#include <minix/driver.h> /* struct device */
|
||||
#include <minix/type.h> /* vir_bytes */
|
||||
/* TODO: no header for ddekit_usb_dev */
|
||||
|
||||
/* Number of handled peripherals (USB devices) */
|
||||
#define MAX_PERIPHS (1)
|
||||
/* Number of handled disks per driver */
|
||||
#define MAX_DRIVES (4)
|
||||
/* 4 partitions per disk */
|
||||
#define PART_PER_DISK (4)
|
||||
/* 4 sub partitions per partition */
|
||||
#define SUBPART_PER_PART (4)
|
||||
/* 16 sub partitions per disk */
|
||||
#define SUBPART_PER_DISK (PART_PER_DISK * SUBPART_PER_PART)
|
||||
|
||||
/*---------------------------*
|
||||
* declared types *
|
||||
*---------------------------*/
|
||||
/* Information on opened mass storage drives */
|
||||
typedef struct mass_storage_drive {
|
||||
|
||||
struct device disk; /* disk device */
|
||||
struct device part[PART_PER_DISK]; /* partition devices */
|
||||
struct device subpart[SUBPART_PER_DISK];/* sub-partition devices */
|
||||
unsigned long open_ct; /* opening counter */
|
||||
int drive_idx; /* Index of this drive */
|
||||
}
|
||||
mass_storage_drive;
|
||||
|
||||
/* Information on attached peripherals (USB devices) */
|
||||
typedef struct mass_storage_periph {
|
||||
|
||||
mass_storage_drive drives[MAX_DRIVES]; /* Possible drive info */
|
||||
struct ddekit_usb_dev * dev; /* DDEKit device handler */
|
||||
unsigned int interfaces; /* Interfaces bitmap */
|
||||
int ep_in; /* Bulk IN endpoint*/
|
||||
int ep_out; /* Bulk OUT endpoint*/
|
||||
}
|
||||
mass_storage_periph;
|
||||
|
||||
/* Structure for the information on current state of driver */
|
||||
typedef struct mass_storage_state {
|
||||
|
||||
/* DDEKit device handlers */
|
||||
mass_storage_periph periph[MAX_PERIPHS];
|
||||
|
||||
/* Currently used peripheral */
|
||||
mass_storage_periph * cur_periph;
|
||||
|
||||
/* Currently used drive */
|
||||
mass_storage_drive * cur_drive;
|
||||
|
||||
/* Currently used device (drive/partition/sub-partition) */
|
||||
struct device * cur_device;
|
||||
|
||||
/* Driver instance */
|
||||
long instance;
|
||||
}
|
||||
mass_storage_state;
|
||||
|
||||
/* State of current IO vector array for transfer operations */
|
||||
typedef struct iov_state {
|
||||
|
||||
vir_bytes base_addr; /* Address to read/write or grant ID */
|
||||
vir_bytes remaining_bytes; /* How many bytes remain in vector */
|
||||
vir_bytes offset; /* How many bytes were copied */
|
||||
unsigned int iov_idx; /* Index of currently selected vector */
|
||||
}
|
||||
iov_state;
|
||||
|
||||
#endif /* !_USB_STORAGE_H_ */
|
Loading…
Reference in a new issue