add USBHost library

pull/1/head
unknown 2013-03-14 16:12:24 +00:00 committed by samux
parent 444e802b93
commit 1c981f929a
23 changed files with 4953 additions and 0 deletions

View File

@ -0,0 +1,36 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IUSBENUMERATOR_H_
#define IUSBENUMERATOR_H_
#include "stdint.h"
#include "USBEndpoint.h"
/*
Generic interface to implement for "smart" USB enumeration
*/
class IUSBEnumerator
{
public:
virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
};
#endif /*IUSBENUMERATOR_H_*/

View File

@ -0,0 +1,124 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "USBDeviceConnected.h"
#include "dbg.h"
USBDeviceConnected::USBDeviceConnected() {
init();
}
void USBDeviceConnected::init() {
hub_nb = 0;
port = 0;
vid = 0;
pid = 0;
nb_interf = 0;
enumerated = false;
activeAddr = false;
sizeControlEndpoint = 8;
device_class = 0;
device_subclass = 0;
proto = 0;
speed = false;
for (int i = 0; i < MAX_INTF; i++) {
memset((void *)&intf[i], 0, sizeof(INTERFACE));
intf[i].in_use = false;
for (int j = 0; j < MAX_ENDPOINT_PER_INTERFACE; j++) {
intf[i].ep[j] = NULL;
strcpy(intf[i].name, "Unknown");
}
}
hub_parent = NULL;
hub = NULL;
nb_interf = 0;
}
INTERFACE * USBDeviceConnected::getInterface(uint8_t index) {
if (index >= MAX_INTF)
return NULL;
if (intf[index].in_use)
return &intf[index];
return NULL;
}
bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) {
if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use)) {
return false;
}
intf[intf_nb].in_use = true;
intf[intf_nb].intf_class = intf_class;
intf[intf_nb].intf_subclass = intf_subclass;
intf[intf_nb].intf_protocol = intf_protocol;
intf[intf_nb].nb_endpoint = 0;
return true;
}
bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) {
if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use == false) || (intf[intf_nb].nb_endpoint >= MAX_ENDPOINT_PER_INTERFACE)) {
return false;
}
intf[intf_nb].nb_endpoint++;
for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
if (intf[intf_nb].ep[i] == NULL) {
intf[intf_nb].ep[i] = ept;
return true;
}
}
return false;
}
void USBDeviceConnected::init(uint8_t hub_, uint8_t port_, bool lowSpeed_) {
USB_DBG("init dev: %p", this);
init();
hub_nb = hub_;
port = port_;
speed = lowSpeed_;
}
void USBDeviceConnected::disconnect() {
for(int i = 0; i < MAX_INTF; i++) {
intf[i].detach.call();
}
init();
}
USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) {
if (intf_nb >= MAX_INTF) {
return NULL;
}
for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
if ((intf[intf_nb].ep[i]->getType() == type) && (intf[intf_nb].ep[i]->getDir() == dir)) {
if(index) {
index--;
} else {
return intf[intf_nb].ep[i];
}
}
}
return NULL;
}
USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) {
if ((intf_nb >= MAX_INTF) || (index >= MAX_ENDPOINT_PER_INTERFACE)) {
return NULL;
}
return intf[intf_nb].ep[index];
}

View File

@ -0,0 +1,185 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBDEVICECONNECTED_H
#define USBDEVICECONNECTED_H
#include "stdint.h"
#include "USBEndpoint.h"
#include "USBHostConf.h"
#include "rtos.h"
class USBHostHub;
typedef struct {
bool in_use;
uint8_t nb_endpoint;
uint8_t intf_class;
uint8_t intf_subclass;
uint8_t intf_protocol;
USBEndpoint * ep[MAX_ENDPOINT_PER_INTERFACE];
FunctionPointer detach;
char name[10];
} INTERFACE;
/**
* USBDeviceConnected class
*/
class USBDeviceConnected
{
public:
/**
* Constructor
*/
USBDeviceConnected();
/**
* Attach an USBEndpoint to this device
*
* @param intf_nb interface number
* @param ep pointeur on the USBEndpoint which will be attached
* @returns true if successful, false otherwise
*/
bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep);
/**
* Retrieve an USBEndpoint by its TYPE and DIRECTION
*
* @param intf_nb the interface on which to lookup the USBEndpoint
* @param type type of the USBEndpoint looked for
* @param dir direction of the USBEndpoint looked for
* @param index the index of the USBEndpoint whitin the interface
* @returns pointer on the USBEndpoint if found, NULL otherwise
*/
USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0);
/**
* Retrieve an USBEndpoint by its index
*
* @param intf_nb interface number
* @param index index of the USBEndpoint
* @returns pointer on the USBEndpoint if found, NULL otherwise
*/
USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index);
/**
* Add a new interface to this device
*
* @param intf_nb interface number
* @param intf_class interface class
* @param intf_subclass interface subclass
* @param intf_protocol interface protocol
* @returns true if successful, false otherwise
*/
bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol);
/**
* Get a specific interface
*
* @param index index of the interface to be fetched
* @returns interface
*/
INTERFACE * getInterface(uint8_t index);
/**
* Attach a member function to call when a the device has been disconnected
*
* @param intf_nb interface number
* @param tptr pointer to the object to call the member function on
* @param mptr pointer to the member function to be called
*/
template<typename T>
inline void onDisconnect(uint8_t intf_nb, T* tptr, void (T::*mptr)(void)) {
if ((mptr != NULL) && (tptr != NULL)) {
intf[intf_nb].detach.attach(tptr, mptr);
}
}
/**
* Attach a callback called when the device has been disconnected
*
* @param intf_nb interface number
* @param fn function pointer
*/
inline void onDisconnect(uint8_t intf_nb, void (*fn)(void)) {
if (fn != NULL) {
intf[intf_nb].detach.attach(fn);
}
}
/**
* Disconnect the device by calling a callback function registered by a driver
*/
void disconnect();
// setters
void init(uint8_t hub, uint8_t port, bool lowSpeed);
inline void setAddress(uint8_t addr_) { addr = addr_; };
inline void setVid(uint16_t vid_) { vid = vid_; };
inline void setPid(uint16_t pid_) { pid = pid_; };
inline void setClass(uint8_t device_class_) { device_class = device_class_; };
inline void setSubClass(uint8_t device_subclass_) { device_subclass = device_subclass_; };
inline void setProtocol(uint8_t pr) { proto = pr; };
inline void setSizeControlEndpoint(uint32_t size) { sizeControlEndpoint = size; };
inline void activeAddress(bool active) { activeAddr = active; };
inline void setEnumerated() { enumerated = true; };
inline void setNbIntf(uint8_t nb_intf) {nb_interf = nb_intf; };
inline void setHubParent(USBHostHub * hub) { hub_parent = hub; };
inline void setName(const char * name_, uint8_t intf_nb) { strcpy(intf[intf_nb].name, name_); };
//getters
inline uint8_t getPort() { return port; };
inline uint8_t getHub() { return hub_nb; };
inline uint8_t getAddress() { return addr; };
inline uint16_t getVid() { return vid; };
inline uint16_t getPid() { return pid; };
inline uint8_t getClass() { return device_class; };
inline uint8_t getSubClass() { return device_subclass; };
inline uint8_t getProtocol() { return proto; };
inline bool getSpeed() { return speed; };
inline uint32_t getSizeControlEndpoint() { return sizeControlEndpoint; };
inline bool isActiveAddress() { return activeAddr; };
inline bool isEnumerated() { return enumerated; };
inline USBHostHub * getHubParent() { return hub_parent; };
inline uint8_t getNbIntf() { return nb_interf; };
inline const char * getName(uint8_t intf_nb) { return intf[intf_nb].name; };
// in case this device is a hub
USBHostHub * hub;
private:
USBHostHub * hub_parent;
INTERFACE intf[MAX_INTF];
uint32_t sizeControlEndpoint;
uint8_t hub_nb;
uint8_t port;
uint16_t vid;
uint16_t pid;
uint8_t addr;
uint8_t device_class;
uint8_t device_subclass;
uint8_t proto;
bool speed;
volatile bool activeAddr;
volatile bool enumerated;
uint8_t nb_interf;
void init();
};
#endif

View File

@ -0,0 +1,162 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dbg.h"
#include "USBEndpoint.h"
void USBEndpoint::init(HCED * hced_, ENDPOINT_TYPE type_, ENDPOINT_DIRECTION dir_, uint32_t size, uint8_t ep_number, HCTD* td_list_[2])
{
hced = hced_;
type = type_;
dir = dir_;
setup = (type == CONTROL_ENDPOINT) ? true : false;
//TDs have been allocated by the host
memcpy((HCTD**)td_list, td_list_, sizeof(HCTD*)*2); //TODO: Maybe should add a param for td_list size... at least a define
memcpy(td_list_[0], 0, sizeof(HCTD));
memcpy(td_list_[1], 0, sizeof(HCTD));
td_list[0]->ep = this;
td_list[1]->ep = this;
hced->control = 0;
//Empty queue
hced->tailTD = td_list[0];
hced->headTD = td_list[0];
hced->nextED = 0;
address = (ep_number & 0x7F) | ((dir - 1) << 7);
hced->control = ((ep_number & 0x7F) << 7) // Endpoint address
| (type != CONTROL_ENDPOINT ? ( dir << 11) : 0 ) // direction : Out = 1, 2 = In
| ((size & 0x3ff) << 16); // MaxPkt Size
transfer_len = 0;
transferred = 0;
buf_start = 0;
nextEp = NULL;
td_current = td_list[0];
td_next = td_list[1];
intf_nb = 0;
state = USB_TYPE_IDLE;
}
void USBEndpoint::setSize(uint32_t size)
{
hced->control &= ~(0x3ff << 16);
hced->control |= (size << 16);
}
void USBEndpoint::setDeviceAddress(uint8_t addr)
{
hced->control &= ~(0x7f);
hced->control |= (addr & 0x7F);
}
void USBEndpoint::setSpeed(uint8_t speed)
{
hced->control &= ~(1 << 13);
hced->control |= (speed << 13);
}
//Only for control Eps
void USBEndpoint::setNextToken(uint32_t token)
{
switch (token) {
case TD_SETUP:
dir = OUT;
setup = true;
break;
case TD_IN:
dir = IN;
setup = false;
break;
case TD_OUT:
dir = OUT;
setup = false;
break;
}
}
struct {
USB_TYPE type;
const char * str;
} static type_string[] = {
/*0*/ {USB_TYPE_OK, "USB_TYPE_OK"},
{USB_TYPE_CRC_ERROR, "USB_TYPE_CRC_ERROR"},
{USB_TYPE_BIT_STUFFING_ERROR, "USB_TYPE_BIT_STUFFING_ERROR"},
{USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR, "USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR"},
{USB_TYPE_STALL_ERROR, "USB_TYPE_STALL_ERROR"},
/*5*/ {USB_TYPE_DEVICE_NOT_RESPONDING_ERROR, "USB_TYPE_DEVICE_NOT_RESPONDING_ERROR"},
{USB_TYPE_PID_CHECK_FAILURE_ERROR, "USB_TYPE_PID_CHECK_FAILURE_ERROR"},
{USB_TYPE_UNEXPECTED_PID_ERROR, "USB_TYPE_UNEXPECTED_PID_ERROR"},
{USB_TYPE_DATA_OVERRUN_ERROR, "USB_TYPE_DATA_OVERRUN_ERROR"},
{USB_TYPE_DATA_UNDERRUN_ERROR, "USB_TYPE_DATA_UNDERRUN_ERROR"},
/*10*/ {USB_TYPE_ERROR, "USB_TYPE_ERROR"},
{USB_TYPE_ERROR, "USB_TYPE_ERROR"},
{USB_TYPE_BUFFER_OVERRUN_ERROR, "USB_TYPE_BUFFER_OVERRUN_ERROR"},
{USB_TYPE_BUFFER_UNDERRUN_ERROR, "USB_TYPE_BUFFER_UNDERRUN_ERROR"},
{USB_TYPE_DISCONNECTED, "USB_TYPE_DISCONNECTED"},
/*15*/ {USB_TYPE_FREE, "USB_TYPE_FREE"},
{USB_TYPE_IDLE, "USB_TYPE_IDLE"},
{USB_TYPE_PROCESSING, "USB_TYPE_PROCESSING"},
{USB_TYPE_ERROR, "USB_TYPE_ERROR"}
};
void USBEndpoint::setState(uint8_t st) {
if (st > 18)
return;
state = type_string[st].type;
}
const char * USBEndpoint::getStateString() {
return type_string[state].str;
}
void USBEndpoint::queueTransfer()
{
transfer_len = (uint32_t)td_current->bufEnd - (uint32_t)td_current->currBufPtr + 1;
transferred = transfer_len;
buf_start = (uint8_t *)td_current->currBufPtr;
//Now add this free TD at this end of the queue
state = USB_TYPE_PROCESSING;
td_current->nextTD = td_next;
hced->tailTD = td_next;
}
void USBEndpoint::unqueueTransfer(volatile HCTD * td)
{
td->control=0;
td->currBufPtr=0;
td->bufEnd=0;
td->nextTD=0;
hced->headTD = (HCTD *)((uint32_t)hced->tailTD | ((uint32_t)hced->headTD & 0x2)); //Carry bit
td_current = td_next;
td_next = td;
}
void USBEndpoint::queueEndpoint(USBEndpoint * ed)
{
nextEp = ed;
hced->nextED = (ed == NULL) ? 0 : ed->getHCED();
}

View File

@ -0,0 +1,171 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBENDPOINT_H
#define USBENDPOINT_H
#include "FunctionPointer.h"
#include "USBHostTypes.h"
#include "rtos.h"
class USBDeviceConnected;
/**
* USBEndpoint class
*/
class USBEndpoint
{
public:
/**
* Constructor
*/
USBEndpoint() {
state = USB_TYPE_FREE;
nextEp = NULL;
};
/**
* Initialize an endpoint
*
* @param hced hced associated to the endpoint
* @param type endpoint type
* @param dir endpoint direction
* @param size endpoint size
* @param ep_number endpoint number
* @param td_list array of two allocated transfer descriptors
*/
void init(HCED * hced, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t ep_number, HCTD* td_list[2]);
/**
* Set next token. Warning: only useful for the control endpoint
*
* @param token IN, OUT or SETUP token
*/
void setNextToken(uint32_t token);
/**
* Queue an endpoint
*
* @param endpoint endpoint which will be queued in the linked list
*/
void queueEndpoint(USBEndpoint * endpoint);
/**
* Queue a transfer on the endpoint
*/
void queueTransfer();
/**
* Unqueue a transfer from the endpoint
*
* @param td hctd which will be unqueued
*/
void unqueueTransfer(volatile HCTD * td);
/**
* Attach a member function to call when a transfer is finished
*
* @param tptr pointer to the object to call the member function on
* @param mptr pointer to the member function to be called
*/
template<typename T>
inline void attach(T* tptr, void (T::*mptr)(void)) {
if((mptr != NULL) && (tptr != NULL)) {
rx.attach(tptr, mptr);
}
}
/**
* Attach a callback called when a transfer is finished
*
* @param fptr function pointer
*/
inline void attach(void (*fptr)(void)) {
if(fptr != NULL) {
rx.attach(fptr);
}
}
/**
* Call the handler associted to the end of a transfer
*/
inline void call() {
rx.call();
};
// setters
inline void setState(USB_TYPE st) { state = st; }
void setState(uint8_t st);
void setDeviceAddress(uint8_t addr);
inline void setLengthTransferred(int len) { transferred = len; };
void setSpeed(uint8_t speed);
void setSize(uint32_t size);
inline void setDir(ENDPOINT_DIRECTION d) { dir = d; }
inline void setIntfNb(uint8_t intf_nb_) { intf_nb = intf_nb_; };
// getters
const char * getStateString();
inline USB_TYPE getState() { return state; }
inline ENDPOINT_TYPE getType() { return type; };
inline uint8_t getDeviceAddress() { return hced->control & 0x7f; };
inline int getLengthTransferred() { return transferred; }
inline uint8_t * getBufStart() { return buf_start; }
inline uint8_t getAddress(){ return address; };
inline uint32_t getSize() { return (hced->control >> 16) & 0x3ff; };
inline volatile HCTD * getHeadTD() { return (volatile HCTD*) ((uint32_t)hced->headTD & ~0xF); };
inline volatile HCTD** getTDList() { return td_list; };
inline volatile HCED * getHCED() { return hced; };
inline ENDPOINT_DIRECTION getDir() { return dir; }
inline volatile HCTD * getProcessedTD() { return td_current; };
inline volatile HCTD* getNextTD() { return td_current; };
inline bool isSetup() { return setup; }
inline USBEndpoint * nextEndpoint() { return (USBEndpoint*)nextEp; };
inline uint8_t getIntfNb() { return intf_nb; };
USBDeviceConnected * dev;
Queue<uint8_t, 1> ep_queue;
private:
ENDPOINT_TYPE type;
volatile USB_TYPE state;
ENDPOINT_DIRECTION dir;
bool setup;
uint8_t address;
int transfer_len;
int transferred;
uint8_t * buf_start;
FunctionPointer rx;
USBEndpoint* nextEp;
// USBEndpoint descriptor
volatile HCED * hced;
volatile HCTD * td_list[2];
volatile HCTD * td_current;
volatile HCTD * td_next;
uint8_t intf_nb;
};
#endif

View File

@ -0,0 +1,322 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "USBHALHost.h"
#include "dbg.h"
// bits of the USB/OTG clock control register
#define HOST_CLK_EN (1<<0)
#define DEV_CLK_EN (1<<1)
#define PORTSEL_CLK_EN (1<<3)
#define AHB_CLK_EN (1<<4)
// bits of the USB/OTG clock status register
#define HOST_CLK_ON (1<<0)
#define DEV_CLK_ON (1<<1)
#define PORTSEL_CLK_ON (1<<3)
#define AHB_CLK_ON (1<<4)
// we need host clock, OTG/portsel clock and AHB clock
#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
#define HCCA_SIZE sizeof(HCCA)
#define ED_SIZE sizeof(HCED)
#define TD_SIZE sizeof(HCTD)
#define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
static volatile __align(256) uint8_t usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned)); //256 bytes aligned!
USBHALHost * USBHALHost::instHost;
USBHALHost::USBHALHost() {
instHost = this;
memInit();
memset((void*)usb_hcca, 0, HCCA_SIZE);
for (int i = 0; i < MAX_ENDPOINT; i++) {
edBufAlloc[i] = false;
}
for (int i = 0; i < MAX_TD; i++) {
tdBufAlloc[i] = false;
}
}
void USBHALHost::init() {
NVIC_DisableIRQ(USB_IRQn);
//Cut power
LPC_SC->PCONP &= ~(1UL<<31);
wait_ms(100);
// turn on power for USB
LPC_SC->PCONP |= (1UL<<31);
// Enable USB host clock, port selection and AHB clock
LPC_USB->USBClkCtrl |= CLOCK_MASK;
// Wait for clocks to become available
while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK);
// it seems the bits[0:1] mean the following
// 0: U1=device, U2=host
// 1: U1=host, U2=host
// 2: reserved
// 3: U1=host, U2=device
// NB: this register is only available if OTG clock (aka "port select") is enabled!!
// since we don't care about port 2, set just bit 0 to 1 (U1=host)
LPC_USB->OTGStCtrl |= 1;
// now that we've configured the ports, we can turn off the portsel clock
LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
// configure USB D+/D- pins
// P0[29] = USB_D+, 01
// P0[30] = USB_D-, 01
LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));
LPC_PINCON->PINSEL1 |= ((1<<26) | (1<<28));
LPC_USB->HcControl = 0; // HARDWARE RESET
LPC_USB->HcControlHeadED = 0; // Initialize Control list head to Zero
LPC_USB->HcBulkHeadED = 0; // Initialize Bulk list head to Zero
// Wait 100 ms before apply reset
wait_ms(100);
// software reset
LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
// Write Fm Interval and Largest Data Packet Counter
LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL;
LPC_USB->HcPeriodicStart = FI * 90 / 100;
// Put HC in operational state
LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
// Set Global Power
LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;
LPC_USB->HcHCCA = (uint32_t)(usb_hcca);
// Clear Interrrupt Status
LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;
LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC;
// Enable the USB Interrupt
NVIC_SetVector(USB_IRQn, (uint32_t)(_usbisr));
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
NVIC_EnableIRQ(USB_IRQn);
// Check for any connected devices
if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) {
//Device connected
wait_ms(150);
USB_DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus1);
deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA);
}
}
uint32_t USBHALHost::controlHeadED() {
return LPC_USB->HcControlHeadED;
}
uint32_t USBHALHost::bulkHeadED() {
return LPC_USB->HcBulkHeadED;
}
uint32_t USBHALHost::interruptHeadED() {
return usb_hcca->IntTable[0];
}
void USBHALHost::updateBulkHeadED(uint32_t addr) {
LPC_USB->HcBulkHeadED = addr;
}
void USBHALHost::updateControlHeadED(uint32_t addr) {
LPC_USB->HcControlHeadED = addr;
}
void USBHALHost::updateInterruptHeadED(uint32_t addr) {
usb_hcca->IntTable[0] = addr;
}
void USBHALHost::enableList(ENDPOINT_TYPE type) {
switch(type) {
case CONTROL_ENDPOINT:
LPC_USB->HcCommandStatus = OR_CMD_STATUS_CLF;
LPC_USB->HcControl |= OR_CONTROL_CLE;
break;
case ISOCHRONOUS_ENDPOINT:
break;
case BULK_ENDPOINT:
LPC_USB->HcCommandStatus = OR_CMD_STATUS_BLF;
LPC_USB->HcControl |= OR_CONTROL_BLE;
break;
case INTERRUPT_ENDPOINT:
LPC_USB->HcControl |= OR_CONTROL_PLE;
break;
}
}
bool USBHALHost::disableList(ENDPOINT_TYPE type) {
switch(type) {
case CONTROL_ENDPOINT:
if(LPC_USB->HcControl & OR_CONTROL_CLE) {
LPC_USB->HcControl &= ~OR_CONTROL_CLE;
return true;
}
return false;
case ISOCHRONOUS_ENDPOINT:
return false;
case BULK_ENDPOINT:
if(LPC_USB->HcControl & OR_CONTROL_BLE){
LPC_USB->HcControl &= ~OR_CONTROL_BLE;
return true;
}
return false;
case INTERRUPT_ENDPOINT:
if(LPC_USB->HcControl & OR_CONTROL_PLE) {
LPC_USB->HcControl &= ~OR_CONTROL_PLE;
return true;
}
return false;
}
return false;
}
void USBHALHost::memInit() {
usb_hcca = (volatile HCCA *)usb_buf;
usb_edBuf = usb_buf + HCCA_SIZE;
usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE);
}
volatile uint8_t * USBHALHost::getED() {
for (int i = 0; i < MAX_ENDPOINT; i++) {
if ( !edBufAlloc[i] ) {
edBufAlloc[i] = true;
return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE);
}
}
perror("Could not allocate ED\r\n");
return NULL; //Could not alloc ED
}
volatile uint8_t * USBHALHost::getTD() {
int i;
for (i = 0; i < MAX_TD; i++) {
if ( !tdBufAlloc[i] ) {
tdBufAlloc[i] = true;
return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE);
}
}
perror("Could not allocate TD\r\n");
return NULL; //Could not alloc TD
}
void USBHALHost::freeED(volatile uint8_t * ed) {
int i;
i = (ed - usb_edBuf) / ED_SIZE;
edBufAlloc[i] = false;
}
void USBHALHost::freeTD(volatile uint8_t * td) {
int i;
i = (td - usb_tdBuf) / TD_SIZE;
tdBufAlloc[i] = false;
}
void USBHALHost::resetRootHub() {
// Initiate port reset
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS;
while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS);
// ...and clear port reset signal
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
}
void USBHALHost::_usbisr(void) {
if (instHost) {
instHost->UsbIrqhandler();
}
}
void USBHALHost::UsbIrqhandler() {
if( LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable ) //Is there something to actually process?
{
uint32_t int_status = LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable;
// Root hub status change interrupt
if (int_status & OR_INTR_STATUS_RHSC) {
if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) {
if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) {
// When DRWE is on, Connect Status Change
// means a remote wakeup event.
} else {
//Root device connected
if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) {
// wait 150ms to avoid bounce
wait_ms(150);
//Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA);
}
//Root device disconnected
else {
if (!(int_status & OR_INTR_STATUS_WDH)) {
usb_hcca->DoneHead = 0;
}
// wait 200ms to avoid bounce
wait_ms(200);
deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE);
if (int_status & OR_INTR_STATUS_WDH) {
usb_hcca->DoneHead = 0;
LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
}
}
}
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
}
if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) {
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
}
LPC_USB->HcInterruptStatus = OR_INTR_STATUS_RHSC;
}
// Writeback Done Head interrupt
if (int_status & OR_INTR_STATUS_WDH) {
transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE);
LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
}
}
}

View File

@ -0,0 +1,169 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBHALHOST_H
#define USBHALHOST_H
#include "USBHostTypes.h"
#include "USBHostConf.h"
class USBHostHub;
/**
* USBHALHost class
*/
class USBHALHost {
protected:
/**
* Constructor
* init variables and memory where will be stored HCCA, ED and TD
*/
USBHALHost();
/**
* Initialize host controller. Enable USB interrupts. This part is not in the constructor because,
* this function calls a virtual method if a device is already connected
*/
void init();
/**
* reset the root hub
*/
void resetRootHub();
/**
* return the value contained in the control HEAD ED register
*
* @returns address of the control Head ED
*/
uint32_t controlHeadED();
/**
* return the value contained in the bulk HEAD ED register
*
* @returns address of the bulk head ED
*/
uint32_t bulkHeadED();
/**
* return the value of the head interrupt ED contained in the HCCA
*
* @returns address of the head interrupt ED contained in the HCCA
*/
uint32_t interruptHeadED();
/**
* Update the head ED for control transfers
*/
void updateControlHeadED(uint32_t addr);
/**
* Update the head ED for bulk transfers
*/
void updateBulkHeadED(uint32_t addr);
/**
* Update the head ED for interrupt transfers
*/
void updateInterruptHeadED(uint32_t addr);
/**
* Enable List for the specified endpoint type
*
* @param type enable the list of ENDPOINT_TYPE type
*/
void enableList(ENDPOINT_TYPE type);
/**
* Disable List for the specified endpoint type
*
* @param type disable the list of ENDPOINT_TYPE type
*/
bool disableList(ENDPOINT_TYPE type);
/**
* Virtual method called when a device has been connected
*
* @param hub hub number of the device
* @param port port number of the device
* @param lowSpeed 1 if low speed, 0 otherwise
* @param hub_parent reference to the hub where the device is connected (NULL if the hub parent is the root hub)
*/
virtual void deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent = NULL) = 0;
/**
* Virtual method called when a device has been disconnected
*
* @param hub hub number of the device
* @param port port number of the device
* @param hub_parent reference to the hub where the device is connected (NULL if the hub parent is the root hub)
* @param addr list of the TDs which have been completed to dequeue freed TDs
*/
virtual void deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr) = 0;
/**
* Virtual method called when a transfer has been completed
*
* @param addr list of the TDs which have been completed
*/
virtual void transferCompleted(volatile uint32_t addr) = 0;
/**
* Find a memory section for a new ED
*
* @returns the address of the new ED
*/
volatile uint8_t * getED();
/**
* Find a memory section for a new TD
*
* @returns the address of the new TD
*/
volatile uint8_t * getTD();
/**
* Release a previous memory section reserved for an ED
*
* @param ed address of the ED
*/
void freeED(volatile uint8_t * ed);
/**
* Release a previous memory section reserved for an TD
*
* @param td address of the TD
*/
void freeTD(volatile uint8_t * td);
private:
static void _usbisr(void);
void UsbIrqhandler();
void memInit();
HCCA volatile * usb_hcca; //256 bytes aligned
uint8_t volatile * usb_edBuf; //4 bytes aligned
uint8_t volatile * usb_tdBuf; //4 bytes aligned
static USBHALHost * instHost;
bool volatile edBufAlloc[MAX_ENDPOINT];
bool volatile tdBufAlloc[MAX_TD];
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,383 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBHOST_H
#define USBHOST_H
#include "USBHALHost.h"
#include "USBDeviceConnected.h"
#include "IUSBEnumerator.h"
#include "USBHostConf.h"
#include "rtos.h"
#include "dbg.h"
#include "USBHostHub.h"
/**
* USBHost class
* This class is a singleton. All drivers have a reference on the static USBHost instance
*/
class USBHost : public USBHALHost {
public:
/**
* Static method to create or retrieve the single USBHost instance
*/
static USBHost * getHostInst();
/**
* Control read: setup stage, data stage and status stage
*
* @param dev the control read will be done for this device
* @param requestType request type
* @param request request
* @param value value
* @param index index
* @param buf pointer on a buffer where will be store the data received
* @param len length of the transfer
*
* @returns status of the control read
*/
USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
/**
* Control write: setup stage, data stage and status stage
*
* @param dev the control write will be done for this device
* @param requestType request type
* @param request request
* @param value value
* @param index index
* @param buf pointer on a buffer which will be written
* @param len length of the transfer
*
* @returns status of the control write
*/
USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
/**
* Bulk read
*
* @param dev the bulk transfer will be done for this device
* @param ep USBEndpoint which will be used to read a packet
* @param buf pointer on a buffer where will be store the data received
* @param len length of the transfer
* @param blocking if true, the read is blocking (wait for completion)
*
* @returns status of the bulk read
*/
USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
/**
* Bulk write
*
* @param dev the bulk transfer will be done for this device
* @param ep USBEndpoint which will be used to write a packet
* @param buf pointer on a buffer which will be written
* @param len length of the transfer
* @param blocking if true, the write is blocking (wait for completion)
*
* @returns status of the bulk write
*/
USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
/**
* Interrupt read
*
* @param dev the bulk transfer will be done for this device
* @param ep USBEndpoint which will be used to write a packet
* @param buf pointer on a buffer which will be written
* @param len length of the transfer
* @param blocking if true, the read is blocking (wait for completion)
*
* @returns status of the interrupt read
*/
USB_TYPE interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
/**
* Interrupt write
*
* @param dev the bulk transfer will be done for this device
* @param ep USBEndpoint which will be used to write a packet
* @param buf pointer on a buffer which will be written
* @param len length of the transfer
* @param blocking if true, the write is blocking (wait for completion)
*
* @returns status of the interrupt write
*/
USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
/**
* Enumerate a device.
*
* @param dev device which will be enumerated
*
* @returns status of the enumeration
*/
USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator);
/**
* reset a specific device
*
* @param dev device which will be resetted
*/
USB_TYPE resetDevice(USBDeviceConnected * dev);
/**
* Get a device
*
* @param index index of the device which will be returned
*
* @returns pointer on the "index" device
*/
USBDeviceConnected * getDevice(uint8_t index);
/*
* If there is a HID device connected, the host stores the length of the report descriptor.
* This avoid to the driver to re-ask the configuration descriptor to request the report descriptor
*
* @returns length of the report descriptor
*/
inline uint16_t getLengthReportDescr() {
return lenReportDescr;
};
/**
* register a driver into the host associated with a callback function called when the device is disconnected
*
* @param dev device
* @param intf interface number
* @param tptr pointer to the object to call the member function on
* @param mptr pointer to the member function to be called
*/
template<typename T>
inline void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) {
int index = findDevice(dev);
if ((index != -1) && (mptr != NULL) && (tptr != NULL)) {
USB_DBG("register driver for dev: %p on intf: %d", dev, intf);
deviceAttachedDriver[index][intf] = true;
dev->onDisconnect(intf, tptr, mptr);
}
}
/**
* register a driver into the host associated with a callback function called when the device is disconnected
*
* @param dev device
* @param intf interface number
* @param fn callback called when the specified device has been disconnected
*/
inline void registerDriver(USBDeviceConnected * dev, uint8_t intf, void (*fn)(void)) {
int index = findDevice(dev);
if ((index != -1) && (fn != NULL)) {
USB_DBG("register driver for dev: %p on intf: %d", dev, intf);
deviceAttachedDriver[index][intf] = true;
dev->onDisconnect(intf, fn);
}
}
friend class USBHostHub;
protected:
/**
* Virtual method called when a transfer has been completed
*
* @param addr list of the TDs which have been completed
*/
virtual void transferCompleted(volatile uint32_t addr);
/**
* Virtual method called when a device has been connected
*
* @param hub hub number of the device
* @param port port number of the device
* @param lowSpeed 1 if low speed, 0 otherwise
* @param hub_parent reference on the parent hub
*/
virtual void deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent = NULL);
/**
* Virtuel method called when a device has been disconnected
*
* @param hub hub number of the device
* @param port port number of the device
* @param addr list of the TDs which have been completed to dequeue freed TDs
*/
virtual void deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr);
private:
// singleton class -> constructor is private
USBHost();
static USBHost * instHost;
uint16_t lenReportDescr;
// endpoints
void unqueueEndpoint(USBEndpoint * ep) ;
USBEndpoint endpoints[MAX_ENDPOINT];
USBEndpoint* volatile control;
USBEndpoint* volatile headControlEndpoint;
USBEndpoint* volatile headBulkEndpoint;
USBEndpoint* volatile headInterruptEndpoint;
USBEndpoint* volatile tailControlEndpoint;
USBEndpoint* volatile tailBulkEndpoint;
USBEndpoint* volatile tailInterruptEndpoint;
bool controlEndpointAllocated;
// devices connected
USBDeviceConnected devices[MAX_DEVICE_CONNECTED];
bool deviceInUse[MAX_DEVICE_CONNECTED];
bool deviceAttachedDriver[MAX_DEVICE_CONNECTED][MAX_INTF];
bool deviceReset[MAX_DEVICE_CONNECTED];
bool deviceInited[MAX_DEVICE_CONNECTED];
#if MAX_HUB_NB
USBHostHub hubs[MAX_HUB_NB];
bool hub_in_use[MAX_HUB_NB];
#endif
// to store a setup packet
uint8_t setupPacket[8];
typedef struct {
uint8_t event_id;
void * td_addr;
uint8_t hub;
uint8_t port;
uint8_t lowSpeed;
uint8_t td_state;
void * hub_parent;
} message_t;
Thread usbThread;
void usb_process();
static void usb_process_static(void const * arg);
Mail<message_t, 10> mail_usb_event;
Mutex usb_mutex;
Mutex td_mutex;
// buffer for conf descriptor
uint8_t data[300];
/**
* Add a transfer on the TD linked list associated to an ED
*
* @param ed the transfer is associated to this ed
* @param buf pointer on a buffer where will be read/write data to send or receive
* @param len transfer length
*
* @return status of the transfer
*/
USB_TYPE addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) ;
/**
* Link the USBEndpoint to the linked list and attach an USBEndpoint this USBEndpoint to a device
*
* @param dev pointer on a USBDeviceConnected object
* @param ep pointer on the USBEndpoint which will be added
*
* return true if successful
*/
bool addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) ;
/**
* Create an USBEndpoint descriptor. Warning: the USBEndpoint is not linked.
*
* @param type USBEndpoint type (CONTROL_ENDPOINT, BULK_ENDPOINT, INTERRUPT_ENDPOINT)
* @param dir USBEndpoint direction (no meaning for CONTROL_ENDPOINT)
* @param size USBEndpoint max packet size
* @param addr USBEndpoint address
*
* @returns pointer on the USBEndpoint created
*/
USBEndpoint * newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) ;
/**
* Request the device descriptor
*
* @param dev request the device descriptor on this device
* @param buf buffer to store the device descriptor
* @param max_len_buf maximum size of buf
* @param len_dev_descr pointer to store the length of the packet transferred
*/
USB_TYPE getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_dev_descr = NULL);
/**
* Request the configuration descriptor
*
* @param dev request the configuration descriptor on this device
* @param buf buffer to store the configuration descriptor
* @param max_len_buf maximum size of buf
* @param len_conf_descr pointer to store the length of the packet transferred
*/
USB_TYPE getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_conf_descr = NULL);
/**
* Set the address of a specific device
*
* @param dev device to set the address
* @param address address
*/
USB_TYPE setAddress(USBDeviceConnected * dev, uint8_t address);
/**
* Set the configuration of a device
*
* @param dev device on which the specified configuration will be activated
* @param conf configuration number to activate (usually 1)
*/
USB_TYPE setConfiguration(USBDeviceConnected * dev, uint8_t conf);
/**
* Free a specific device
*
* @param dev device to be freed
*/
void freeDevice(USBDeviceConnected * dev);
USB_TYPE controlTransfer( USBDeviceConnected * dev,
uint8_t requestType,
uint8_t request,
uint32_t value,
uint32_t index,
uint8_t * buf,
uint32_t len,
bool write);
USB_TYPE generalTransfer( USBDeviceConnected * dev,
USBEndpoint * ep,
uint8_t * buf,
uint32_t len,
bool blocking,
ENDPOINT_TYPE type,
bool write) ;
void fillControlBuf(uint8_t requestType, uint8_t request, uint16_t value, uint16_t index, int len) ;
void parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) ;
int findDevice(USBDeviceConnected * dev) ;
int findDevice(uint8_t hub, uint8_t port, USBHostHub * hub_parent = NULL) ;
uint8_t numberDriverAttached(USBDeviceConnected * dev);
/////////////////////////
/// FOR DEBUG
/////////////////////////
void printList(ENDPOINT_TYPE type);
};
#endif

View File

@ -0,0 +1,81 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBHOST_CONF_H
#define USBHOST_CONF_H
/*
* Maximum number of devices that can be connected
* to the usb host
*/
#define MAX_DEVICE_CONNECTED 5
/*
* Maximum of Hub connected to the usb host
*/
#define MAX_HUB_NB 2
/*
* Maximum number of ports on a USB hub
*/
#define MAX_HUB_PORT 4
/*
* Enable USBHostMSD
*/
#define USBHOST_MSD 1
/*
* Enable USBHostKeyboard
*/
#define USBHOST_KEYBOARD 1
/*
* Enable USBHostMouse
*/
#define USBHOST_MOUSE 1
/*
* Enable USBHostSerial
*/
#define USBHOST_SERIAL 1
/*
* Maximum number of interfaces of a usb device
*/
#define MAX_INTF 3
/*
* Maximum number of endpoints on each interface
*/
#define MAX_ENDPOINT_PER_INTERFACE 3
/*
* Maximum number of endpoint descriptors that can be allocated
*/
#define MAX_ENDPOINT (MAX_DEVICE_CONNECTED * MAX_INTF * MAX_ENDPOINT_PER_INTERFACE)
/*
* Maximum number of transfer descriptors that can be allocated
*/
#define MAX_TD (MAX_ENDPOINT*2)
/*
* usb_thread stack size
*/
#define USB_THREAD_STACK (256*4 + MAX_HUB_NB*256*4)
#endif

View File

@ -0,0 +1,225 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USB_INC_H
#define USB_INC_H
#include "mbed.h"
enum USB_TYPE {
USB_TYPE_OK = 0,
// completion code
USB_TYPE_CRC_ERROR = 1,
USB_TYPE_BIT_STUFFING_ERROR = 2,
USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR = 3,
USB_TYPE_STALL_ERROR = 4,
USB_TYPE_DEVICE_NOT_RESPONDING_ERROR = 5,
USB_TYPE_PID_CHECK_FAILURE_ERROR = 6,
USB_TYPE_UNEXPECTED_PID_ERROR = 7,
USB_TYPE_DATA_OVERRUN_ERROR = 8,
USB_TYPE_DATA_UNDERRUN_ERROR = 9,
USB_TYPE_RESERVED = 9,
USB_TYPE_RESERVED_ = 10,
USB_TYPE_BUFFER_OVERRUN_ERROR = 12,
USB_TYPE_BUFFER_UNDERRUN_ERROR = 13,
// general usb state
USB_TYPE_DISCONNECTED = 14,
USB_TYPE_FREE = 15,
USB_TYPE_IDLE = 16,
USB_TYPE_PROCESSING = 17,
USB_TYPE_ERROR = 18,
};
enum ENDPOINT_DIRECTION {
OUT = 1,
IN
};
enum ENDPOINT_TYPE {
CONTROL_ENDPOINT = 0,
ISOCHRONOUS_ENDPOINT,
BULK_ENDPOINT,
INTERRUPT_ENDPOINT
};
#define AUDIO_CLASS 0x01
#define CDC_CLASS 0x02
#define HID_CLASS 0x03
#define MSD_CLASS 0x08
#define HUB_CLASS 0x09
#define SERIAL_CLASS 0x0A
// ------------------ HcControl Register ---------------------
#define OR_CONTROL_PLE 0x00000004
#define OR_CONTROL_CLE 0x00000010
#define OR_CONTROL_BLE 0x00000020
#define OR_CONTROL_HCFS 0x000000C0
#define OR_CONTROL_HC_OPER 0x00000080
// ----------------- HcCommandStatus Register -----------------
#define OR_CMD_STATUS_HCR 0x00000001
#define OR_CMD_STATUS_CLF 0x00000002
#define OR_CMD_STATUS_BLF 0x00000004
// --------------- HcInterruptStatus Register -----------------
#define OR_INTR_STATUS_WDH 0x00000002
#define OR_INTR_STATUS_RHSC 0x00000040
#define OR_INTR_STATUS_UE 0x00000010
// --------------- HcInterruptEnable Register -----------------
#define OR_INTR_ENABLE_WDH 0x00000002
#define OR_INTR_ENABLE_RHSC 0x00000040
#define OR_INTR_ENABLE_MIE 0x80000000
// ---------------- HcRhDescriptorA Register ------------------
#define OR_RH_STATUS_LPSC 0x00010000
#define OR_RH_STATUS_DRWE 0x00008000
// -------------- HcRhPortStatus[1:NDP] Register --------------
#define OR_RH_PORT_CCS 0x00000001
#define OR_RH_PORT_PRS 0x00000010
#define OR_RH_PORT_CSC 0x00010000
#define OR_RH_PORT_PRSC 0x00100000
#define OR_RH_PORT_LSDA 0x00000200
#define FI 0x2EDF // 12000 bits per frame (-1)
#define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI)
#define ED_SKIP (uint32_t) (0x00001000) // Skip this ep in queue
#define TD_ROUNDING (uint32_t) (0x00040000) // Buffer Rounding
#define TD_SETUP (uint32_t)(0) // Direction of Setup Packet
#define TD_IN (uint32_t)(0x00100000) // Direction In
#define TD_OUT (uint32_t)(0x00080000) // Direction Out
#define TD_DELAY_INT(x) (uint32_t)((x) << 21) // Delay Interrupt
#define TD_TOGGLE_0 (uint32_t)(0x02000000) // Toggle 0
#define TD_TOGGLE_1 (uint32_t)(0x03000000) // Toggle 1
#define TD_CC (uint32_t)(0xF0000000) // Completion Code
#define DEVICE_DESCRIPTOR (1)
#define CONFIGURATION_DESCRIPTOR (2)
#define INTERFACE_DESCRIPTOR (4)
#define ENDPOINT_DESCRIPTOR (5)
#define HID_DESCRIPTOR (33)
// ----------- Control RequestType Fields -----------
#define USB_DEVICE_TO_HOST 0x80
#define USB_HOST_TO_DEVICE 0x00
#define USB_REQUEST_TYPE_CLASS 0x20
#define USB_REQUEST_TYPE_STANDARD 0x00
#define USB_RECIPIENT_DEVICE 0x00
#define USB_RECIPIENT_INTERFACE 0x01
#define USB_RECIPIENT_ENDPOINT 0x02
// -------------- USB Standard Requests --------------
#define SET_ADDRESS 0x05
#define GET_DESCRIPTOR 0x06
#define SET_CONFIGURATION 0x09
#define SET_INTERFACE 0x0b
#define CLEAR_FEATURE 0x01
// -------------- USB Descriptor Length --------------
#define DEVICE_DESCRIPTOR_LENGTH 0x12
#define CONFIGURATION_DESCRIPTOR_LENGTH 0x09
// ------------ HostController Transfer Descriptor ------------
typedef __packed struct HCTD {
__IO uint32_t control; // Transfer descriptor control
__IO uint8_t * currBufPtr; // Physical address of current buffer pointer
__IO HCTD * nextTD; // Physical pointer to next Transfer Descriptor
__IO uint8_t * bufEnd; // Physical address of end of buffer
void * ep; // ep address where a td is linked in
uint32_t dummy[3]; // padding
} HCTD;
// ----------- HostController EndPoint Descriptor -------------
typedef __packed struct hcEd {
__IO uint32_t control; // Endpoint descriptor control
__IO HCTD * tailTD; // Physical address of tail in Transfer descriptor list
__IO HCTD * headTD; // Physcial address of head in Transfer descriptor list
__IO hcEd * nextED; // Physical address of next Endpoint descriptor
} HCED;
// ----------- Host Controller Communication Area ------------
typedef __packed struct hcca {
__IO uint32_t IntTable[32]; // Interrupt Table
__IO uint32_t FrameNumber; // Frame Number
__IO uint32_t DoneHead; // Done Head
volatile uint8_t Reserved[116]; // Reserved for future use
volatile uint8_t Unknown[4]; // Unused
} HCCA;
typedef __packed struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} DeviceDescriptor;
typedef __packed struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} ConfigurationDescriptor;
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} InterfaceDescriptor;
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
} EndpointDescriptor;
typedef struct {
uint8_t bDescLength;
uint8_t bDescriptorType;
uint8_t bNbrPorts;
uint16_t wHubCharacteristics;
uint8_t bPwrOn2PwrGood;
uint8_t bHubContrCurrent;
uint8_t DeviceRemovable;
uint8_t PortPweCtrlMak;
} HubDescriptor;
#endif

View File

@ -0,0 +1,51 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USB_DEBUG_H
#define USB_DEBUG_H
//Debug is disabled by default
#define DEBUG 0
#define DEBUG_TRANSFER 0
#define DEBUG_EP_STATE 0
#define DEBUG_EVENT 0
#if (DEBUG)
#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#else
#define USB_DBG(x, ...)
#endif
#if (DEBUG_TRANSFER)
#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#else
#define USB_DBG_TRANSFER(x, ...)
#endif
#if (DEBUG_EVENT)
#define USB_DBG_EVENT(x, ...) std::printf("[USB_EVENT: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#else
#define USB_DBG_EVENT(x, ...)
#endif
#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#endif

View File

@ -0,0 +1,184 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "USBHostKeyboard.h"
#if USBHOST_KEYBOARD
static uint8_t keymap[4][0x39] = {
{ 0, 0, 0, 0, 'a', 'b' /*0x05*/,
'c', 'd', 'e', 'f', 'g' /*0x0a*/,
'h', 'i', 'j', 'k', 'l'/*0x0f*/,
'm', 'n', 'o', 'p', 'q'/*0x14*/,
'r', 's', 't', 'u', 'v'/*0x19*/,
'w', 'x', 'y', 'z', '1'/*0x1E*/,
'2', '3', '4', '5', '6'/*0x23*/,
'7', '8', '9', '0', 0x0A /*enter*/, /*0x28*/
0x1B /*escape*/, 0x08 /*backspace*/, 0x09/*tab*/, 0x20/*space*/, '-', /*0x2d*/
'=', '[', ']', '\\', '#', /*0x32*/
';', '\'', 0, ',', '.', /*0x37*/
'/'},
/* CTRL MODIFIER */
{ 0, 0, 0, 0, 0, 0 /*0x05*/,
0, 0, 0, 0, 0 /*0x0a*/,
0, 0, 0, 0, 0/*0x0f*/,
0, 0, 0, 0, 0/*0x14*/,
0, 0, 0, 0, 0/*0x19*/,
0, 0, 0, 0, 0/*0x1E*/,
0, 0, 0, 0, 0/*0x23*/,
0, 0, 0, 0, 0 /*enter*/, /*0x28*/
0, 0, 0, 0, 0, /*0x2d*/
0, 0, 0, 0, 0, /*0x32*/
0, 0, 0, 0, 0, /*0x37*/
0},
/* SHIFT MODIFIER */
{ 0, 0, 0, 0, 'A', 'B' /*0x05*/,
'C', 'D', 'E', 'F', 'G' /*0x0a*/,
'H', 'I', 'J', 'K', 'L'/*0x0f*/,
'M', 'N', 'O', 'P', 'Q'/*0x14*/,
'R', 'S', 'T', 'U', 'V'/*0x19*/,
'W', 'X', 'Y', 'Z', '!'/*0x1E*/,
'@', '#', '$', '%', '^'/*0x23*/,
'&', '*', '(', ')', 0, /*0x28*/
0, 0, 0, 0, 0, /*0x2d*/
'+', '{', '}', '|', '~', /*0x32*/
':', '"', 0, '<', '>', /*0x37*/
'?'},
/* ALT MODIFIER */
{ 0, 0, 0, 0, 0, 0 /*0x05*/,
0, 0, 0, 0, 0 /*0x0a*/,
0, 0, 0, 0, 0/*0x0f*/,
0, 0, 0, 0, 0/*0x14*/,
0, 0, 0, 0, 0/*0x19*/,
0, 0, 0, 0, 0/*0x1E*/,
0, 0, 0, 0, 0/*0x23*/,
0, 0, 0, 0, 0 /*enter*/, /*0x28*/
0, 0, 0, 0, 0, /*0x2d*/
0, 0, 0, 0, 0, /*0x32*/
0, 0, 0, 0, 0, /*0x37*/
0}
};
USBHostKeyboard::USBHostKeyboard() {
host = USBHost::getHostInst();
init();
}
void USBHostKeyboard::init() {
dev = NULL;
int_in = NULL;
report_id = 0;
onKey = NULL;
onKeyCode = NULL;
dev_connected = false;
keyboard_intf = -1;
keyboard_device_found = false;
}
bool USBHostKeyboard::connected() {
return dev_connected;
}
bool USBHostKeyboard::connect() {
if (dev_connected) {
return true;
}
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
if ((dev = host->getDevice(i)) != NULL) {
if (host->enumerate(dev, this))
break;
if (keyboard_device_found) {
int_in = dev->getEndpoint(keyboard_intf, INTERRUPT_ENDPOINT, IN);
if (!int_in)
break;
USB_INFO("New Keyboard device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, keyboard_intf);
dev->setName("Keyboard", keyboard_intf);
host->registerDriver(dev, keyboard_intf, this, &USBHostKeyboard::init);
int_in->attach(this, &USBHostKeyboard::rxHandler);
host->interruptRead(dev, int_in, report, int_in->getSize(), false);
dev_connected = true;
return true;
}
}
}
init();
return false;
}
void USBHostKeyboard::rxHandler() {
int len = int_in->getLengthTransferred();
int index = (len == 9) ? 1 : 0;
int len_listen = int_in->getSize();
uint8_t key = 0;
if (len == 8 || len == 9) {
uint8_t modifier = (report[index] == 4) ? 3 : report[index];
len_listen = len;
key = keymap[modifier][report[index + 2]];
if (key && onKey) {
(*onKey)(key);
}
if ((report[index + 2] || modifier) && onKeyCode) {
(*onKeyCode)(report[index + 2], modifier);
}
}
if (dev && int_in)
host->interruptRead(dev, int_in, report, len_listen, false);
}
/*virtual*/ void USBHostKeyboard::setVidPid(uint16_t vid, uint16_t pid)
{
// we don't check VID/PID for keyboard driver
}
/*virtual*/ bool USBHostKeyboard::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
{
if ((keyboard_intf == -1) &&
(intf_class == HID_CLASS) &&
(intf_subclass == 0x01) &&
(intf_protocol == 0x01)) {
keyboard_intf = intf_nb;
return true;
}
return false;
}
/*virtual*/ bool USBHostKeyboard::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if (intf_nb == keyboard_intf) {
if (type == INTERRUPT_ENDPOINT && dir == IN) {
keyboard_device_found = true;
return true;
}
}
return false;
}
#endif

View File

@ -0,0 +1,102 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBHOSTKEYBOARD_H
#define USBHOSTKEYBOARD_H
#include "USBHostConf.h"
#if USBHOST_KEYBOARD
#include "USBHost.h"
/**
* A class to communicate a USB keyboard
*/
class USBHostKeyboard : public IUSBEnumerator {
public:
/**
* Constructor
*/
USBHostKeyboard();
/**
* Try to connect a keyboard device
*
* @return true if connection was successful
*/
bool connect();
/**
* Check if a keyboard is connected
*
* @returns true if a keyboard is connected
*/
bool connected();
/**
* Attach a callback called when a keyboard event is received
*
* @param ptr function pointer
*/
inline void attach(void (*ptr)(uint8_t key)) {
if (ptr != NULL) {
onKey = ptr;
}
}
/**
* Attach a callback called when a keyboard event is received
*
* @param ptr function pointer
*/
inline void attach(void (*ptr)(uint8_t keyCode, uint8_t modifier)) {
if (ptr != NULL) {
onKeyCode = ptr;
}
}
protected:
//From IUSBEnumerator
virtual void setVidPid(uint16_t vid, uint16_t pid);
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
private:
USBHost * host;
USBDeviceConnected * dev;
USBEndpoint * int_in;
uint8_t report[9];
int keyboard_intf;
bool keyboard_device_found;
bool dev_connected;
void rxHandler();
void (*onKey)(uint8_t key);
void (*onKeyCode)(uint8_t key, uint8_t modifier);
int report_id;
void init();
};
#endif
#endif

View File

@ -0,0 +1,145 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "USBHostMouse.h"
#if USBHOST_MOUSE
USBHostMouse::USBHostMouse() {
host = USBHost::getHostInst();
init();
}
void USBHostMouse::init() {
dev = NULL;
int_in = NULL;
onUpdate = NULL;
onButtonUpdate = NULL;
onXUpdate = NULL;
onYUpdate = NULL;
onZUpdate = NULL;
report_id = 0;
dev_connected = false;
mouse_device_found = false;
mouse_intf = -1;
buttons = 0;
x = 0;
y = 0;
z = 0;
}
bool USBHostMouse::connected() {
return dev_connected;
}
bool USBHostMouse::connect() {
if (dev_connected) {
return true;
}
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
if ((dev = host->getDevice(i)) != NULL) {
if(host->enumerate(dev, this))
break;
if (mouse_device_found) {
int_in = dev->getEndpoint(mouse_intf, INTERRUPT_ENDPOINT, IN);
if (!int_in)
break;
USB_INFO("New Mouse device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, mouse_intf);
dev->setName("Mouse", mouse_intf);
host->registerDriver(dev, mouse_intf, this, &USBHostMouse::init);
int_in->attach(this, &USBHostMouse::rxHandler);
host->interruptRead(dev, int_in, report, int_in->getSize(), false);
dev_connected = true;
return true;
}
}
}
init();
return false;
}
void USBHostMouse::rxHandler() {
int len_listen = int_in->getSize();
int len = int_in->getLengthTransferred();
if (onUpdate) {
(*onUpdate)(report[0] & 0x07, report[1], report[2], report[3]);
}
if (onButtonUpdate && (buttons != (report[0] & 0x07))) {
(*onButtonUpdate)(report[0] & 0x07);
}
if (onXUpdate && (x != report[1])) {
(*onXUpdate)(report[1]);
}
if (onYUpdate && (y != report[2])) {
(*onYUpdate)(report[2]);
}
if (onZUpdate && (z != report[3])) {
(*onZUpdate)(report[3]);
}
// update mouse state
buttons = report[0] & 0x07;
x = report[1];
y = report[2];
z = report[3];
if (dev)
host->interruptRead(dev, int_in, report, len_listen, false);
}
/*virtual*/ void USBHostMouse::setVidPid(uint16_t vid, uint16_t pid)
{
// we don't check VID/PID for mouse driver
}
/*virtual*/ bool USBHostMouse::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
{
if ((mouse_intf == -1) &&
(intf_class == HID_CLASS) &&
(intf_subclass == 0x01) &&
(intf_protocol == 0x02)) {
mouse_intf = intf_nb;
return true;
}
return false;
}
/*virtual*/ bool USBHostMouse::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if (intf_nb == mouse_intf) {
if (type == INTERRUPT_ENDPOINT && dir == IN) {
mouse_device_found = true;
return true;
}
}
return false;
}
#endif

View File

@ -0,0 +1,139 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBHOSTMOUSE_H
#define USBHOSTMOUSE_H
#include "USBHostConf.h"
#if USBHOST_MOUSE
#include "USBHost.h"
/**
* A class to communicate a USB mouse
*/
class USBHostMouse : public IUSBEnumerator {
public:
/**
* Constructor
*/
USBHostMouse();
/**
* Try to connect a mouse device
*
* @return true if connection was successful
*/
bool connect();
/**
* Check if a mouse is connected
*
* @returns true if a mouse is connected
*/
bool connected();
/**
* Attach a callback called when a mouse event is received
*
* @param ptr function pointer
*/
inline void attachEvent(void (*ptr)(uint8_t buttons, int8_t x, int8_t y, int8_t z)) {
if (ptr != NULL) {
onUpdate = ptr;
}
}
/**
* Attach a callback called when the button state changes
*
* @param ptr function pointer
*/
inline void attachButtonEvent(void (*ptr)(uint8_t buttons)) {
if (ptr != NULL) {
onButtonUpdate = ptr;
}
}
/**
* Attach a callback called when the X axis value changes
*
* @param ptr function pointer
*/
inline void attachXEvent(void (*ptr)(int8_t x)) {
if (ptr != NULL) {
onXUpdate = ptr;
}
}
/**
* Attach a callback called when the Y axis value changes
*
* @param ptr function pointer
*/
inline void attachYEvent(void (*ptr)(int8_t y)) {
if (ptr != NULL) {
onYUpdate = ptr;
}
}
/**
* Attach a callback called when the Z axis value changes (scrolling)
*
* @param ptr function pointer
*/
inline void attachZEvent(void (*ptr)(int8_t z)) {
if (ptr != NULL) {
onZUpdate = ptr;
}
}
protected:
//From IUSBEnumerator
virtual void setVidPid(uint16_t vid, uint16_t pid);
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
private:
USBHost * host;
USBDeviceConnected * dev;
USBEndpoint * int_in;
uint8_t report[4];
bool dev_connected;
bool mouse_device_found;
int mouse_intf;
uint8_t buttons;
int8_t x;
int8_t y;
int8_t z;
void rxHandler();
void (*onUpdate)(uint8_t buttons, int8_t x, int8_t y, int8_t z);
void (*onButtonUpdate)(uint8_t buttons);
void (*onXUpdate)(int8_t x);
void (*onYUpdate)(int8_t y);
void (*onZUpdate)(int8_t z);
int report_id;
void init();
};
#endif
#endif

View File

@ -0,0 +1,271 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "USBHostHub.h"
#if MAX_HUB_NB
#include "USBHost.h"
#include "dbg.h"
#define GET_STATUS 0x00
#define CLEAR_FEATURE 0x01
#define GET_STATE 0x02
#define SET_FEATURE 0x03
#define GET_DESCRIPTOR 0x06
#define PORT_CONNECTION_FEATURE (0x00)
#define PORT_ENABLE_FEATURE (0x01)
#define PORT_RESET_FEATURE (0x04)
#define PORT_POWER_FEATURE (0x08)
#define C_PORT_CONNECTION_FEATURE (16)
#define C_PORT_ENABLE_FEATURE (17)
#define C_PORT_RESET_FEATURE (20)
#define PORT_CONNECTION (1 << 0)
#define PORT_ENABLE (1 << 1)
#define PORT_SUSPEND (1 << 2)
#define PORT_OVER_CURRENT (1 << 3)
#define PORT_RESET (1 << 4)
#define PORT_POWER (1 << 8)
#define PORT_LOW_SPEED (1 << 9)
#define C_PORT_CONNECTION (1 << 16)
#define C_PORT_ENABLE (1 << 17)
#define C_PORT_SUSPEND (1 << 18)
#define C_PORT_OVER_CURRENT (1 << 19)
#define C_PORT_RESET (1 << 20)
USBHostHub::USBHostHub() {
host = NULL;
init();
}
void USBHostHub::init() {
dev_connected = false;
dev = NULL;
int_in = NULL;
dev_connected = false;
hub_intf = -1;
hub_device_found = false;
nb_port = 0;
hub_characteristics = 0;
for (int i = 0; i < MAX_HUB_PORT; i++) {
device_children[i] = NULL;
}
}
void USBHostHub::setHost(USBHost * host_) {
host = host_;
}
bool USBHostHub::connected()
{
return dev_connected;
}
bool USBHostHub::connect(USBDeviceConnected * dev)
{
if (dev_connected) {
return true;
}
if(host->enumerate(dev, this)) {
init();
return false;
}
if (hub_device_found) {
this->dev = dev;
int_in = dev->getEndpoint(hub_intf, INTERRUPT_ENDPOINT, IN);
if (!int_in) {
init();
return false;
}
USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, hub_intf);
dev->setName("Hub", hub_intf);
host->registerDriver(dev, hub_intf, this, &USBHostHub::disconnect);
int_in->attach(this, &USBHostHub::rxHandler);
// get HUB descriptor
host->controlRead( dev,
USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
GET_DESCRIPTOR,
0x29 << 8, 0, buf, sizeof(HubDescriptor));
nb_port = buf[2];
hub_characteristics = buf[3];
USB_DBG("Hub has %d port", nb_port);
for (uint8_t j = 1; j <= nb_port; j++) {
setPortFeature(PORT_POWER_FEATURE, j);
}
wait_ms(buf[5]*2);
host->interruptRead(dev, int_in, buf, 1, false);
dev_connected = true;
return true;
}
return false;
}
void USBHostHub::disconnect() {
init();
}
/*virtual*/ void USBHostHub::setVidPid(uint16_t vid, uint16_t pid)
{
// we don't check VID/PID for MSD driver
}
/*virtual*/ bool USBHostHub::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
{
if ((hub_intf == -1) &&
(intf_class == HUB_CLASS) &&
(intf_subclass == 0) &&
(intf_protocol == 0)) {
hub_intf = intf_nb;
return true;
}
return false;
}
/*virtual*/ bool USBHostHub::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if (intf_nb == hub_intf) {
if ((type == INTERRUPT_ENDPOINT) && (dir == IN)) {
hub_device_found = true;
return true;
}
}
return false;
}
void USBHostHub::deviceConnected(USBDeviceConnected * dev) {
device_children[dev->getPort() - 1] = dev;
}
void USBHostHub::deviceDisconnected(USBDeviceConnected * dev) {
device_children[dev->getPort() - 1] = NULL;
}
void USBHostHub::hubDisconnected() {
for (uint8_t i = 0; i < MAX_HUB_PORT; i++) {
if (device_children[i] != NULL) {
host->freeDevice(device_children[i]);
}
}
}
void USBHostHub::rxHandler() {
uint32_t status;
if (int_in) {
if (int_in->getState() == USB_TYPE_IDLE) {
for (int port = 1; port <= nb_port; port++) {
status = getPortStatus(port);
USB_DBG("[hub handler hub: %d] status port %d [hub: %p]: 0x%X", dev->getHub(), port, dev, status);
// if connection status has changed
if (status & C_PORT_CONNECTION) {
if (status & PORT_CONNECTION) {
USB_DBG("[hub handler hub: %d - port: %d] new device connected", dev->getHub(), port);
host->deviceConnected(dev->getHub() + 1, port, status & PORT_LOW_SPEED, this);
} else {
USB_DBG("[hub handler hub: %d - port: %d] device disconnected", dev->getHub(), port);
host->deviceDisconnected(dev->getHub() + 1, port, this, NULL);
}
clearPortFeature(C_PORT_CONNECTION_FEATURE, port);
}
if (status & C_PORT_RESET) {
clearPortFeature(C_PORT_RESET_FEATURE, port);
}
if (status & C_PORT_ENABLE) {
clearPortFeature(C_PORT_ENABLE_FEATURE, port);
}
if ((status & PORT_OVER_CURRENT)) {
USB_ERR("OVER CURRENT DETECTED\r\n");
clearPortFeature(PORT_OVER_CURRENT, port);
host->deviceDisconnected(dev->getHub() + 1, port, this, NULL);
}
}
}
host->interruptRead(dev, int_in, buf, 1, false);
}
}
void USBHostHub::portReset(uint8_t port) {
// reset port
uint32_t status;
USB_DBG("reset port %d on hub: %p [this: %p]", port, dev, this)
setPortFeature(PORT_RESET_FEATURE, port);
while(1) {
status = getPortStatus(port);
if (status & (PORT_ENABLE | PORT_RESET))
break;
if (status & PORT_OVER_CURRENT) {
USB_ERR("OVER CURRENT DETECTED\r\n");
clearPortFeature(PORT_OVER_CURRENT, port);
host->deviceDisconnected(dev->getHub() + 1, port, this, NULL);
break;
}
Thread::wait(10);
}
}
void USBHostHub::setPortFeature(uint32_t feature, uint8_t port) {
host->controlWrite( dev,
USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
SET_FEATURE,
feature,
port,
NULL,
0);
}
void USBHostHub::clearPortFeature(uint32_t feature, uint8_t port) {
host->controlWrite( dev,
USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
CLEAR_FEATURE,
feature,
port,
NULL,
0);
}
uint32_t USBHostHub::getPortStatus(uint8_t port) {
uint32_t st;
host->controlRead( dev,
USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
GET_STATUS,
0,
port,
(uint8_t *)&st,
4);
return st;
}
#endif

View File

@ -0,0 +1,125 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBHOSTHUB_H
#define USBHOSTHUB_H
#include "USBHostConf.h"
#if MAX_HUB_NB
#include "USBHostTypes.h"
#include "IUSBEnumerator.h"
class USBHost;
class USBDeviceConnected;
class USBEndpoint;
/**
* A class to use a USB Hub
*/
class USBHostHub : public IUSBEnumerator {
public:
/**
* Constructor
*/
USBHostHub();
/**
* Check if a USB Hub is connected
*
* @return true if a serial device is connected
*/
bool connected();
/**
* Try to connect device
*
* @param dev device to connect
* @return true if connection was successful
*/
bool connect(USBDeviceConnected * dev);
/**
* Automatically called by USBHost when a device
* has been enumerated by usb_thread
*
* @param dev device connected
*/
void deviceConnected(USBDeviceConnected * dev);
/**
* Automatically called by USBHost when a device
* has been disconnected from this hub
*
* @param dev device disconnected
*/
void deviceDisconnected(USBDeviceConnected * dev);
/**
* Rest a specific port
*
* @param port port number
*/
void portReset(uint8_t port);
/*
* Called by USBHost to set the instance of USBHost
*
* @param host host instance
*/
void setHost(USBHost * host);
/**
* Called by USBhost when a hub has been disconnected
*/
void hubDisconnected();
protected:
//From IUSBEnumerator
virtual void setVidPid(uint16_t vid, uint16_t pid);
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
private:
USBHost * host;
USBDeviceConnected * dev;
bool dev_connected;
USBEndpoint * int_in;
uint8_t nb_port;
uint8_t hub_characteristics;
void rxHandler();
uint8_t buf[sizeof(HubDescriptor)];
int hub_intf;
bool hub_device_found;
void setPortFeature(uint32_t feature, uint8_t port);
void clearPortFeature(uint32_t feature, uint8_t port);
uint32_t getPortStatus(uint8_t port);
USBDeviceConnected * device_children[MAX_HUB_PORT];
void init();
void disconnect();
};
#endif
#endif

View File

@ -0,0 +1,356 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "USBHostMSD.h"
#if USBHOST_MSD
#include "dbg.h"
#define CBW_SIGNATURE 0x43425355
#define CSW_SIGNATURE 0x53425355
#define DEVICE_TO_HOST 0x80
#define HOST_TO_DEVICE 0x00
#define GET_MAX_LUN (0xFE)
#define BO_MASS_STORAGE_RESET (0xFF)
USBHostMSD::USBHostMSD(const char * rootdir) : FATFileSystem(rootdir)
{
host = USBHost::getHostInst();
init();
}
void USBHostMSD::init() {
dev_connected = false;
dev = NULL;
bulk_in = NULL;
bulk_out = NULL;
dev_connected = false;
blockSize = 0;
blockCount = 0;
msd_intf = -1;
msd_device_found = false;
disk_init = false;
dev_connected = false;
nb_ep = 0;
}
bool USBHostMSD::connected()
{
return dev_connected;
}
bool USBHostMSD::connect()
{
if (dev_connected) {
return true;
}
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
if ((dev = host->getDevice(i)) != NULL) {
USB_DBG("Trying to connect MSD device\r\n");
if(host->enumerate(dev, this))
break;
if (msd_device_found) {
bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN);
bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT);
if (!bulk_in || !bulk_out)
continue;
USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf);
dev->setName("MSD", msd_intf);
host->registerDriver(dev, msd_intf, this, &USBHostMSD::init);
dev_connected = true;
return true;
}
} //if()
} //for()
init();
return false;
}
/*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid)
{
// we don't check VID/PID for MSD driver
}
/*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
{
if ((msd_intf == -1) &&
(intf_class == MSD_CLASS) &&
(intf_subclass == 0x06) &&
(intf_protocol == 0x50)) {
msd_intf = intf_nb;
return true;
}
return false;
}
/*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if (intf_nb == msd_intf) {
if (type == BULK_ENDPOINT) {
nb_ep++;
if (nb_ep == 2)
msd_device_found = true;
return true;
}
}
return false;
}
int USBHostMSD::testUnitReady() {
USB_DBG("Test unit ready");
return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0);
}
int USBHostMSD::readCapacity() {
USB_DBG("Read capacity");
uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0};
uint8_t result[8];
int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8);
if (status == 0) {
blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3];
blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7];
USB_INFO("MSD [dev: %p] - blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", dev, blockCount, blockSize, blockCount*blockSize);
}
return status;
}
int USBHostMSD::SCSIRequestSense() {
USB_DBG("Request sense");
uint8_t cmd[6] = {0x03,0,0,0,18,0};
uint8_t result[18];
int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18);
return status;
}
int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) {
USB_DBG("Inquiry");
uint8_t evpd = (page_code == 0) ? 0 : 1;
uint8_t cmd[6] = {0x12, (lun << 5) | evpd, page_code, 0, 36, 0};
uint8_t result[36];
int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36);
if (status == 0) {
char vid_pid[17];
memcpy(vid_pid, &result[8], 8);
vid_pid[8] = 0;
USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid);
memcpy(vid_pid, &result[16], 16);
vid_pid[16] = 0;
USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid);
memcpy(vid_pid, &result[32], 4);
vid_pid[4] = 0;
USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid);
}
return status;
}
int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) {
// if ep stalled: send clear feature
if (res == USB_TYPE_STALL_ERROR) {
res = host->controlWrite( dev,
USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
CLEAR_FEATURE,
0, ep->getAddress(), NULL, 0);
// set state to IDLE if clear feature successful
if (res == USB_TYPE_OK) {
ep->setState(USB_TYPE_IDLE);
}
}
if (res != USB_TYPE_OK)
return -1;
return 0;
}
int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) {
int res = 0;
cbw.Signature = CBW_SIGNATURE;
cbw.Tag = 0;
cbw.DataLength = transfer_len;
cbw.Flags = flags;
cbw.LUN = 0;
cbw.CBLength = cmd_len;
memset(cbw.CB,0,sizeof(cbw.CB));
if (cmd) {
memcpy(cbw.CB,cmd,cmd_len);
}
// send the cbw
USB_DBG("Send CBW");
res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31);
if (checkResult(res, bulk_out))
return -1;
// data stage if needed
if (data) {
USB_DBG("data stage");
if (flags == HOST_TO_DEVICE) {
res = host->bulkWrite(dev, bulk_out, data, transfer_len);
if (checkResult(res, bulk_out))
return -1;
} else if (flags == DEVICE_TO_HOST) {
res = host->bulkRead(dev, bulk_in, data, transfer_len);
if (checkResult(res, bulk_in))
return -1;
}
}
// status stage
csw.Signature = 0;
USB_DBG("Read CSW");
res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13);
if (checkResult(res, bulk_in))
return -1;
if (csw.Signature != CSW_SIGNATURE) {
return -1;
}
USB_DBG("recv csw: status: %d", csw.Status);
// ModeSense?
if ((csw.Status == 1) && (cmd[0] != 0x03)) {
USB_DBG("request mode sense");
return SCSIRequestSense();
}
// perform reset recovery
if ((csw.Status == 2) && (cmd[0] != 0x03)) {
// send Bulk-Only Mass Storage Reset request
res = host->controlWrite( dev,
USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
BO_MASS_STORAGE_RESET,
0, msd_intf, NULL, 0);
// unstall both endpoints
res = host->controlWrite( dev,
USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
CLEAR_FEATURE,
0, bulk_in->getAddress(), NULL, 0);
res = host->controlWrite( dev,
USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
CLEAR_FEATURE,
0, bulk_out->getAddress(), NULL, 0);
}
return csw.Status;
}
int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) {
uint8_t cmd[10];
memset(cmd,0,10);
cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
cmd[2] = (block >> 24) & 0xff;
cmd[3] = (block >> 16) & 0xff;
cmd[4] = (block >> 8) & 0xff;
cmd[5] = block & 0xff;
cmd[7] = (nbBlock >> 8) & 0xff;
cmd[8] = nbBlock & 0xff;
return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock);
}
int USBHostMSD::getMaxLun() {
uint8_t buf[1], res;
res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
0xfe, 0, msd_intf, buf, 1);
USB_DBG("max lun: %d", buf[0]);
return res;
}
int USBHostMSD::disk_initialize() {
USB_DBG("FILESYSTEM: init");
U16 i, timeout = 10;
getMaxLun();
for (i = 0; i < timeout; i++) {
Thread::wait(100);
if (!testUnitReady())
break;
}
if (i == timeout) {
disk_init = false;
return -1;
}
inquiry(0, 0);
disk_init = 1;
return readCapacity();
}
int USBHostMSD::disk_write(const uint8_t *buffer, uint64_t block_number) {
USB_DBG("FILESYSTEM: write block: %lld", block_number);
if (!disk_init) {
disk_initialize();
}
if (!disk_init)
return -1;
return dataTransfer((uint8_t *)buffer, block_number, 1, HOST_TO_DEVICE);
}
int USBHostMSD::disk_read(uint8_t * buffer, uint64_t block_number) {
USB_DBG("FILESYSTEM: read block %lld", block_number);
if (!disk_init) {
disk_initialize();
}
if (!disk_init)
return -1;
return dataTransfer((uint8_t *)buffer, block_number, 1, DEVICE_TO_HOST);
}
uint64_t USBHostMSD::disk_sectors() {
USB_DBG("FILESYSTEM: sectors");
if (!disk_init) {
disk_initialize();
}
if (!disk_init)
return 0;
return blockCount;
}
#endif

View File

@ -0,0 +1,119 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBHOSTMSD_H
#define USBHOSTMSD_H
#include "USBHostConf.h"
#if USBHOST_MSD
#include "USBHost.h"
#include "FATFileSystem.h"
/**
* A class to communicate a USB flash disk
*/
class USBHostMSD : public IUSBEnumerator, public FATFileSystem {
public:
/**
* Constructor
*
* @param rootdir mount name
*/
USBHostMSD(const char * rootdir);
/**
* Check if a MSD device is connected
*
* @return true if a MSD device is connected
*/
bool connected();
/**
* Try to connect to a MSD device
*
* @return true if connection was successful
*/
bool connect();
protected:
//From IUSBEnumerator
virtual void setVidPid(uint16_t vid, uint16_t pid);
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
// From FATFileSystem
virtual int disk_initialize();
virtual int disk_status() {return 0;};
virtual int disk_read(uint8_t * buffer, uint64_t sector);
virtual int disk_write(const uint8_t * buffer, uint64_t sector);
virtual int disk_sync() {return 0;};
virtual uint64_t disk_sectors();
private:
USBHost * host;
USBDeviceConnected * dev;
bool dev_connected;
USBEndpoint * bulk_in;
USBEndpoint * bulk_out;
uint8_t nb_ep;
// Bulk-only CBW
typedef __packed struct {
uint32_t Signature;
uint32_t Tag;
uint32_t DataLength;
uint8_t Flags;
uint8_t LUN;
uint8_t CBLength;
uint8_t CB[16];
} CBW;
// Bulk-only CSW
typedef __packed struct {
uint32_t Signature;
uint32_t Tag;
uint32_t DataResidue;
uint8_t Status;
} CSW;
CBW cbw;
CSW csw;
int SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len);
int testUnitReady();
int readCapacity();
int inquiry(uint8_t lun, uint8_t page_code);
int SCSIRequestSense();
int dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction);
int checkResult(uint8_t res, USBEndpoint * ep);
int getMaxLun();
int blockSize;
uint64_t blockCount;
int msd_intf;
bool msd_device_found;
bool disk_init;
void init();
};
#endif
#endif

View File

@ -0,0 +1,89 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MTXCIRCBUFFER_H
#define MTXCIRCBUFFER_H
#include "stdint.h"
#include "rtos.h"
//Mutex protected circular buffer
template<typename T, int size>
class MtxCircBuffer {
public:
MtxCircBuffer() {
write = 0;
read = 0;
}
bool isFull() {
mtx.lock();
bool r = (((write + 1) % size) == read);
mtx.unlock();
return r;
}
bool isEmpty() {
mtx.lock();
bool r = (read == write);
mtx.unlock();
return r;
}
void flush() {
write = 0;
read = 0;
}
void queue(T k) {
mtx.lock();
while (((write + 1) % size) == read) {
mtx.unlock();
Thread::wait(10);
mtx.lock();
}
buf[write++] = k;
write %= size;
mtx.unlock();
}
uint16_t available() {
mtx.lock();
uint16_t a = (write >= read) ? (write - read) : (size - read + write);
mtx.unlock();
return a;
}
bool dequeue(T * c) {
mtx.lock();
bool empty = (read == write);
if (!empty) {
*c = buf[read++];
read %= size;
}
mtx.unlock();
return (!empty);
}
private:
volatile uint16_t write;
volatile uint16_t read;
volatile T buf[size];
Mutex mtx;
};
#endif

View File

@ -0,0 +1,184 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "USBHostSerial.h"
#if USBHOST_SERIAL
#include "dbg.h"
#define SET_LINE_CODING 0x20
USBHostSerial::USBHostSerial(): circ_buf() {
host = USBHost::getHostInst();
size_bulk_in = 0;
size_bulk_out = 0;
init();
}
void USBHostSerial::init() {
dev = NULL;
bulk_in = NULL;
bulk_out = NULL;
dev_connected = false;
serial_intf = -1;
serial_device_found = false;
line_coding.baudrate = 9600;
line_coding.data_bits = 8;
line_coding.parity = None;
line_coding.stop_bits = 1;
circ_buf.flush();
}
bool USBHostSerial::connected()
{
return dev_connected;
}
bool USBHostSerial::connect() {
if (dev_connected) {
return true;
}
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
if ((dev = host->getDevice(i)) != NULL) {
USB_DBG("Trying to connect serial device\r\n");
if(host->enumerate(dev, this))
break;
if (serial_device_found) {
bulk_in = dev->getEndpoint(serial_intf, BULK_ENDPOINT, IN);
bulk_out = dev->getEndpoint(serial_intf, BULK_ENDPOINT, OUT);
if (!bulk_in || !bulk_out)
break;
USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
dev->setName("Serial", serial_intf);
host->registerDriver(dev, serial_intf, this, &USBHostSerial::init);
baud(9600);
size_bulk_in = bulk_in->getSize();
size_bulk_out = bulk_out->getSize();
bulk_in->attach(this, &USBHostSerial::rxHandler);
bulk_out->attach(this, &USBHostSerial::txHandler);
host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
dev_connected = true;
return true;
}
}
}
init();
return false;
}
void USBHostSerial::rxHandler() {
if (bulk_in) {
int len = bulk_in->getLengthTransferred();
if (bulk_in->getState() == USB_TYPE_IDLE) {
for (int i = 0; i < len; i++) {
circ_buf.queue(buf[i]);
}
rx.call();
host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
}
}
}
void USBHostSerial::txHandler() {
if (bulk_out) {
if (bulk_out->getState() == USB_TYPE_IDLE) {
tx.call();
}
}
}
int USBHostSerial::_putc(int c) {
if (bulk_out) {
if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) {
return 1;
}
}
return -1;
}
void USBHostSerial::baud(int baudrate) {
line_coding.baudrate = baudrate;
format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits);
}
void USBHostSerial::format(int bits, Parity parity, int stop_bits) {
line_coding.data_bits = bits;
line_coding.parity = parity;
line_coding.stop_bits = (stop_bits == 1) ? 0 : 2;
// set line coding
int res = host->controlWrite( dev,
USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
SET_LINE_CODING,
0, serial_intf, (uint8_t *)&line_coding, 7);
}
int USBHostSerial::_getc() {
uint8_t c = 0;
if (bulk_in == NULL) {
init();
return -1;
}
while (circ_buf.isEmpty());
circ_buf.dequeue(&c);
return c;
}
uint8_t USBHostSerial::available() {
return circ_buf.available();
}
/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
{
// we don't check VID/PID for MSD driver
}
/*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
{
if ((serial_intf == -1) &&
(intf_class == SERIAL_CLASS) &&
(intf_subclass == 0x00) &&
(intf_protocol == 0x00)) {
serial_intf = intf_nb;
return true;
}
return false;
}
/*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if (intf_nb == serial_intf) {
if (type == BULK_ENDPOINT) {
serial_device_found = true;
return true;
}
}
return false;
}
#endif

View File

@ -0,0 +1,166 @@
/* mbed USBHost Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBHOSTSERIAL_H
#define USBHOSTSERIAL_H
#include "USBHostConf.h"
#if USBHOST_SERIAL
#include "USBHost.h"
#include "Stream.h"
#include "MtxCircBuffer.h"
/**
* A class to communicate a USB virtual serial port
*/
class USBHostSerial : public IUSBEnumerator, public Stream {
public:
/**
* Constructor
*/
USBHostSerial();
enum IrqType {
RxIrq,
TxIrq
};
enum Parity {
None = 0,
Odd,
Even,
Mark,
Space
};
/**
* Check if a virtual serial port is connected
*
* @returns true if a serial device is connected
*/
bool connected();
/**
* Try to connect a serial device
*
* @return true if connection was successful
*/
bool connect();
/**
* Check the number of bytes available.
*
* @returns the number of bytes available
*/
uint8_t available();
/**
* Attach a member function to call when a packet is received.
*
* @param tptr pointer to the object to call the member function on
* @param mptr pointer to the member function to be called
* @param irq irq type
*/
template<typename T>
inline void attach(T* tptr, void (T::*mptr)(void), IrqType irq = RxIrq) {
if ((mptr != NULL) && (tptr != NULL)) {
if (irq == RxIrq) {
rx.attach(tptr, mptr);
} else {
tx.attach(tptr, mptr);
}
}
}
/**
* Attach a callback called when a packet is received
*
* @param ptr function pointer
*/
inline void attach(void (*fn)(void), IrqType irq = RxIrq) {
if (fn != NULL) {
if (irq == RxIrq) {
rx.attach(fn);
} else {
tx.attach(fn);
}
}
}
/** Set the baud rate of the serial port
*
* @param baudrate The baudrate of the serial port (default = 9600).
*/
void baud(int baudrate = 9600);
/** Set the transmission format used by the Serial port
*
* @param bits The number of bits in a word (default = 8)
* @param parity The parity used (USBHostSerial::None, USBHostSerial::Odd, USBHostSerial::Even, USBHostSerial::Mark, USBHostSerial::Space; default = USBHostSerial::None)
* @param stop The number of stop bits (1 or 2; default = 1)
*/
void format(int bits = 8, Parity parity = USBHostSerial::None, int stop_bits = 1);
protected:
//From IUSBEnumerator
virtual void setVidPid(uint16_t vid, uint16_t pid);
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
virtual int _getc();
virtual int _putc(int c);
private:
USBHost * host;
USBDeviceConnected * dev;
USBEndpoint * bulk_in;
USBEndpoint * bulk_out;
uint32_t size_bulk_in;
uint32_t size_bulk_out;
bool dev_connected;
void init();
MtxCircBuffer<uint8_t, 64> circ_buf;
uint8_t buf[64];
typedef __packed struct {
uint32_t baudrate;
uint8_t stop_bits;
uint8_t parity;
uint8_t data_bits;
} LINE_CODING;
LINE_CODING line_coding;
void rxHandler();
void txHandler();
FunctionPointer rx;
FunctionPointer tx;
int serial_intf;
bool serial_device_found;
};
#endif
#endif