Commit 61710f61 authored by Ben Avison's avatar Ben Avison

Various changes to get it up to a releasable standard.

Detail:
  * Unplugging of devices is now reliable.
  * Stall handling now works (requires USBDriver 0.17).
  * We now do max LUN checking, since devices don't seem to do it reliably
    themselves.
  * Unknown SCSI driver handler reason codes now return an error.
  * Scatter list handling improvements - eg individual transfers can now be
    bigger than the DeviceFS buffer size (accounting for the last.
Admin:
  Tested with various mass storage devices.

Version 0.02. Tagged as 'SCSISoftUSB-0_02'
parent 38a04a4e
/* (0.01)
/* (0.02)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.68.
*
*/
#define Module_MajorVersion_CMHG 0.01
#define Module_MajorVersion_CMHG 0.02
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 14 May 2003
#define Module_Date_CMHG 23 May 2003
#define Module_MajorVersion "0.01"
#define Module_Version 1
#define Module_MajorVersion "0.02"
#define Module_Version 2
#define Module_MinorVersion ""
#define Module_Date "14 May 2003"
#define Module_Date "23 May 2003"
#define Module_ApplicationDate "14-May-03"
#define Module_ApplicationDate "23-May-03"
#define Module_ComponentName "SCSISoftUSB"
#define Module_ComponentPath "RiscOS/Sources/HWSupport/SCSI/SCSISoftUSB"
#define Module_FullVersion "0.01"
#define Module_HelpVersion "0.01 (14 May 2003)"
#define Module_LibraryVersionInfo "0:1"
#define Module_FullVersion "0.02"
#define Module_HelpVersion "0.02 (23 May 2003)"
#define Module_LibraryVersionInfo "0:2"
......@@ -101,6 +101,7 @@ extern usbd_status usbd_close_pipe(usbd_pipe_handle pipe);
* Function prototypes which umass.c thinks are private to itself but aren't really
*****************************************************************************/
extern usbd_status umass_setup_transfer(struct umass_softc *sc, usbd_pipe_handle pipeh, void *buffer, int buflen, int flags);
extern usbd_status umass_clear_endpoint_stall(struct umass_softc *sc, int endpt);
/*****************************************************************************
......@@ -172,7 +173,19 @@ bool glue_AttachDevice(my_usb_device_t *device, uint8_t *maxlun)
void glue_DetachDevice(my_usb_device_t *device)
{
DEBUGf("DetachDevice\n");
GetOffTickerV(device);
struct umass_softc *softc = (struct umass_softc *)device->softc;
if (device->command_active && softc->transfer_priv != NULL)
{
DEBUGf("Calling SCSIdriver from DetachDevice\n");
asm_DoTransferCompleteCallback((_kernel_oserror *)(ErrorNumber_SCSI_Died & 0xFF),
0,
device->callback,
softc->transfer_datalen,
device->callback_pw,
device->callback_wp);
softc->transfer_priv = NULL; /* if we're interrupting ticker processing, no longer try to do a callback at end of ticker */
}
umass_detach((struct device *)softc, 0);
}
......@@ -214,16 +227,15 @@ void glue_ResetBus(my_usb_device_t *device)
void glue_ResetDevice(my_usb_device_t *device)
{
DEBUGf("ResetDevice\n");
if (device->dying) return;
struct umass_softc *softc = (struct umass_softc *)device->softc;
bool callback_required;
bool irqs_were_off = _kernel_irqs_disabled();
if (!irqs_were_off) _kernel_irqs_off();
if (!device->command_active)
{
softc->transfer_priv = NULL; /* definitely don't do a callback if we're not interrupting an ongoing operation */
}
callback_required = (softc->transfer_priv != NULL); /* ongoing operation may have been a reset too, or may not have initialised enough yet */
} /* (it may be null anyway, if ongoing operation was a reset too, has been detached, or hasn't initialised enough yet) */
device->command_active = true; /* prevent any new commands from being started until we're done */
device->ticker_semaphore = true; /* prevent TickerV from doing anything */
if (!irqs_were_off) _kernel_irqs_on();
......@@ -242,13 +254,16 @@ void glue_ResetDevice(my_usb_device_t *device)
device->command_active = false;
device->ticker_semaphore = false;
/* Do callback if necessary */
DEBUGf("Calling SCSIdriver\n");
if (callback_required) asm_DoTransferCompleteCallback(device->callback_error,
device->callback_status_byte,
device->callback,
device->callback_not_transferred,
device->callback_pw,
device->callback_wp);
if (softc->transfer_priv != NULL)
{
DEBUGf("Calling SCSIdriver from ResetDevice\n");
asm_DoTransferCompleteCallback(device->callback_error,
device->callback_status_byte,
device->callback,
device->callback_not_transferred,
device->callback_pw,
device->callback_wp);
}
if (!irqs_were_off) _kernel_irqs_off();
return;
}
......@@ -283,6 +298,7 @@ void glue_ResetDevice(my_usb_device_t *device)
_kernel_oserror *glue_DoCommand(my_usb_device_t *device, uint32_t lun, uint32_t data_direction, const char *control_block, size_t control_block_length, scatter_entry_t *scatter_list, size_t transfer_length, void (*callback)(void), void *callback_pw, void *callback_wp)
{
DEBUGf("DoCommand\n");
if (device->dying) return (_kernel_oserror *)(ErrorNumber_SCSI_Died & 0xFF);
struct umass_softc *softc = (struct umass_softc *)device->softc;
bool irqs_were_off = _kernel_irqs_disabled();
......@@ -331,13 +347,16 @@ _kernel_oserror *glue_DoCommand(my_usb_device_t *device, uint32_t lun, uint32_t
device->command_active = false;
device->ticker_semaphore = false;
/* Do callback */
DEBUGf("Calling SCSIdriver\n");
asm_DoTransferCompleteCallback(device->callback_error,
device->callback_status_byte,
device->callback,
device->callback_not_transferred,
device->callback_pw,
device->callback_wp);
if (softc->transfer_priv != NULL)
{
DEBUGf("Calling SCSIdriver from DoCommand\n");
asm_DoTransferCompleteCallback(device->callback_error,
device->callback_status_byte,
device->callback,
device->callback_not_transferred,
device->callback_pw,
device->callback_wp);
}
}
else
{
......@@ -393,7 +412,7 @@ void glue_Tick(my_usb_device_t *device)
buffer_used = USED_SPACE(device->current_pipe->buffer);
DEBUGf("USED_SPACE = %x\n", buffer_used);
uint32_t maxpacket = device->current_pipe->maxpacket;
size_t buffer_free = BUFFER_SIZE - buffer_used;
size_t buffer_free = (BUFFER_SIZE - 1) - buffer_used;
if (buffer_free < device->curr_transferlength)
{
/* Ensure we only send in packet-size chunks, until the last packet */
......@@ -423,13 +442,16 @@ void glue_Tick(my_usb_device_t *device)
buffer_used ++;
device->curr_transferlength --;
device->curr_offset ++;
while (device->curr_offset == device->curr_scatterlist->length)
if (device->curr_transferlength > 0)
{
device->curr_scatterlist++;
device->curr_offset = 0;
if ((uint32_t) device->curr_scatterlist->start >= 0xFFFF00000u)
while (device->curr_offset == device->curr_scatterlist->length)
{
device->curr_scatterlist = (scatter_entry_t *) ((char *) device->curr_scatterlist + (int32_t) device->curr_scatterlist->start);
device->curr_scatterlist++;
device->curr_offset = 0;
if ((uint32_t) device->curr_scatterlist->start >= 0xFFFF00000u)
{
device->curr_scatterlist = (scatter_entry_t *) ((char *) device->curr_scatterlist + (int32_t) device->curr_scatterlist->start);
}
}
}
}
......@@ -444,21 +466,24 @@ void glue_Tick(my_usb_device_t *device)
if (wholepacket_len > 0)
{
INSERT_BLOCK(device->current_pipe->buffer, device->curr_scatterlist->start + device->curr_offset, wholepacket_len);
contig_len -= wholepacket_len;
buffer_free -= wholepacket_len;
buffer_used += wholepacket_len;
device->curr_transferlength -= wholepacket_len;
device->curr_offset += wholepacket_len;
while (device->curr_offset == device->curr_scatterlist->length)
if (device->curr_transferlength > 0)
{
device->curr_scatterlist++;
device->curr_offset = 0;
if ((uint32_t) device->curr_scatterlist->start >= 0xFFFF00000u)
while (device->curr_offset == device->curr_scatterlist->length)
{
device->curr_scatterlist = (scatter_entry_t *) ((char *) device->curr_scatterlist + (int32_t) device->curr_scatterlist->start);
device->curr_scatterlist++;
device->curr_offset = 0;
if ((uint32_t) device->curr_scatterlist->start >= 0xFFFF00000u)
{
device->curr_scatterlist = (scatter_entry_t *) ((char *) device->curr_scatterlist + (int32_t) device->curr_scatterlist->start);
}
}
}
}
contig_len -= wholepacket_len;
while (contig_len > 0)
{
......@@ -468,13 +493,16 @@ void glue_Tick(my_usb_device_t *device)
buffer_used ++;
device->curr_transferlength --;
device->curr_offset ++;
while (device->curr_offset == device->curr_scatterlist->length)
if (device->curr_transferlength > 0)
{
device->curr_scatterlist++;
device->curr_offset = 0;
if ((uint32_t) device->curr_scatterlist->start >= 0xFFFF00000u)
while (device->curr_offset == device->curr_scatterlist->length)
{
device->curr_scatterlist = (scatter_entry_t *) ((char *) device->curr_scatterlist + (int32_t) device->curr_scatterlist->start);
device->curr_scatterlist++;
device->curr_offset = 0;
if ((uint32_t) device->curr_scatterlist->start >= 0xFFFF00000u)
{
device->curr_scatterlist = (scatter_entry_t *) ((char *) device->curr_scatterlist + (int32_t) device->curr_scatterlist->start);
}
}
}
}
......@@ -503,13 +531,16 @@ void glue_Tick(my_usb_device_t *device)
buffer_used -= contig_len;
device->curr_transferlength -= contig_len;
device->curr_offset += contig_len;
while (device->curr_offset == device->curr_scatterlist->length)
if (device->curr_transferlength > 0)
{
device->curr_scatterlist++;
device->curr_offset = 0;
if ((uint32_t) device->curr_scatterlist->start >= 0xFFFF00000u)
while (device->curr_offset == device->curr_scatterlist->length)
{
device->curr_scatterlist = (scatter_entry_t *) ((char *) device->curr_scatterlist + (int32_t) device->curr_scatterlist->start);
device->curr_scatterlist++;
device->curr_offset = 0;
if ((uint32_t) device->curr_scatterlist->start >= 0xFFFF00000u)
{
device->curr_scatterlist = (scatter_entry_t *) ((char *) device->curr_scatterlist + (int32_t) device->curr_scatterlist->start);
}
}
}
}
......@@ -555,13 +586,16 @@ void glue_Tick(my_usb_device_t *device)
{
device->command_active = false;
GetOffTickerV(device);
DEBUGf("Calling SCSIdriver\n");
asm_DoTransferCompleteCallback(device->callback_error,
device->callback_status_byte,
device->callback,
device->callback_not_transferred,
device->callback_pw,
device->callback_wp);
if (softc->transfer_priv != NULL)
{
DEBUGf("Calling SCSIdriver from Tick, addr=%x err=%x r0=%x r4=%x r5=%x r12=%x\n", (int)device->callback, (int)device->callback_error, device->callback_status_byte, device->callback_not_transferred, (int)device->callback_pw, (int)device->callback_wp);
asm_DoTransferCompleteCallback(device->callback_error,
device->callback_status_byte,
device->callback,
device->callback_not_transferred,
device->callback_pw,
device->callback_wp);
}
}
}
......@@ -741,7 +775,7 @@ static void GetOffTickerV(my_usb_device_t *device)
else
{
prev = ptr;
ptr = ptr->next;
ptr = ptr->next_ticker;
}
}
if (!irqs_were_off) _kernel_irqs_on();
......@@ -952,6 +986,48 @@ usbd_status umass_setup_transfer(struct umass_softc *sc, usbd_pipe_handle pipeh,
return USBD_NORMAL_COMPLETION;
}
/*****************************************************************************
* umass_clear_endpoint_stall
*
* Performs the necessary actions to remove a stall condition from an endpoint.
* This is a replacement for one of the routines in umass.c, but it fits better
* with the other routines in this source file.
*
* Assumptions
* NONE
*
* Inputs
* sc: the BSD-style struct describing the device
* endpt: the endpoint that is stalled (index into our array of pipes)
*
* Outputs
* NONE
*
* Returns
* BSD-style status code
*****************************************************************************/
usbd_status umass_clear_endpoint_stall(struct umass_softc *sc, int endpt)
{
bool irqs_were_off = _kernel_irqs_disabled();
if (!irqs_were_off) _kernel_irqs_off();
my_usb_device_t *device = global_DeviceList;
while (device != NULL)
{
if (device->softc == sc) break;
device = device->next;
}
if (!irqs_were_off) _kernel_irqs_on();
if (device == NULL) return USBD_INVAL;
_kernel_oserror *e = _swix(DeviceFS_CallDevice, _INR(0,2),
DeviceCall_ExternalBase + 5,
device->devicefs_name,
device->pipe[endpt].handle);
DEBUGf("New device call returned %s\n", e ? e->errmess : "no error");
if (!e) return USBD_NORMAL_COMPLETION;
return USBD_IOERROR;
}
/*****************************************************************************
* END OF FILE
*****************************************************************************/
......@@ -41,6 +41,7 @@
#include "Global/Services.h"
#include "Global/RISCOS.h"
#include "Interface/SCSIErr.h"
#include "DebugLib/DebugLib.h"
#include "USB/USBDevFS.h"
......@@ -687,23 +688,29 @@ static _kernel_oserror *CheckConnectedDevice(const USBServiceCall *service_call_
static _kernel_oserror *CheckDisconnectedDevice(const char *device_name)
{
my_usb_device_t *prev = NULL;
for (my_usb_device_t *device = global_DeviceList; device != NULL; device = device->next)
my_usb_device_t *next;
for (my_usb_device_t *device = global_DeviceList; device != NULL; device = next)
{
next = device->next;
if (strcmp(device->devicefs_name, device_name) == 0)
{
device->dying = true; /* no more commands can be started */
glue_DetachDevice(device);
DeregisterSCSIDevice(device, device->scsi_driver_handle);
if (prev == NULL)
{
global_DeviceList = device->next;
global_DeviceList = next;
}
else
{
prev->next = device->next;
prev->next = next;
}
glue_DetachDevice(device);
free((char *)device + 4);
}
prev = device;
else
{
prev = device;
}
}
return NULL;
}
......@@ -729,9 +736,10 @@ static _kernel_oserror *RemoveAllDevices(void)
{
for (my_usb_device_t *device = global_DeviceList; device != NULL; device = global_DeviceList)
{
device->dying = true;
glue_DetachDevice(device);
DeregisterSCSIDevice(device, device->scsi_driver_handle);
global_DeviceList = device->next;
glue_DetachDevice(device);
free((char *)device + 4);
}
return NULL;
......@@ -766,7 +774,7 @@ _kernel_oserror *module_SCSIHandler(_kernel_swi_regs *r, void *pw)
break;
case 1: /* Reset bus */
assert(false /* shouldn't happen */);
e = (_kernel_oserror *)(ErrorNumber_SCSI_SWIunkn & 0xFF); /* shouldn't happen */
break;
case 2: /* Reset device */
......@@ -775,26 +783,42 @@ _kernel_oserror *module_SCSIHandler(_kernel_swi_regs *r, void *pw)
break;
case 4: /* Foreground op */
assert(false /* shouldn't happen */);
e = (_kernel_oserror *)(ErrorNumber_SCSI_SWIunkn & 0xFF); /* shouldn't happen */
break;
case 5: /* Background op */
e = glue_DoCommand((my_usb_device_t *)r->r[8],
(r->r[0] >> 10) & 0x3F,
r->r[0] & (3 << 24),
(char *) r->r[2],
r->r[1],
(scatter_entry_t *) r->r[3],
r->r[4],
(void (*)(void)) r->r[6],
(void *) r->r[5],
(void *) r->r[7]);
r->r[0] = -1; /* operation still in progress */
{
my_usb_device_t *device = (my_usb_device_t *)r->r[8];
// uint32_t lun = (r->r[0] >> 10) & 0x3F;
uint32_t lun = (r->r[0] >> 5) & 0x7;
if (lun > device->maxlun)
{
e = (_kernel_oserror *)(ErrorNumber_SCSI_NoDevice & 0xFF);
}
else
{
e = glue_DoCommand(device,
lun,
r->r[0] & (3 << 24),
(char *) r->r[2],
r->r[1],
(scatter_entry_t *) r->r[3],
r->r[4],
(void (*)(void)) r->r[6],
(void *) r->r[5],
(void *) r->r[7]);
r->r[0] = -1; /* operation still in progress */
}
break;
}
case 6: /* Cancel background operation */
glue_ResetDevice((my_usb_device_t *)r->r[8]);
break;
default: /* Unknown reason code */
e = (_kernel_oserror *)(ErrorNumber_SCSI_SWIunkn & 0xFF);
break;
}
return e;
}
......
......@@ -224,9 +224,9 @@ Static
#endif
umass_clear_endpoint_stall(struct umass_softc *sc, int endpt
#ifndef __riscos
, usbd_xfer_handle xfer
, usbd_xfer_handle xfer
#endif
);
);
#if 0
Static void umass_reset(struct umass_softc *sc, transfer_cb_f cb, void *priv);
#endif
......@@ -961,44 +961,25 @@ umass_setup_ctrl_transfer(struct umass_softc *sc, usb_device_request_t *req, voi
#endif
}
Static
#ifdef __riscos
usbd_status
#else
void
#endif
umass_clear_endpoint_stall(struct umass_softc *sc, int endpt
#ifndef __riscos
, usbd_xfer_handle xfer
#endif
)
Static void umass_clear_endpoint_stall(struct umass_softc *sc, int endpt, usbd_xfer_handle xfer)
{
#ifndef __riscos
if (sc->sc_dying)
return;
#endif
DPRINTF(UDMASS_BBB, ("%s: Clear endpoint 0x%02x stall\n",
USBDEVNAME(sc->sc_dev), sc->sc_epaddr[endpt]));
#ifndef __riscos /* can't see an easy way to get at this routine - can we do without? */
usbd_clear_endpoint_toggle(sc->sc_pipe[endpt]);
#endif
sc->sc_req.bmRequestType = UT_WRITE_ENDPOINT;
sc->sc_req.bRequest = UR_CLEAR_FEATURE;
USETW(sc->sc_req.wValue, UF_ENDPOINT_HALT);
USETW(sc->sc_req.wIndex, sc->sc_epaddr[endpt]);
USETW(sc->sc_req.wLength, 0);
#ifdef __riscos
return
#endif
umass_setup_ctrl_transfer(sc, &sc->sc_req, NULL
#ifndef __riscos
, 0, 0, xfer
#endif
);
umass_setup_ctrl_transfer(sc, &sc->sc_req, NULL, 0, 0, xfer);
}
#endif
#if 0
Static void
......@@ -1060,7 +1041,6 @@ umass_bbb_reset(struct umass_softc *sc, int transfer_status
USETW(sc->sc_req.wValue, 0);
USETW(sc->sc_req.wIndex, sc->sc_ifaceno);
USETW(sc->sc_req.wLength, 0);
DEBUGf("About to do a bulk reset\n");
#ifdef __riscos
*err =
#endif
......@@ -1069,7 +1049,6 @@ DEBUGf("About to do a bulk reset\n");
, 0, 0, sc->transfer_xfer[XFER_BBB_RESET1]
#endif
);
DEBUGf("Returned from bulk reset\n");
}
Static void
......
......@@ -44,7 +44,7 @@
#define INSERT_BLOCK(buffer_id, block, length) do { asm_CallBufferManager(1, buffer_id, block, length, static_BufManWS, static_BufManRout); } while(0)
#define REMOVE_BLOCK(buffer_id, block, length) do { asm_CallBufferManager(3, buffer_id, block, length, static_BufManWS, static_BufManRout); } while(0)
#define USED_SPACE(buffer_id) asm_CallBufferManager(6, buffer_id, 0, 0, static_BufManWS, static_BufManRout)
#define FREE_SPACE(buffer_id) asm_CallBufferManager(6, buffer_id, 0, 0, static_BufManWS, static_BufManRout)
#define FREE_SPACE(buffer_id) asm_CallBufferManager(7, buffer_id, 0, 0, static_BufManWS, static_BufManRout)
/*****************************************************************************
......
......@@ -13,7 +13,9 @@
* limitations under the License.
*/
#if 1
#undef DEBUGGING
#ifndef DEBUGGING
#define NO_SVCPRINT
#define DEBUGf(...)
#else
......
......@@ -93,6 +93,8 @@ typedef struct my_usb_device
struct my_usb_device *next;
bool dying;
uint8_t interface;
uint8_t alternate;
uint8_t subclass;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment