* Switched from the old v2 callback status codes to the new v3 codes

This means that the usb_callback_func now takes a status_t instead of a uint32 status.
Also the error codes are now different. I don't see this as a real problem in binary compatibility, as the status codes were never really documented and most drivers just assumed that a nonzero status meant an error.
Source compatibility breaks for callback functions and error defines. I fixed (hopefully) all places in the tree that are currenty included in the image and affected by the change.
* Corrected error reporting in UHCI and EHCI using the new status codes.
* Fixed a memory leak in EHCI where the async advance interrupt was not triggered in time.
* Fixed another race condition in usb_raw that could cause a crash when a device is removed while a transfer is pending.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18916 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2006-09-24 20:17:56 +00:00
parent 8a278a1bb7
commit 17f83b219d
20 changed files with 175 additions and 150 deletions

View File

@ -73,7 +73,7 @@ struct usb_configuration_info {
usb_interface_list *interface; usb_interface_list *interface;
}; };
typedef void (*usb_callback_func)(void *cookie, uint32 status, void *data, typedef void (*usb_callback_func)(void *cookie, status_t status, void *data,
size_t actualLength); size_t actualLength);
@ -203,24 +203,6 @@ struct usb_module_info {
}; };
/*
* These status are passed to the usb_callback_func callbacks. They indicate
* the status of a completed queued transfer. Multiple of these status codes
* may be combined. For example it is possible to have:
* B_USB_STATUS_DEVICE_TIMEOUT | B_USB_STATUS_DEVICE_STALLED
* This indicates that a timeout happened and that the used pipe is now
* stalled.
*/
#define B_USB_STATUS_SUCCESS 0x0000
#define B_USB_STATUS_DEVICE_CRC_ERROR 0x0002
#define B_USB_STATUS_DEVICE_TIMEOUT 0x0004
#define B_USB_STATUS_DEVICE_STALLED 0x0008
#define B_USB_STATUS_IRP_CANCELLED_BY_REQUEST 0x0010
#define B_USB_STATUS_DRIVER_INTERNAL_ERROR 0x0020
#define B_USB_STATUS_ADAPTER_HARDWARE_ERROR 0x0040
#define B_USB_STATUS_ISOCH_IRP_ABORTED 0x0080
#define B_USB_MODULE_NAME "bus_managers/usb/v2" #define B_USB_MODULE_NAME "bus_managers/usb/v2"

View File

@ -79,7 +79,7 @@ typedef struct {
status_t status; status_t status;
} usb_iso_packet_descriptor; } usb_iso_packet_descriptor;
typedef void (*usb_callback_func)(void *cookie, uint32 status, void *data, typedef void (*usb_callback_func)(void *cookie, status_t status, void *data,
size_t actualLength); size_t actualLength);
@ -214,24 +214,6 @@ struct usb_module_info {
}; };
/*
* These status are passed to the usb_callback_func callbacks. They indicate
* the status of a completed queued transfer. Multiple of these status codes
* may be combined. For example it is possible to have:
* B_USB_STATUS_DEVICE_TIMEOUT | B_USB_STATUS_DEVICE_STALLED
* This indicates that a timeout happened and that the used pipe is now
* stalled.
*/
#define B_USB_STATUS_SUCCESS 0x0000
#define B_USB_STATUS_DEVICE_CRC_ERROR 0x0002
#define B_USB_STATUS_DEVICE_TIMEOUT 0x0004
#define B_USB_STATUS_DEVICE_STALLED 0x0008
#define B_USB_STATUS_IRP_CANCELLED_BY_REQUEST 0x0010
#define B_USB_STATUS_DRIVER_INTERNAL_ERROR 0x0020
#define B_USB_STATUS_ADAPTER_HARDWARE_ERROR 0x0040
#define B_USB_STATUS_ISOCH_IRP_ABORTED 0x0080
#define B_USB_MODULE_NAME "bus_managers/usb/v3" #define B_USB_MODULE_NAME "bus_managers/usb/v3"

View File

@ -10,6 +10,22 @@
#define IS_USER_ADDRESS(x) (((uint32)x & 0x80000000) > 0) #define IS_USER_ADDRESS(x) (((uint32)x & 0x80000000) > 0)
#define IS_KERNEL_ADDRESS(x) (((uint32)x & 0x80000000) == 0) #define IS_KERNEL_ADDRESS(x) (((uint32)x & 0x80000000) == 0)
#ifndef B_DEV_INVALID_PIPE
enum {
B_DEV_INVALID_PIPE = B_DEV_DOOR_OPEN + 1,
B_DEV_CRC_ERROR,
B_DEV_STALLED,
B_DEV_BAD_PID,
B_DEV_UNEXPECTED_PID,
B_DEV_DATA_OVERRUN,
B_DEV_DATA_UNDERRUN,
B_DEV_FIFO_OVERRUN,
B_DEV_FIFO_UNDERRUN,
B_DEV_PENDING,
B_DEV_MULTIPLE_ERRORS,
B_DEV_TOO_LATE,
};
#endif
inline status_t inline status_t
benaphore_init(benaphore *ben, const char *name) benaphore_init(benaphore *ben, const char *name)

View File

@ -230,7 +230,7 @@ Hub::Explore()
void void
Hub::InterruptCallback(void *cookie, uint32 status, void *data, Hub::InterruptCallback(void *cookie, status_t status, void *data,
size_t actualLength) size_t actualLength)
{ {
TRACE(("USB Hub: interrupt callback!\n")); TRACE(("USB Hub: interrupt callback!\n"));

View File

@ -204,9 +204,9 @@ IsochronousPipe::QueueIsochronous(void *data, size_t dataLength,
typedef struct transfer_result_data_s { typedef struct transfer_result_data_s {
sem_id notify_sem; sem_id notify_sem;
uint32 status; status_t status;
size_t actual_length; size_t actual_length;
} transfer_result_data; } transfer_result_data;
@ -243,15 +243,12 @@ ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value,
if (actualLength) if (actualLength)
*actualLength = transferResult.actual_length; *actualLength = transferResult.actual_length;
if (transferResult.status == B_USB_STATUS_SUCCESS) return transferResult.status;
return B_OK;
return B_ERROR;
} }
void void
ControlPipe::SendRequestCallback(void *cookie, uint32 status, void *data, ControlPipe::SendRequestCallback(void *cookie, status_t status, void *data,
size_t actualLength) size_t actualLength)
{ {
transfer_result_data *transferResult = (transfer_result_data *)cookie; transfer_result_data *transferResult = (transfer_result_data *)cookie;

View File

@ -123,7 +123,7 @@ set_configuration(usb_device device,
TRACE(("usb_module: set_configuration(0x%08x, 0x%08x)\n", device, configuration)); TRACE(("usb_module: set_configuration(0x%08x, 0x%08x)\n", device, configuration));
Object *object = gUSBStack->GetObject(device); Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return ((Device *)object)->SetConfiguration(configuration); return ((Device *)object)->SetConfiguration(configuration);
} }
@ -135,7 +135,7 @@ set_alt_interface(usb_device device, const usb_interface_info *interface)
TRACE(("usb_module: set_alt_interface(0x%08x, 0x%08x)\n", device, interface)); TRACE(("usb_module: set_alt_interface(0x%08x, 0x%08x)\n", device, interface));
Object *object = gUSBStack->GetObject(device); Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return B_ERROR; return B_ERROR;
} }
@ -147,7 +147,7 @@ set_feature(usb_id handle, uint16 selector)
TRACE(("usb_module: set_feature(0x%08x, %d)\n", handle, selector)); TRACE(("usb_module: set_feature(0x%08x, %d)\n", handle, selector));
Object *object = gUSBStack->GetObject(handle); Object *object = gUSBStack->GetObject(handle);
if (!object) if (!object)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return object->SetFeature(selector); return object->SetFeature(selector);
} }
@ -159,7 +159,7 @@ clear_feature(usb_id handle, uint16 selector)
TRACE(("usb_module: clear_feature(0x%08x, %d)\n", handle, selector)); TRACE(("usb_module: clear_feature(0x%08x, %d)\n", handle, selector));
Object *object = gUSBStack->GetObject(handle); Object *object = gUSBStack->GetObject(handle);
if (!object) if (!object)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return object->ClearFeature(selector); return object->ClearFeature(selector);
} }
@ -174,7 +174,7 @@ get_status(usb_id handle, uint16 *status)
Object *object = gUSBStack->GetObject(handle); Object *object = gUSBStack->GetObject(handle);
if (!object) if (!object)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return object->GetStatus(status); return object->GetStatus(status);
} }
@ -187,7 +187,7 @@ get_descriptor(usb_device device, uint8 type, uint8 index, uint16 languageID,
TRACE(("usb_module: get_descriptor(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%08x, %d, 0x%08x)\n", device, type, index, languageID, data, dataLength, actualLength)); TRACE(("usb_module: get_descriptor(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%08x, %d, 0x%08x)\n", device, type, index, languageID, data, dataLength, actualLength));
Object *object = gUSBStack->GetObject(device); Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return ((Device *)object)->GetDescriptor(type, index, languageID, return ((Device *)object)->GetDescriptor(type, index, languageID,
data, dataLength, actualLength); data, dataLength, actualLength);
@ -201,7 +201,7 @@ send_request(usb_device device, uint8 requestType, uint8 request,
TRACE(("usb_module: send_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, 0x%08x)\n", device, requestType, request, value, index, length, data, actualLength)); TRACE(("usb_module: send_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, 0x%08x)\n", device, requestType, request, value, index, length, data, actualLength));
Object *object = gUSBStack->GetObject(device); Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return ((Device *)object)->DefaultPipe()->SendRequest(requestType, request, return ((Device *)object)->DefaultPipe()->SendRequest(requestType, request,
value, index, length, data, length, actualLength); value, index, length, data, length, actualLength);
@ -216,7 +216,7 @@ queue_request(usb_device device, uint8 requestType, uint8 request,
TRACE(("usb_module: queue_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, 0x%08x, 0x%08x)\n", device, requestType, request, value, index, length, data, callback, callbackCookie)); TRACE(("usb_module: queue_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, 0x%08x, 0x%08x)\n", device, requestType, request, value, index, length, data, callback, callbackCookie));
Object *object = gUSBStack->GetObject(device); Object *object = gUSBStack->GetObject(device);
if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return ((Device *)object)->DefaultPipe()->QueueRequest(requestType, return ((Device *)object)->DefaultPipe()->QueueRequest(requestType,
request, value, index, length, data, length, callback, callbackCookie); request, value, index, length, data, length, callback, callbackCookie);
@ -230,7 +230,7 @@ queue_interrupt(usb_pipe pipe, void *data, size_t dataLength,
TRACE(("usb_module: queue_interrupt(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie)); TRACE(("usb_module: queue_interrupt(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie));
Object *object = gUSBStack->GetObject(pipe); Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_INTERRUPT_PIPE) == 0) if (!object || (object->Type() & USB_OBJECT_INTERRUPT_PIPE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return ((InterruptPipe *)object)->QueueInterrupt(data, dataLength, callback, return ((InterruptPipe *)object)->QueueInterrupt(data, dataLength, callback,
callbackCookie); callbackCookie);
@ -244,7 +244,7 @@ queue_bulk(usb_pipe pipe, void *data, size_t dataLength,
TRACE(("usb_module: queue_bulk(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie)); TRACE(("usb_module: queue_bulk(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie));
Object *object = gUSBStack->GetObject(pipe); Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0) if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return ((BulkPipe *)object)->QueueBulk(data, dataLength, callback, return ((BulkPipe *)object)->QueueBulk(data, dataLength, callback,
callbackCookie); callbackCookie);
@ -258,7 +258,7 @@ queue_bulk_v(usb_pipe pipe, iovec *vector, size_t vectorCount,
TRACE(("usb_module: queue_bulk(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, vector, vectorCount, callback, callbackCookie)); TRACE(("usb_module: queue_bulk(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, vector, vectorCount, callback, callbackCookie));
Object *object = gUSBStack->GetObject(pipe); Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0) if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return ((BulkPipe *)object)->QueueBulkV(vector, vectorCount, callback, return ((BulkPipe *)object)->QueueBulkV(vector, vectorCount, callback,
callbackCookie); callbackCookie);
@ -274,7 +274,7 @@ queue_isochronous(usb_pipe pipe, void *data, size_t dataLength,
TRACE(("usb_module: queue_isochronous(0x%08x, 0x%08x, %d, 0x%08x, %d, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", pipe, data, dataLength, packetDesc, packetCount, startingFrameNumber, flags, callback, callbackCookie)); TRACE(("usb_module: queue_isochronous(0x%08x, 0x%08x, %d, 0x%08x, %d, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", pipe, data, dataLength, packetDesc, packetCount, startingFrameNumber, flags, callback, callbackCookie));
Object *object = gUSBStack->GetObject(pipe); Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0) if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return ((IsochronousPipe *)object)->QueueIsochronous(data, dataLength, return ((IsochronousPipe *)object)->QueueIsochronous(data, dataLength,
packetDesc, packetCount, startingFrameNumber, flags, callback, packetDesc, packetCount, startingFrameNumber, flags, callback,
@ -289,7 +289,7 @@ set_pipe_policy(usb_pipe pipe, uint8 maxQueuedPackets,
TRACE(("usb_module: set_pipe_policy(0x%08x, %d, %d, %d)\n", pipe, maxQueuedPackets, maxBufferDurationMS, sampleSize)); TRACE(("usb_module: set_pipe_policy(0x%08x, %d, %d, %d)\n", pipe, maxQueuedPackets, maxBufferDurationMS, sampleSize));
Object *object = gUSBStack->GetObject(pipe); Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0) if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return B_ERROR; return B_ERROR;
} }
@ -301,7 +301,7 @@ cancel_queued_transfers(usb_pipe pipe)
TRACE(("usb_module: cancel_queued_transfers(0x%08x)\n", pipe)); TRACE(("usb_module: cancel_queued_transfers(0x%08x)\n", pipe));
Object *object = gUSBStack->GetObject(pipe); Object *object = gUSBStack->GetObject(pipe);
if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) if (!object || (object->Type() & USB_OBJECT_PIPE) == 0)
return B_BAD_VALUE; return B_DEV_INVALID_PIPE;
return ((Pipe *)object)->CancelQueuedTransfers(); return ((Pipe *)object)->CancelQueuedTransfers();
} }

View File

@ -272,7 +272,7 @@ virtual void SetDataToggle(bool toggle) {};
void *data, size_t dataLength, void *data, size_t dataLength,
size_t *actualLength); size_t *actualLength);
static void SendRequestCallback(void *cookie, static void SendRequestCallback(void *cookie,
uint32 status, void *data, status_t status, void *data,
size_t actualLength); size_t actualLength);
status_t QueueRequest(uint8 requestType, status_t QueueRequest(uint8 requestType,
@ -437,7 +437,7 @@ virtual status_t GetDescriptor(uint8 descriptorType,
status_t ResetPort(uint8 index); status_t ResetPort(uint8 index);
void Explore(); void Explore();
static void InterruptCallback(void *cookie, static void InterruptCallback(void *cookie,
uint32 status, void *data, status_t status, void *data,
size_t actualLength); size_t actualLength);
virtual status_t ReportDevice( virtual status_t ReportDevice(

View File

@ -2,6 +2,10 @@ SubDir HAIKU_TOP src add-ons kernel busses scsi usb ;
SetSubDirSupportedPlatformsBeOSCompatible ; SetSubDirSupportedPlatformsBeOSCompatible ;
if $(TARGET_PLATFORM) != haiku {
UsePublicHeaders [ FDirName drivers ] ;
}
KernelAddon usb_scsi : KernelAddon usb_scsi :
usb_scsi.c usb_scsi.c
tracing.c tracing.c

View File

@ -30,7 +30,7 @@
??? ???
*/ */
void bulk_callback(void *cookie, uint32 status, void* data, uint32 actual_len) void bulk_callback(void *cookie, status_t status, void* data, uint32 actual_len)
{ {
TRACE_BULK_CALLBACK(status, actual_len); TRACE_BULK_CALLBACK(status, actual_len);
if(cookie){ if(cookie){

View File

@ -17,7 +17,7 @@
#include "device_info.h" #include "device_info.h"
#endif /* _DEVICE_INFO_H_ */ #endif /* _DEVICE_INFO_H_ */
void bulk_callback(void *cookie, uint32 status, void* data, uint32 actual_len); void bulk_callback(void *cookie, status_t status, void* data, uint32 actual_len);
status_t process_data_io(usb_device_info *udi, iovec *sg_data, int32 sg_count/*sg_buffer *sgb*/, EDirection dir); status_t process_data_io(usb_device_info *udi, iovec *sg_data, int32 sg_count/*sg_buffer *sgb*/, EDirection dir);

View File

@ -106,6 +106,7 @@ EHCI::EHCI(pci_info *info, Stack *stack)
fLastTransfer(NULL), fLastTransfer(NULL),
fFinishThread(-1), fFinishThread(-1),
fStopFinishThread(false), fStopFinishThread(false),
fFreeListHead(NULL),
fRootHub(NULL), fRootHub(NULL),
fRootHubAddress(0), fRootHubAddress(0),
fPortCount(0), fPortCount(0),
@ -879,7 +880,7 @@ EHCI::CancelPendingTransfer(Transfer *transfer)
transfer_data *current = fFirstTransfer; transfer_data *current = fFirstTransfer;
while (current) { while (current) {
if (current->transfer == transfer) { if (current->transfer == transfer) {
current->transfer->Finished(B_USB_STATUS_IRP_CANCELLED_BY_REQUEST, 0); current->transfer->Finished(B_CANCELED, 0);
delete current->transfer; delete current->transfer;
if (last) if (last)
@ -912,7 +913,7 @@ EHCI::CancelAllPendingTransfers()
transfer_data *transfer = fFirstTransfer; transfer_data *transfer = fFirstTransfer;
while (transfer) { while (transfer) {
transfer->transfer->Finished(B_USB_STATUS_IRP_CANCELLED_BY_REQUEST, 0); transfer->transfer->Finished(B_CANCELED, 0);
delete transfer->transfer; delete transfer->transfer;
transfer_data *next = transfer->link; transfer_data *next = transfer->link;
@ -956,7 +957,6 @@ EHCI::FinishTransfers()
transfer_data *transfer = fFirstTransfer; transfer_data *transfer = fFirstTransfer;
Unlock(); Unlock();
ehci_qh *freeListHead = NULL;
while (transfer) { while (transfer) {
bool transferDone = false; bool transferDone = false;
ehci_qtd *descriptor = (ehci_qtd *)transfer->queue_head->element_log; ehci_qtd *descriptor = (ehci_qtd *)transfer->queue_head->element_log;
@ -977,18 +977,34 @@ EHCI::FinishTransfers()
// a transfer error occured // a transfer error occured
TRACE_ERROR(("usb_ehci: qtd (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status)); TRACE_ERROR(("usb_ehci: qtd (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status));
uint32 callbackStatus = 0; status_t callbackStatus = B_ERROR;
if (status & EHCI_QTD_STATUS_HALTED) uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT;
callbackStatus |= B_USB_STATUS_DEVICE_STALLED; errorCount &= EHCI_QTD_ERRCOUNT_MASK;
if (status & EHCI_QTD_STATUS_BUFFER) if (errorCount == 0) {
callbackStatus |= B_USB_STATUS_DEVICE_TIMEOUT; // the error counter counted down to zero, report why
if (status & EHCI_QTD_STATUS_BABBLE) int32 reasons = 0;
callbackStatus |= B_USB_STATUS_ADAPTER_HARDWARE_ERROR; if (status & EHCI_QTD_STATUS_BUFFER) {
if (status & EHCI_QTD_STATUS_TERROR) callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
callbackStatus |= B_USB_STATUS_DRIVER_INTERNAL_ERROR; reasons++;
// ToDo: define better error values! }
if (status & EHCI_QTD_STATUS_TERROR) {
callbackStatus = B_DEV_CRC_ERROR;
reasons++;
}
UnlinkQueueHead(transfer->queue_head, &freeListHead); if (reasons > 1)
callbackStatus = B_DEV_MULTIPLE_ERRORS;
} else if (status & EHCI_QTD_STATUS_BABBLE) {
// there is a babble condition
callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN;
} else {
// if the error counter didn't count down to zero
// and there was no babble, then this halt was caused
// by a stall handshake
callbackStatus = B_DEV_STALLED;
}
UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
transfer->transfer->Finished(callbackStatus, 0); transfer->transfer->Finished(callbackStatus, 0);
transferDone = true; transferDone = true;
break; break;
@ -1038,9 +1054,9 @@ EHCI::FinishTransfers()
&nextDataToggle); &nextDataToggle);
} }
UnlinkQueueHead(transfer->queue_head, &freeListHead); UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
transfer->transfer->TransferPipe()->SetDataToggle(nextDataToggle); transfer->transfer->TransferPipe()->SetDataToggle(nextDataToggle);
transfer->transfer->Finished(B_USB_STATUS_SUCCESS, actualLength); transfer->transfer->Finished(B_OK, actualLength);
transferDone = true; transferDone = true;
break; break;
} }
@ -1065,19 +1081,22 @@ EHCI::FinishTransfers()
Unlock(); Unlock();
} }
} else { } else {
lastTransfer = transfer; if (Lock()) {
transfer = transfer->link; lastTransfer = transfer;
transfer = transfer->link;
Unlock();
}
} }
} }
if (freeListHead) { if (fFreeListHead) {
// set the doorbell and wait for the host controller to notify us // set the doorbell and wait for the host controller to notify us
WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD); WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD);
if (acquire_sem_etc(fAsyncAdvanceSem, 1, B_RELATIVE_TIMEOUT, 1000) == B_OK) { if (acquire_sem_etc(fAsyncAdvanceSem, 1, B_RELATIVE_TIMEOUT, 1000) == B_OK) {
while (freeListHead) { while (fFreeListHead) {
ehci_qh *next = (ehci_qh *)freeListHead->next_log; ehci_qh *next = (ehci_qh *)fFreeListHead->next_log;
FreeQueueHead(freeListHead); FreeQueueHead(fFreeListHead);
freeListHead = next; fFreeListHead = next;
} }
} }
} }

View File

@ -142,6 +142,7 @@ static pci_module_info *sPCIModule;
sem_id fFinishTransfersSem; sem_id fFinishTransfersSem;
thread_id fFinishThread; thread_id fFinishThread;
bool fStopFinishThread; bool fStopFinishThread;
ehci_qh *fFreeListHead;
// Root Hub // Root Hub
EHCIRootHub *fRootHub; EHCIRootHub *fRootHub;

View File

@ -153,7 +153,7 @@ typedef struct {
#define EHCI_QTD_PID_SETUP 0x02 #define EHCI_QTD_PID_SETUP 0x02
#define EHCI_QTD_STATUS_SHIFT 0 #define EHCI_QTD_STATUS_SHIFT 0
#define EHCI_QTD_STATUS_MASK 0x7f #define EHCI_QTD_STATUS_MASK 0x7f
#define EHCI_QTD_STATUS_ERRMASK 0x70 #define EHCI_QTD_STATUS_ERRMASK 0x50
#define EHCI_QTD_STATUS_ACTIVE (1 << 7) // Active #define EHCI_QTD_STATUS_ACTIVE (1 << 7) // Active
#define EHCI_QTD_STATUS_HALTED (1 << 6) // Halted #define EHCI_QTD_STATUS_HALTED (1 << 6) // Halted
#define EHCI_QTD_STATUS_BUFFER (1 << 5) // Data Buffer Error #define EHCI_QTD_STATUS_BUFFER (1 << 5) // Data Buffer Error

View File

@ -136,8 +136,7 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
usb_request_data *request = transfer->RequestData(); usb_request_data *request = transfer->RequestData();
TRACE(("usb_ehci_roothub: request: %d\n", request->Request)); TRACE(("usb_ehci_roothub: request: %d\n", request->Request));
// ToDo: define better status codes. We should return a request error. status_t status = B_TIMED_OUT;
uint32 status = B_USB_STATUS_DEVICE_TIMEOUT;
size_t actualLength = 0; size_t actualLength = 0;
switch (request->Request) { switch (request->Request) {
case USB_REQUEST_GET_STATUS: { case USB_REQUEST_GET_STATUS: {
@ -149,7 +148,7 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
// and if there is a over-current condition (bit 1). // and if there is a over-current condition (bit 1).
// everything as 0 means all is ok. // everything as 0 means all is ok.
memset(transfer->Data(), 0, actualLength); memset(transfer->Data(), 0, actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -157,7 +156,7 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
if (ehci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) { if (ehci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
actualLength = MIN(sizeof(usb_port_status), transfer->DataLength()); actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
memcpy(transfer->Data(), (void *)&portStatus, actualLength); memcpy(transfer->Data(), (void *)&portStatus, actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
} }
break; break;
@ -165,12 +164,12 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
case USB_REQUEST_SET_ADDRESS: case USB_REQUEST_SET_ADDRESS:
if (request->Value >= 128) { if (request->Value >= 128) {
status = B_USB_STATUS_DEVICE_TIMEOUT; status = B_TIMED_OUT;
break; break;
} }
TRACE(("usb_ehci_roothub: set address: %d\n", request->Value)); TRACE(("usb_ehci_roothub: set address: %d\n", request->Value));
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
case USB_REQUEST_GET_DESCRIPTOR: case USB_REQUEST_GET_DESCRIPTOR:
@ -182,7 +181,7 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
transfer->DataLength()); transfer->DataLength());
memcpy(transfer->Data(), (void *)&sEHCIRootHubDevice, memcpy(transfer->Data(), (void *)&sEHCIRootHubDevice,
actualLength); actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -192,7 +191,7 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
sEHCIRootHubConfig.hub.num_ports = ehci->PortCount(); sEHCIRootHubConfig.hub.num_ports = ehci->PortCount();
memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig, memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig,
actualLength); actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -205,7 +204,7 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
transfer->DataLength()); transfer->DataLength());
memcpy(transfer->Data(), (void *)&sEHCIRootHubStrings[index], memcpy(transfer->Data(), (void *)&sEHCIRootHubStrings[index],
actualLength); actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -215,14 +214,14 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
sEHCIRootHubConfig.hub.num_ports = ehci->PortCount(); sEHCIRootHubConfig.hub.num_ports = ehci->PortCount();
memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig.hub, memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig.hub,
actualLength); actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
} }
break; break;
case USB_REQUEST_SET_CONFIGURATION: case USB_REQUEST_SET_CONFIGURATION:
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
case USB_REQUEST_CLEAR_FEATURE: { case USB_REQUEST_CLEAR_FEATURE: {
@ -234,7 +233,7 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
TRACE(("usb_ehci_roothub: clear feature: %d\n", request->Value)); TRACE(("usb_ehci_roothub: clear feature: %d\n", request->Value));
if (ehci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK) if (ehci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -247,7 +246,7 @@ EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
TRACE(("usb_ehci_roothub: set feature: %d\n", request->Value)); TRACE(("usb_ehci_roothub: set feature: %d\n", request->Value));
if (ehci->SetPortFeature(request->Index - 1, request->Value) >= B_OK) if (ehci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
} }

View File

@ -770,14 +770,39 @@ UHCI::FinishTransfers()
// an error occured. we have to remove the // an error occured. we have to remove the
// transfer from the queue and clean up // transfer from the queue and clean up
uint32 callbackStatus = 0; status_t callbackStatus = B_ERROR;
if (status & TD_STATUS_ERROR_STALLED) uint8 errorCount = status >> TD_ERROR_COUNT_SHIFT;
callbackStatus |= B_USB_STATUS_DEVICE_STALLED; errorCount &= TD_ERROR_COUNT_MASK;
if (status & TD_STATUS_ERROR_TIMEOUT) { if (errorCount == 0) {
if (transfer->incoming) // the error counter counted down to zero, report why
callbackStatus |= B_USB_STATUS_DEVICE_CRC_ERROR; int32 reasons = 0;
else if (status & TD_STATUS_ERROR_BUFFER) {
callbackStatus |= B_USB_STATUS_DEVICE_TIMEOUT; callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
reasons++;
}
if (status & TD_STATUS_ERROR_TIMEOUT) {
callbackStatus = transfer->incoming ? B_DEV_CRC_ERROR : B_TIMED_OUT;
reasons++;
}
if (status & TD_STATUS_ERROR_NAK) {
callbackStatus = B_DEV_UNEXPECTED_PID;
reasons++;
}
if (status & TD_STATUS_ERROR_BITSTUFF) {
callbackStatus = B_DEV_CRC_ERROR;
reasons++;
}
if (reasons > 1)
callbackStatus = B_DEV_MULTIPLE_ERRORS;
} else if (status & TD_STATUS_ERROR_BABBLE) {
// there is a babble condition
callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN;
} else {
// if the error counter didn't count down to zero
// and there was no babble, then this halt was caused
// by a stall handshake
callbackStatus = B_DEV_STALLED;
} }
transfer->queue->RemoveDescriptorChain( transfer->queue->RemoveDescriptorChain(
@ -841,7 +866,7 @@ UHCI::FinishTransfers()
FreeDescriptorChain(transfer->first_descriptor); FreeDescriptorChain(transfer->first_descriptor);
transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0); transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
transfer->transfer->Finished(B_USB_STATUS_SUCCESS, actualLength); transfer->transfer->Finished(B_OK, actualLength);
transferDone = true; transferDone = true;
break; break;
} }

View File

@ -128,7 +128,9 @@ typedef struct
#define TD_DEPTH_FIRST 0x04 #define TD_DEPTH_FIRST 0x04
#define TD_TERMINATE 0x01 #define TD_TERMINATE 0x01
#define TD_ERROR_MASK 0x7e0000 #define TD_ERROR_MASK 0x440000
#define TD_ERROR_COUNT_SHIFT 27
#define TD_ERROR_COUNT_MASK 0x03
#define TD_LINK_MASK 0xfffffff0 #define TD_LINK_MASK 0xfffffff0

View File

@ -140,8 +140,7 @@ UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
usb_request_data *request = transfer->RequestData(); usb_request_data *request = transfer->RequestData();
TRACE(("usb_uhci_roothub: request: %d\n", request->Request)); TRACE(("usb_uhci_roothub: request: %d\n", request->Request));
// ToDo: define better status codes. We should return a request error. status_t status = B_TIMED_OUT;
uint32 status = B_USB_STATUS_DEVICE_TIMEOUT;
size_t actualLength = 0; size_t actualLength = 0;
switch (request->Request) { switch (request->Request) {
case USB_REQUEST_GET_STATUS: { case USB_REQUEST_GET_STATUS: {
@ -150,7 +149,7 @@ UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
actualLength = MIN(sizeof(usb_port_status), actualLength = MIN(sizeof(usb_port_status),
transfer->DataLength()); transfer->DataLength());
memset(transfer->Data(), 0, actualLength); memset(transfer->Data(), 0, actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -158,19 +157,19 @@ UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
if (uhci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) { if (uhci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
actualLength = MIN(sizeof(usb_port_status), transfer->DataLength()); actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
memcpy(transfer->Data(), (void *)&portStatus, actualLength); memcpy(transfer->Data(), (void *)&portStatus, actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
} }
break; break;
} }
case USB_REQUEST_SET_ADDRESS: case USB_REQUEST_SET_ADDRESS:
if (request->Value >= 128) { if (request->Value >= 128) {
status = B_USB_STATUS_DEVICE_TIMEOUT; status = B_TIMED_OUT;
break; break;
} }
TRACE(("usb_uhci_roothub: set address: %d\n", request->Value)); TRACE(("usb_uhci_roothub: set address: %d\n", request->Value));
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
case USB_REQUEST_GET_DESCRIPTOR: case USB_REQUEST_GET_DESCRIPTOR:
@ -182,7 +181,7 @@ UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
transfer->DataLength()); transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubDevice, memcpy(transfer->Data(), (void *)&sUHCIRootHubDevice,
actualLength); actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -191,7 +190,7 @@ UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
transfer->DataLength()); transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig, memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig,
actualLength); actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -204,7 +203,7 @@ UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
transfer->DataLength()); transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubStrings[index], memcpy(transfer->Data(), (void *)&sUHCIRootHubStrings[index],
actualLength); actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -213,14 +212,14 @@ UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
transfer->DataLength()); transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig.hub, memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig.hub,
actualLength); actualLength);
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
} }
break; break;
case USB_REQUEST_SET_CONFIGURATION: case USB_REQUEST_SET_CONFIGURATION:
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
case USB_REQUEST_CLEAR_FEATURE: { case USB_REQUEST_CLEAR_FEATURE: {
@ -232,7 +231,7 @@ UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
TRACE(("usb_uhci_roothub: clear feature: %d\n", request->Value)); TRACE(("usb_uhci_roothub: clear feature: %d\n", request->Value));
if (uhci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK) if (uhci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
@ -245,7 +244,7 @@ UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
TRACE(("usb_uhci_roothub: set feature: %d!\n", request->Value)); TRACE(("usb_uhci_roothub: set feature: %d!\n", request->Value));
if (uhci->SetPortFeature(request->Index - 1, request->Value) >= B_OK) if (uhci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS; status = B_OK;
break; break;
} }
} }

View File

@ -99,12 +99,13 @@ usb_raw_device_removed(void *cookie)
gDeviceCount--; gDeviceCount--;
benaphore_unlock(&gDeviceListLock); benaphore_unlock(&gDeviceListLock);
benaphore_lock(&device->lock);
device->device = 0; device->device = 0;
benaphore_destroy(&device->lock); if (device->reference_count == 0) {
delete_sem(device->notify); benaphore_lock(&device->lock);
if (device->reference_count == 0) benaphore_destroy(&device->lock);
delete_sem(device->notify);
free(device); free(device);
}
return B_OK; return B_OK;
} }
@ -123,12 +124,6 @@ usb_raw_open(const char *name, uint32 flags, void **cookie)
raw_device *element = gDeviceList; raw_device *element = gDeviceList;
while (element) { while (element) {
if (strcmp(name, element->name) == 0) { if (strcmp(name, element->name) == 0) {
if (element->reference_count > 0) {
// device is already open
benaphore_unlock(&gDeviceListLock);
return B_BUSY;
}
element->reference_count++; element->reference_count++;
*cookie = element; *cookie = element;
benaphore_unlock(&gDeviceListLock); benaphore_unlock(&gDeviceListLock);
@ -159,8 +154,12 @@ usb_raw_free(void *cookie)
raw_device *device = (raw_device *)cookie; raw_device *device = (raw_device *)cookie;
device->reference_count--; device->reference_count--;
if (device->device == 0) if (device->device == 0) {
benaphore_lock(&device->lock);
benaphore_destroy(&device->lock);
delete_sem(device->notify);
free(device); free(device);
}
benaphore_unlock(&gDeviceListLock); benaphore_unlock(&gDeviceListLock);
return B_OK; return B_OK;
@ -168,27 +167,27 @@ usb_raw_free(void *cookie)
static void static void
usb_raw_callback(void *cookie, uint32 status, void *data, size_t actualLength) usb_raw_callback(void *cookie, status_t status, void *data, size_t actualLength)
{ {
TRACE((DRIVER_NAME": callback()\n")); TRACE((DRIVER_NAME": callback()\n"));
raw_device *device = (raw_device *)cookie; raw_device *device = (raw_device *)cookie;
switch (status) { switch (status) {
case B_USB_STATUS_SUCCESS: case B_OK:
device->status = RAW_STATUS_SUCCESS; device->status = RAW_STATUS_SUCCESS;
break; break;
case B_USB_STATUS_DEVICE_CRC_ERROR: case B_TIMED_OUT:
device->status = RAW_STATUS_CRC_ERROR;
break;
case B_USB_STATUS_DEVICE_TIMEOUT:
device->status = RAW_STATUS_TIMEOUT; device->status = RAW_STATUS_TIMEOUT;
break; break;
case B_USB_STATUS_DEVICE_STALLED: case B_CANCELED:
device->status = RAW_STATUS_STALLED;
break;
case B_USB_STATUS_IRP_CANCELLED_BY_REQUEST:
device->status = RAW_STATUS_ABORTED; device->status = RAW_STATUS_ABORTED;
break; break;
case B_DEV_CRC_ERROR:
device->status = RAW_STATUS_CRC_ERROR;
break;
case B_DEV_STALLED:
device->status = RAW_STATUS_STALLED;
break;
default: default:
device->status = RAW_STATUS_FAILED; device->status = RAW_STATUS_FAILED;
break; break;

View File

@ -592,11 +592,11 @@ usb_callback(void *cookie, uint32 busStatus,
acquire_sem(device->sem_lock); acquire_sem(device->sem_lock);
device->actual_length = actualLength; device->actual_length = actualLength;
device->bus_status = busStatus; /* B_USB_STATUS_* */ device->bus_status = busStatus; /* B_USB_STATUS_* */
if (busStatus != B_USB_STATUS_SUCCESS) { if (busStatus != B_OK) {
/* request failed */ /* request failed */
release_sem(device->sem_lock); release_sem(device->sem_lock);
DPRINTF_ERR((MY_ID "bus status %d\n", (int)busStatus)); DPRINTF_ERR((MY_ID "bus status %d\n", (int)busStatus));
if (busStatus == B_USB_STATUS_IRP_CANCELLED_BY_REQUEST) { if (busStatus == B_CANCELED) {
/* cancelled: device is unplugged */ /* cancelled: device is unplugged */
return; return;
} }

View File

@ -158,11 +158,11 @@ midi_usb_callback(void *cookie, uint32 status,
acquire_sem (my_dev->sem_lock); acquire_sem (my_dev->sem_lock);
my_dev->actual_length = actual_len; my_dev->actual_length = actual_len;
my_dev->bus_status = status; /* B_USB_STATUS_* */ my_dev->bus_status = status; /* B_USB_STATUS_* */
if (status != B_USB_STATUS_SUCCESS) { if (status != B_OK) {
/* request failed */ /* request failed */
release_sem (my_dev->sem_lock); release_sem (my_dev->sem_lock);
DPRINTF_ERR ((MY_ID "bus status %d\n", (int)status)); DPRINTF_ERR ((MY_ID "bus status %d\n", (int)status));
if (status == B_USB_STATUS_IRP_CANCELLED_BY_REQUEST) { if (status == B_CANCELED) {
/* cancelled: device is unplugged */ /* cancelled: device is unplugged */
return; return;
} }