mirror of https://github.com/ARMmbed/mbed-os.git
add USBHost library
parent
444e802b93
commit
1c981f929a
|
@ -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_*/
|
||||
|
|
@ -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];
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue