diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index a3bf79aa2e..cd59d52a44 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -363,6 +363,9 @@ OHCI::~OHCI() status_t OHCI::Start() { + if (InitCheck()) + return B_ERROR; + if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_OPERATIONAL)) { TRACE(("USB OHCI::Start(): Controller not started. TODO: find out what happens.\n")); return B_ERROR; @@ -397,6 +400,25 @@ status_t OHCI::SubmitTransfer( Transfer *t ) return B_ERROR; } +status_t +OHCI::NotifyPipeChange(Pipe *pipe, usb_change change) +{ + if (InitCheck()) + return B_ERROR; + + switch (change) { + case USB_CHANGE_CREATED: + return InsertEndpointForPipe(pipe); + case USB_CHANGE_DESTROYED: + // Do something + return B_ERROR; + case USB_CHANGE_PIPE_POLICY_CHANGED: + default: + break; + } + return B_ERROR; //We should never go here +} + status_t OHCI::GetPortStatus(uint8 index, usb_port_status *status) { @@ -481,7 +503,8 @@ OHCI::ClearPortFeature(uint8 index, uint16 feature) Endpoint * OHCI::AllocateEndpoint() { - Endpoint *endpoint = new Endpoint; + //Allocate memory chunk + Endpoint *endpoint = new(std::nothrow) Endpoint; void *phy; if (fStack->AllocateChunk((void **)&endpoint->ed, &phy, sizeof(ohci_endpoint_descriptor)) != B_OK) { TRACE(("OHCI::AllocateEndpoint(): Error Allocating Endpoint\n")); @@ -489,8 +512,15 @@ OHCI::AllocateEndpoint() } endpoint->physicaladdress = (addr_t)phy; + //Initialize the physical part memset((void *)endpoint->ed, 0, sizeof(ohci_endpoint_descriptor)); - endpoint->ed->ed_flags = OHCI_ED_SKIP; + endpoint->ed->flags = OHCI_ENDPOINT_SKIP; + + //Add a NULL list by creating one TransferDescriptor + TransferDescriptor *trans = new(std::nothrow) TransferDescriptor; + endpoint->head = endpoint->tail = trans; + endpoint->ed->headp = endpoint->ed->tailp = trans->physicaladdress; + return endpoint; } @@ -501,6 +531,122 @@ OHCI::FreeEndpoint(Endpoint *end) delete end; } +TransferDescriptor * +OHCI::AllocateTransfer() +{ + TransferDescriptor *transfer = new TransferDescriptor; + void *phy; + if (fStack->AllocateChunk((void **)&transfer->td, &phy, sizeof(ohci_transfer_descriptor)) != B_OK) { + TRACE(("OHCI::AllocateTransfer(): Error Allocating Transfer\n")); + return 0; + } + transfer->physicaladdress = (addr_t)phy; + memset((void *)transfer->td, 0, sizeof(ohci_transfer_descriptor)); + return transfer; +} + +void +OHCI::FreeTransfer(TransferDescriptor *trans) +{ + fStack->FreeChunk((void *)trans->td, (void *) trans->physicaladdress, sizeof(ohci_transfer_descriptor)); + delete trans; +} + +status_t +OHCI::InsertEndpointForPipe(Pipe *p) +{ + TRACE(("OHCI: Inserting Endpoint for device %u function %u\n", p->DeviceAddress(), p->EndpointAddress())); + + if (InitCheck()) + return B_ERROR; + + Endpoint *endpoint = AllocateEndpoint(); + if (!endpoint) + return B_NO_MEMORY; + + //Set up properties of the endpoint + //TODO: does this need its own utility function? + { + uint32 properties = 0; + + //Set the device address + properties |= OHCI_ENDPOINT_SET_FA(p->DeviceAddress()); + + //Set the endpoint number + properties |= OHCI_ENDPOINT_SET_EN(p->EndpointAddress()); + + //Set the direction + switch (p->Direction()) { + case Pipe::In: + properties |= OHCI_ENDPOINT_DIR_IN; + break; + case Pipe::Out: + properties |= OHCI_ENDPOINT_DIR_OUT; + break; + case Pipe::Default: + properties |= OHCI_ENDPOINT_DIR_TD; + break; + default: + //TODO: error + break; + } + + //Set the speed + switch (p->Speed()) { + case USB_SPEED_LOWSPEED: + //the bit is 0 + break; + case USB_SPEED_FULLSPEED: + properties |= OHCI_ENDPOINT_SPEED; + break; + case USB_SPEED_HIGHSPEED: + default: + //TODO: error + break; + } + + //Assign the format. Isochronous endpoints require this switch + if (p->Type() & USB_OBJECT_ISO_PIPE) + properties |= OHCI_ENDPOINT_FORMAT_ISO; + + //Set the maximum packet size + properties |= OHCI_ENDPOINT_SET_MAXP(p->MaxPacketSize()); + + endpoint->ed->flags = properties; + } + + //Check which list we need to add the endpoint in + Endpoint *listhead; + switch (p->Type()) { + case USB_OBJECT_CONTROL_PIPE: + listhead = fDummyControl; + break; + case USB_OBJECT_BULK_PIPE: + listhead = fDummyBulk; + break; + case USB_OBJECT_ISO_PIPE: + listhead = fDummyIsochronous; + break; + default: + FreeEndpoint(endpoint); + return B_ERROR; + } + + //Add the endpoint to the queues + if (p->Type() != USB_OBJECT_ISO_PIPE) { + //Link the endpoint into the head of the list + endpoint->SetNext(listhead->next); + listhead->SetNext(endpoint); + } else { + //Link the endpoint into the tail of the list + Endpoint *tail = listhead; + while (tail->next != 0) + tail = tail->next; + tail->SetNext(endpoint); + } + + return B_OK; +} pci_module_info *OHCI::pci_module = 0; diff --git a/src/add-ons/kernel/busses/usb/ohci.h b/src/add-ons/kernel/busses/usb/ohci.h index c23bb36eba..c9a0fda9aa 100644 --- a/src/add-ons/kernel/busses/usb/ohci.h +++ b/src/add-ons/kernel/busses/usb/ohci.h @@ -34,7 +34,8 @@ struct pci_info; struct pci_module_info; class OHCIRootHub; -class Endpoint; +struct Endpoint; +struct TransferDescriptor; // -------------------------------- // OHCI: The OHCI class derived @@ -50,6 +51,9 @@ public: ~OHCI(); status_t Start(); status_t SubmitTransfer(Transfer *t); //Override from BusManager. + status_t NotifyPipeChange(Pipe *pipe, //Override from BusManager. + usb_change change); + static pci_module_info *pci_module; // Global data for the module. status_t GetPortStatus(uint8 index, usb_port_status *status); @@ -81,7 +85,11 @@ private: uint8 fNumPorts; // the number of ports // functions Endpoint *AllocateEndpoint(); // allocate memory for an endpoint - void FreeEndpoint(Endpoint *end); //Free endpoint + void FreeEndpoint(Endpoint *end); // Free endpoint + TransferDescriptor *AllocateTransfer(); // create a NULL transfer + void FreeTransfer(TransferDescriptor *trans); // Free transfer + + status_t InsertEndpointForPipe(Pipe *p); }; // -------------------------------- @@ -106,12 +114,25 @@ struct Endpoint addr_t physicaladdress;//Point to the physical address ohci_endpoint_descriptor *ed; //Logical 'endpoint' Endpoint *next; //Pointer to the 'next' endpoint + TransferDescriptor *head, *tail; //Pointers to the 'head' and 'tail' transfer descriptors //Utility functions void SetNext(Endpoint *end) { next = end; - ed->next_endpoint = end->physicaladdress; + if (end == 0) + ed->next_endpoint = 0; + else + ed->next_endpoint = end->physicaladdress; }; + + //Constructor (or better: initialiser) + Endpoint() : physicaladdress(0), ed(0), next(0), head(0), tail(0) {}; +}; + +struct TransferDescriptor +{ + addr_t physicaladdress; + ohci_transfer_descriptor *td; }; #endif // OHCI_H diff --git a/src/add-ons/kernel/busses/usb/ohci_hardware.h b/src/add-ons/kernel/busses/usb/ohci_hardware.h index b5276109fd..89e1447179 100644 --- a/src/add-ons/kernel/busses/usb/ohci_hardware.h +++ b/src/add-ons/kernel/busses/usb/ohci_hardware.h @@ -296,42 +296,41 @@ struct ohci_hcca typedef struct ohci_endpoint_descriptor { - uint32 ed_flags; - addr_t ed_qtailp; // Queue tail pointer - addr_t ed_qheadp; // Queue head pointer + uint32 flags; + addr_t tailp; // Queue tail pointer + addr_t headp; // Queue head pointer addr_t next_endpoint; // Next endpoint in the list }; -#define OHCI_ED_GET_FA(s) ((s) & 0x7f) -#define OHCI_ED_ADDRMASK 0x0000007f -#define OHCI_ED_SET_FA(s) (s) -#define OHCI_ED_GET_EN(s) (((s) >> 7) & 0xf) -#define OHCI_ED_SET_EN(s) ((s) << 7) -#define OHCI_ED_DIR_MASK 0x00001800 -#define OHCI_ED_DIR_TD 0x00000000 -#define OHCI_ED_DIR_OUT 0x00000800 -#define OHCI_ED_DIR_IN 0x00001000 -#define OHCI_ED_SPEED 0x00002000 -#define OHCI_ED_SKIP 0x00004000 -#define OHCI_ED_FORMAT_GEN 0x00000000 -#define OHCI_ED_FORMAT_ISO 0x00008000 -#define OHCI_ED_GET_MAXP(s) (((s) >> 16) & 0x07ff) -#define OHCI_ED_SET_MAXP(s) ((s) << 16) -#define OHCI_ED_MAXPMASK (0x7ff << 16) +#define OHCI_ENDPOINT_GET_FA(s) ((s) & 0x7f) +#define OHCI_ENDPOINT_ADDRMASK 0x0000007f +#define OHCI_ENDPOINT_SET_FA(s) (s) +#define OHCI_ENDPOINT_GET_EN(s) (((s) >> 7) & 0xf) +#define OHCI_ENDPOINT_SET_EN(s) ((s) << 7) +#define OHCI_ENDPOINT_DIR_MASK 0x00001800 +#define OHCI_ENDPOINT_DIR_TD 0x00000000 +#define OHCI_ENDPOINT_DIR_OUT 0x00000800 +#define OHCI_ENDPOINT_DIR_IN 0x00001000 +#define OHCI_ENDPOINT_SPEED 0x00002000 +#define OHCI_ENDPOINT_SKIP 0x00004000 +#define OHCI_ENDPOINT_FORMAT_GEN 0x00000000 +#define OHCI_ENDPOINT_FORMAT_ISO 0x00008000 +#define OHCI_ENDPOINT_GET_MAXP(s) (((s) >> 16) & 0x07ff) +#define OHCI_ENDPOINT_SET_MAXP(s) ((s) << 16) +#define OHCI_ENDPOINT_MAXPMASK (0x7ff << 16) #define OHCI_HALTED 0x00000001 #define OHCI_TOGGLECARRY 0x00000002 #define OHCI_HEADMASK 0xfffffffc -#define OHCI_ED_ALIGN 16 // -------------------------------- // General transfer descriptor structure (section 4.3.1) // -------------------------------- -typedef struct hc_transfer_descriptor +typedef struct ohci_transfer_descriptor { - uint32 td_flags; + uint32 flags; addr_t td_cbp; // Current Buffer Pointer addr_t td_nexttd; // Next Transfer Descriptor addr_t td_be; // Buffer End diff --git a/src/add-ons/kernel/busses/usb/ohci_software.h b/src/add-ons/kernel/busses/usb/ohci_software.h index fb8dfdda03..ebb8893c87 100644 --- a/src/add-ons/kernel/busses/usb/ohci_software.h +++ b/src/add-ons/kernel/busses/usb/ohci_software.h @@ -32,28 +32,6 @@ #include "ohci_hardware.h" -// ------------------------------------ -// OHCI:: Software general -// transfer descriptor -// ------------------------------------ - -typedef struct hcd_soft_transfer -{ - hc_transfer_descriptor td; - struct hcd_soft_transfer *nexttd; // mirrors nexttd in TD - struct hcd_soft_trasfer *dnext; // next in done list - addr_t physaddr; // physical address to the host controller transfer - //LIST_ENTRY(hcd_soft_transfer) hnext; - uint16 len; // the lenght - uint16 flags; // flags -}hcd_soft_transfer; - -#define OHCI_CALL_DONE 0x0001 -#define OHCI_ADD_LEN 0x0002 - -#define OHCI_STD_SIZE ((sizeof (struct hcd_soft_transfer) + OHCI_TD_ALIGN - 1) / OHCI_TD_ALIGN * OHCI_TD_ALIGN) -#define OHCI_STD_CHUNK 128 - // -------------------------------------- // OHCI:: Software isonchronous // transfer descriptor @@ -80,10 +58,5 @@ typedef struct hcd_soft_itransfer #define OHCI_NO_EDS (2*OHCI_NO_INTRS-1) -// -------------------------- -// OHCI:: Hash size for the -// -------------------------- - -#define OHCI_HASH_SIZE 128 #endif // OHCI_SOFT