/drivers/usb/uhci/ch9.h |
---|
0,0 → 1,577 |
/* |
* This file holds USB constants and structures that are needed for |
* USB device APIs. These are used by the USB device model, which is |
* defined in chapter 9 of the USB 2.0 specification and in the |
* Wireless USB 1.0 (spread around). Linux has several APIs in C that |
* need these: |
* |
* - the master/host side Linux-USB kernel driver API; |
* - the "usbfs" user space API; and |
* - the Linux "gadget" slave/device/peripheral side driver API. |
* |
* USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems |
* act either as a USB master/host or as a USB slave/device. That means |
* the master and slave side APIs benefit from working well together. |
* |
* There's also "Wireless USB", using low power short range radios for |
* peripheral interconnection but otherwise building on the USB framework. |
* |
* Note all descriptors are declared '__attribute__((packed))' so that: |
* |
* [a] they never get padded, either internally (USB spec writers |
* probably handled that) or externally; |
* |
* [b] so that accessing bigger-than-a-bytes fields will never |
* generate bus errors on any platform, even when the location of |
* its descriptor inside a bundle isn't "naturally aligned", and |
* |
* [c] for consistency, removing all doubt even when it appears to |
* someone that the two other points are non-issues for that |
* particular descriptor type. |
*/ |
#ifndef __LINUX_USB_CH9_H |
#define __LINUX_USB_CH9_H |
#include <linux/types.h> /* __u8 etc */ |
/*-------------------------------------------------------------------------*/ |
/* CONTROL REQUEST SUPPORT */ |
/* |
* USB directions |
* |
* This bit flag is used in endpoint descriptors' bEndpointAddress field. |
* It's also one of three fields in control requests bRequestType. |
*/ |
#define USB_DIR_OUT 0 /* to device */ |
#define USB_DIR_IN 0x80 /* to host */ |
/* |
* USB types, the second of three bRequestType fields |
*/ |
#define USB_TYPE_MASK (0x03 << 5) |
#define USB_TYPE_STANDARD (0x00 << 5) |
#define USB_TYPE_CLASS (0x01 << 5) |
#define USB_TYPE_VENDOR (0x02 << 5) |
#define USB_TYPE_RESERVED (0x03 << 5) |
/* |
* USB recipients, the third of three bRequestType fields |
*/ |
#define USB_RECIP_MASK 0x1f |
#define USB_RECIP_DEVICE 0x00 |
#define USB_RECIP_INTERFACE 0x01 |
#define USB_RECIP_ENDPOINT 0x02 |
#define USB_RECIP_OTHER 0x03 |
/* From Wireless USB 1.0 */ |
#define USB_RECIP_PORT 0x04 |
#define USB_RECIP_RPIPE 0x05 |
/* |
* Standard requests, for the bRequest field of a SETUP packet. |
* |
* These are qualified by the bRequestType field, so that for example |
* TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved |
* by a GET_STATUS request. |
*/ |
#define USB_REQ_GET_STATUS 0x00 |
#define USB_REQ_CLEAR_FEATURE 0x01 |
#define USB_REQ_SET_FEATURE 0x03 |
#define USB_REQ_SET_ADDRESS 0x05 |
#define USB_REQ_GET_DESCRIPTOR 0x06 |
#define USB_REQ_SET_DESCRIPTOR 0x07 |
#define USB_REQ_GET_CONFIGURATION 0x08 |
#define USB_REQ_SET_CONFIGURATION 0x09 |
#define USB_REQ_GET_INTERFACE 0x0A |
#define USB_REQ_SET_INTERFACE 0x0B |
#define USB_REQ_SYNCH_FRAME 0x0C |
#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */ |
#define USB_REQ_GET_ENCRYPTION 0x0E |
#define USB_REQ_RPIPE_ABORT 0x0E |
#define USB_REQ_SET_HANDSHAKE 0x0F |
#define USB_REQ_RPIPE_RESET 0x0F |
#define USB_REQ_GET_HANDSHAKE 0x10 |
#define USB_REQ_SET_CONNECTION 0x11 |
#define USB_REQ_SET_SECURITY_DATA 0x12 |
#define USB_REQ_GET_SECURITY_DATA 0x13 |
#define USB_REQ_SET_WUSB_DATA 0x14 |
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15 |
#define USB_REQ_LOOPBACK_DATA_READ 0x16 |
#define USB_REQ_SET_INTERFACE_DS 0x17 |
/* |
* USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and |
* are read as a bit array returned by USB_REQ_GET_STATUS. (So there |
* are at most sixteen features of each type.) |
*/ |
#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ |
#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ |
#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */ |
#define USB_DEVICE_BATTERY 2 /* (wireless) */ |
#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */ |
#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/ |
#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */ |
#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */ |
#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ |
#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ |
/** |
* struct usb_ctrlrequest - SETUP data for a USB device control request |
* @bRequestType: matches the USB bmRequestType field |
* @bRequest: matches the USB bRequest field |
* @wValue: matches the USB wValue field (le16 byte order) |
* @wIndex: matches the USB wIndex field (le16 byte order) |
* @wLength: matches the USB wLength field (le16 byte order) |
* |
* This structure is used to send control requests to a USB device. It matches |
* the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the |
* USB spec for a fuller description of the different fields, and what they are |
* used for. |
* |
* Note that the driver for any interface can issue control requests. |
* For most devices, interfaces don't coordinate with each other, so |
* such requests may be made at any time. |
*/ |
struct usb_ctrlrequest { |
__u8 bRequestType; |
__u8 bRequest; |
__le16 wValue; |
__le16 wIndex; |
__le16 wLength; |
} __attribute__ ((packed)); |
/*-------------------------------------------------------------------------*/ |
/* |
* STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or |
* (rarely) accepted by SET_DESCRIPTOR. |
* |
* Note that all multi-byte values here are encoded in little endian |
* byte order "on the wire". But when exposed through Linux-USB APIs, |
* they've been converted to cpu byte order. |
*/ |
/* |
* Descriptor types ... USB 2.0 spec table 9.5 |
*/ |
#define USB_DT_DEVICE 0x01 |
#define USB_DT_CONFIG 0x02 |
#define USB_DT_STRING 0x03 |
#define USB_DT_INTERFACE 0x04 |
#define USB_DT_ENDPOINT 0x05 |
#define USB_DT_DEVICE_QUALIFIER 0x06 |
#define USB_DT_OTHER_SPEED_CONFIG 0x07 |
#define USB_DT_INTERFACE_POWER 0x08 |
/* these are from a minor usb 2.0 revision (ECN) */ |
#define USB_DT_OTG 0x09 |
#define USB_DT_DEBUG 0x0a |
#define USB_DT_INTERFACE_ASSOCIATION 0x0b |
/* these are from the Wireless USB spec */ |
#define USB_DT_SECURITY 0x0c |
#define USB_DT_KEY 0x0d |
#define USB_DT_ENCRYPTION_TYPE 0x0e |
#define USB_DT_BOS 0x0f |
#define USB_DT_DEVICE_CAPABILITY 0x10 |
#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 |
#define USB_DT_WIRE_ADAPTER 0x21 |
#define USB_DT_RPIPE 0x22 |
/* conventional codes for class-specific descriptors */ |
#define USB_DT_CS_DEVICE 0x21 |
#define USB_DT_CS_CONFIG 0x22 |
#define USB_DT_CS_STRING 0x23 |
#define USB_DT_CS_INTERFACE 0x24 |
#define USB_DT_CS_ENDPOINT 0x25 |
/* All standard descriptors have these 2 fields at the beginning */ |
struct usb_descriptor_header { |
__u8 bLength; |
__u8 bDescriptorType; |
} __attribute__ ((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_DEVICE: Device descriptor */ |
struct usb_device_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__le16 bcdUSB; |
__u8 bDeviceClass; |
__u8 bDeviceSubClass; |
__u8 bDeviceProtocol; |
__u8 bMaxPacketSize0; |
__le16 idVendor; |
__le16 idProduct; |
__le16 bcdDevice; |
__u8 iManufacturer; |
__u8 iProduct; |
__u8 iSerialNumber; |
__u8 bNumConfigurations; |
} __attribute__ ((packed)); |
#define USB_DT_DEVICE_SIZE 18 |
/* |
* Device and/or Interface Class codes |
* as found in bDeviceClass or bInterfaceClass |
* and defined by www.usb.org documents |
*/ |
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ |
#define USB_CLASS_AUDIO 1 |
#define USB_CLASS_COMM 2 |
#define USB_CLASS_HID 3 |
#define USB_CLASS_PHYSICAL 5 |
#define USB_CLASS_STILL_IMAGE 6 |
#define USB_CLASS_PRINTER 7 |
#define USB_CLASS_MASS_STORAGE 8 |
#define USB_CLASS_HUB 9 |
#define USB_CLASS_CDC_DATA 0x0a |
#define USB_CLASS_CSCID 0x0b /* chip+ smart card */ |
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */ |
#define USB_CLASS_VIDEO 0x0e |
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0 |
#define USB_CLASS_MISC 0xef |
#define USB_CLASS_APP_SPEC 0xfe |
#define USB_CLASS_VENDOR_SPEC 0xff |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_CONFIG: Configuration descriptor information. |
* |
* USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the |
* descriptor type is different. Highspeed-capable devices can look |
* different depending on what speed they're currently running. Only |
* devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG |
* descriptors. |
*/ |
struct usb_config_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__le16 wTotalLength; |
__u8 bNumInterfaces; |
__u8 bConfigurationValue; |
__u8 iConfiguration; |
__u8 bmAttributes; |
__u8 bMaxPower; |
} __attribute__ ((packed)); |
#define USB_DT_CONFIG_SIZE 9 |
/* from config descriptor bmAttributes */ |
#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ |
#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ |
#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ |
#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */ |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_STRING: String descriptor */ |
struct usb_string_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__le16 wData[1]; /* UTF-16LE encoded */ |
} __attribute__ ((packed)); |
/* note that "string" zero is special, it holds language codes that |
* the device supports, not Unicode characters. |
*/ |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_INTERFACE: Interface descriptor */ |
struct usb_interface_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__u8 bInterfaceNumber; |
__u8 bAlternateSetting; |
__u8 bNumEndpoints; |
__u8 bInterfaceClass; |
__u8 bInterfaceSubClass; |
__u8 bInterfaceProtocol; |
__u8 iInterface; |
} __attribute__ ((packed)); |
#define USB_DT_INTERFACE_SIZE 9 |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_ENDPOINT: Endpoint descriptor */ |
struct usb_endpoint_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__u8 bEndpointAddress; |
__u8 bmAttributes; |
__le16 wMaxPacketSize; |
__u8 bInterval; |
/* NOTE: these two are _only_ in audio endpoints. */ |
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ |
__u8 bRefresh; |
__u8 bSynchAddress; |
} __attribute__ ((packed)); |
#define USB_DT_ENDPOINT_SIZE 7 |
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ |
/* |
* Endpoints |
*/ |
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ |
#define USB_ENDPOINT_DIR_MASK 0x80 |
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ |
#define USB_ENDPOINT_XFER_CONTROL 0 |
#define USB_ENDPOINT_XFER_ISOC 1 |
#define USB_ENDPOINT_XFER_BULK 2 |
#define USB_ENDPOINT_XFER_INT 3 |
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ |
struct usb_qualifier_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__le16 bcdUSB; |
__u8 bDeviceClass; |
__u8 bDeviceSubClass; |
__u8 bDeviceProtocol; |
__u8 bMaxPacketSize0; |
__u8 bNumConfigurations; |
__u8 bRESERVED; |
} __attribute__ ((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_OTG (from OTG 1.0a supplement) */ |
struct usb_otg_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__u8 bmAttributes; /* support for HNP, SRP, etc */ |
} __attribute__ ((packed)); |
/* from usb_otg_descriptor.bmAttributes */ |
#define USB_OTG_SRP (1 << 0) |
#define USB_OTG_HNP (1 << 1) /* swap host/device roles */ |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */ |
struct usb_debug_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
/* bulk endpoints with 8 byte maxpacket */ |
__u8 bDebugInEndpoint; |
__u8 bDebugOutEndpoint; |
} __attribute__((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */ |
struct usb_interface_assoc_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__u8 bFirstInterface; |
__u8 bInterfaceCount; |
__u8 bFunctionClass; |
__u8 bFunctionSubClass; |
__u8 bFunctionProtocol; |
__u8 iFunction; |
} __attribute__ ((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_SECURITY: group of wireless security descriptors, including |
* encryption types available for setting up a CC/association. |
*/ |
struct usb_security_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__le16 wTotalLength; |
__u8 bNumEncryptionTypes; |
} __attribute__((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys |
* may be retrieved. |
*/ |
struct usb_key_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__u8 tTKID[3]; |
__u8 bReserved; |
__u8 bKeyData[0]; |
} __attribute__((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */ |
struct usb_encryption_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__u8 bEncryptionType; |
#define USB_ENC_TYPE_UNSECURE 0 |
#define USB_ENC_TYPE_WIRED 1 /* non-wireless mode */ |
#define USB_ENC_TYPE_CCM_1 2 /* aes128/cbc session */ |
#define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */ |
__u8 bEncryptionValue; /* use in SET_ENCRYPTION */ |
__u8 bAuthKeyIndex; |
} __attribute__((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_BOS: group of wireless capabilities */ |
struct usb_bos_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__le16 wTotalLength; |
__u8 bNumDeviceCaps; |
} __attribute__((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_DEVICE_CAPABILITY: grouped with BOS */ |
struct usb_dev_cap_header { |
__u8 bLength; |
__u8 bDescriptorType; |
__u8 bDevCapabilityType; |
} __attribute__((packed)); |
#define USB_CAP_TYPE_WIRELESS_USB 1 |
struct usb_wireless_cap_descriptor { /* Ultra Wide Band */ |
__u8 bLength; |
__u8 bDescriptorType; |
__u8 bDevCapabilityType; |
__u8 bmAttributes; |
#define USB_WIRELESS_P2P_DRD (1 << 1) |
#define USB_WIRELESS_BEACON_MASK (3 << 2) |
#define USB_WIRELESS_BEACON_SELF (1 << 2) |
#define USB_WIRELESS_BEACON_DIRECTED (2 << 2) |
#define USB_WIRELESS_BEACON_NONE (3 << 2) |
__le16 wPHYRates; /* bit rates, Mbps */ |
#define USB_WIRELESS_PHY_53 (1 << 0) /* always set */ |
#define USB_WIRELESS_PHY_80 (1 << 1) |
#define USB_WIRELESS_PHY_107 (1 << 2) /* always set */ |
#define USB_WIRELESS_PHY_160 (1 << 3) |
#define USB_WIRELESS_PHY_200 (1 << 4) /* always set */ |
#define USB_WIRELESS_PHY_320 (1 << 5) |
#define USB_WIRELESS_PHY_400 (1 << 6) |
#define USB_WIRELESS_PHY_480 (1 << 7) |
__u8 bmTFITXPowerInfo; /* TFI power levels */ |
__u8 bmFFITXPowerInfo; /* FFI power levels */ |
__le16 bmBandGroup; |
__u8 bReserved; |
} __attribute__((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with |
* each endpoint descriptor for a wireless device |
*/ |
struct usb_wireless_ep_comp_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__u8 bMaxBurst; |
__u8 bMaxSequence; |
__le16 wMaxStreamDelay; |
__le16 wOverTheAirPacketSize; |
__u8 bOverTheAirInterval; |
__u8 bmCompAttributes; |
#define USB_ENDPOINT_SWITCH_MASK 0x03 /* in bmCompAttributes */ |
#define USB_ENDPOINT_SWITCH_NO 0 |
#define USB_ENDPOINT_SWITCH_SWITCH 1 |
#define USB_ENDPOINT_SWITCH_SCALE 2 |
} __attribute__((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless |
* host and a device for connection set up, mutual authentication, and |
* exchanging short lived session keys. The handshake depends on a CC. |
*/ |
struct usb_handshake { |
__u8 bMessageNumber; |
__u8 bStatus; |
__u8 tTKID[3]; |
__u8 bReserved; |
__u8 CDID[16]; |
__u8 nonce[16]; |
__u8 MIC[8]; |
} __attribute__((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC). |
* A CC may also be set up using non-wireless secure channels (including |
* wired USB!), and some devices may support CCs with multiple hosts. |
*/ |
struct usb_connection_context { |
__u8 CHID[16]; /* persistent host id */ |
__u8 CDID[16]; /* device id (unique w/in host context) */ |
__u8 CK[16]; /* connection key */ |
} __attribute__((packed)); |
/*-------------------------------------------------------------------------*/ |
/* USB 2.0 defines three speeds, here's how Linux identifies them */ |
enum usb_device_speed { |
USB_SPEED_UNKNOWN = 0, /* enumerating */ |
USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ |
USB_SPEED_HIGH, /* usb 2.0 */ |
USB_SPEED_VARIABLE, /* wireless (usb 2.5) */ |
}; |
enum usb_device_state { |
/* NOTATTACHED isn't in the USB spec, and this state acts |
* the same as ATTACHED ... but it's clearer this way. |
*/ |
USB_STATE_NOTATTACHED = 0, |
/* chapter 9 and authentication (wireless) device states */ |
USB_STATE_ATTACHED, |
USB_STATE_POWERED, /* wired */ |
USB_STATE_UNAUTHENTICATED, /* auth */ |
USB_STATE_RECONNECTING, /* auth */ |
USB_STATE_DEFAULT, /* limited function */ |
USB_STATE_ADDRESS, |
USB_STATE_CONFIGURED, /* most functions */ |
USB_STATE_SUSPENDED |
/* NOTE: there are actually four different SUSPENDED |
* states, returning to POWERED, DEFAULT, ADDRESS, or |
* CONFIGURED respectively when SOF tokens flow again. |
*/ |
}; |
#endif /* __LINUX_USB_CH9_H */ |
/drivers/usb/uhci/detect.inc |
---|
0,0 → 1,63 |
static Bool FindPciDevice() |
{ |
Bool retval = FALSE; |
u32_t bus, last_bus; |
PCITAG tag; |
if( (last_bus = PciApi(1))==-1) |
return retval; |
for(bus=0;bus<=last_bus;bus++) |
{ |
u32_t devfn; |
for(devfn=0;devfn<256;devfn++) |
{ |
hc_t *hc; |
u32_t id; |
u16_t pcicmd; |
u16_t devclass; |
int i; |
devclass = PciRead16(bus,devfn, 0x0A); |
if( devclass != 0x0C03) |
continue; |
pcicmd = PciRead16(bus,devfn, PCI_COMMAND); |
if (! pcicmd & PCI_COMMAND_IO) |
continue; |
hc = (hc_t*)malloc(sizeof(hc_t)); |
memset(hc, 0, sizeof(hc_t)); |
link_initialize(&hc->link); |
hc->pciId = PciRead32(bus,devfn, 0); |
hc->PciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7); |
for (i = 0; i < 6; i++) |
{ |
u32_t base; |
Bool validSize; |
base = PciRead32(bus,devfn, PCI_MAP_REG_START + (i << 2)); |
if(base) |
{ |
if (base & PCI_MAP_IO) { |
hc->ioBase[i] = (addr_t)PCIGETIO(base); |
hc->memType[i] = base & PCI_MAP_IO_ATTR_MASK; |
} else { |
hc->memBase[i] = (u32_t)PCIGETMEMORY(base); |
hc->memType[i] = base & PCI_MAP_MEMORY_ATTR_MASK; |
} |
} |
}; |
list_prepend(&hc->link, &hc_list); |
retval = TRUE; |
}; |
}; |
return retval; |
}; |
/drivers/usb/uhci/hcd.inc |
---|
0,0 → 1,604 |
#define UHCI_USBLEGSUP 0x00c0 /* legacy support */ |
#define UHCI_USBCMD 0 /* command register */ |
#define UHCI_USBINTR 4 /* interrupt register */ |
#define UHCI_USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ |
#define UHCI_USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ |
#define UHCI_USBCMD_RUN 0x0001 /* RUN/STOP bit */ |
#define UHCI_USBCMD_HCRESET 0x0002 /* Host Controller reset */ |
#define UHCI_USBCMD_EGSM 0x0008 /* Global Suspend Mode */ |
#define UHCI_USBCMD_CONFIGURE 0x0040 /* Config Flag */ |
#define UHCI_USBINTR_RESUME 0x0002 /* Resume interrupt enable */ |
#define USBCMD 0 |
#define USBCMD_RS 0x0001 /* Run/Stop */ |
#define USBCMD_HCRESET 0x0002 /* Host reset */ |
#define USBCMD_GRESET 0x0004 /* Global reset */ |
#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */ |
#define USBCMD_FGR 0x0010 /* Force Global Resume */ |
#define USBCMD_SWDBG 0x0020 /* SW Debug mode */ |
#define USBCMD_CF 0x0040 /* Config Flag (sw only) */ |
#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */ |
#define USBSTS 2 |
#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ |
#define USBSTS_ERROR 0x0002 /* Interrupt due to error */ |
#define USBSTS_RD 0x0004 /* Resume Detect */ |
#define USBSTS_HSE 0x0008 /* Host System Error: PCI problems */ |
#define USBSTS_HCPE 0x0010 /* Host Controller Process Error: |
* the schedule is buggy */ |
#define USBSTS_HCH 0x0020 /* HC Halted */ |
#define USBFRNUM 6 |
#define USBFLBASEADD 8 |
#define USBSOF 12 |
#define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */ |
#define USBPORTSC1 16 |
#define USBPORTSC2 18 |
#define UHCI_RH_MAXCHILD 7 |
/* |
* Make sure the controller is completely inactive, unable to |
* generate interrupts or do DMA. |
*/ |
void uhci_reset_hc(hc_t *hc) |
{ |
/* Turn off PIRQ enable and SMI enable. (This also turns off the |
* BIOS's USB Legacy Support.) Turn off all the R/WC bits too. |
*/ |
pciWriteWord(hc->PciTag, UHCI_USBLEGSUP, UHCI_USBLEGSUP_RWC); |
/* Reset the HC - this will force us to get a |
* new notification of any already connected |
* ports due to the virtual disconnect that it |
* implies. |
*/ |
out16(hc->iobase + UHCI_USBCMD, UHCI_USBCMD_HCRESET); |
__asm__ __volatile__ ("":::"memory"); |
delay(20/10); |
if (in16(hc->iobase + UHCI_USBCMD) & UHCI_USBCMD_HCRESET) |
dbgprintf("HCRESET not completed yet!\n"); |
/* Just to be safe, disable interrupt requests and |
* make sure the controller is stopped. |
*/ |
out16(hc->iobase + UHCI_USBINTR, 0); |
out16(hc->iobase + UHCI_USBCMD, 0); |
}; |
int uhci_check_and_reset_hc(hc_t *hc) |
{ |
u16_t legsup; |
unsigned int cmd, intr; |
/* |
* When restarting a suspended controller, we expect all the |
* settings to be the same as we left them: |
* |
* PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; |
* Controller is stopped and configured with EGSM set; |
* No interrupts enabled except possibly Resume Detect. |
* |
* If any of these conditions are violated we do a complete reset. |
*/ |
legsup = pciReadWord(hc->PciTag, UHCI_USBLEGSUP); |
if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) { |
dbgprintf("%s: legsup = 0x%04x\n",__FUNCTION__, legsup); |
goto reset_needed; |
} |
cmd = in16(hc->iobase + UHCI_USBCMD); |
if ( (cmd & UHCI_USBCMD_RUN) || |
!(cmd & UHCI_USBCMD_CONFIGURE) || |
!(cmd & UHCI_USBCMD_EGSM)) |
{ |
dbgprintf("%s: cmd = 0x%04x\n", __FUNCTION__, cmd); |
goto reset_needed; |
} |
intr = in16(hc->iobase + UHCI_USBINTR); |
if (intr & (~UHCI_USBINTR_RESUME)) |
{ |
dbgprintf("%s: intr = 0x%04x\n", __FUNCTION__, intr); |
goto reset_needed; |
} |
return 0; |
reset_needed: |
dbgprintf("Performing full reset\n"); |
uhci_reset_hc(hc); |
return 1; |
} |
Bool init_hc(hc_t *hc) |
{ |
int port; |
u32_t ifl; |
u16_t dev_status; |
int i; |
dbgprintf("\n\ninit uhci %x\n\n", hc->pciId); |
for(i=0;i<6;i++) |
{ |
if(hc->ioBase[i]){ |
hc->iobase = hc->ioBase[i]; |
// dbgprintf("Io base_%d 0x%x\n", i,hc->ioBase[i]); |
break; |
}; |
}; |
/* The UHCI spec says devices must have 2 ports, and goes on to say |
* they may have more but gives no way to determine how many there |
* are. However according to the UHCI spec, Bit 7 of the port |
* status and control register is always set to 1. So we try to |
* use this to our advantage. Another common failure mode when |
* a nonexistent register is addressed is to return all ones, so |
* we test for that also. |
*/ |
for (port = 0; port < 2; port++) |
{ |
u32_t status; |
status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
dbgprintf("port%d status %x\n", port, status); |
if (!(status & 0x0080) || status == 0xffff) |
break; |
} |
dbgprintf("detected %d ports\n\n", port); |
hc->numports = port; |
/* Kick BIOS off this hardware and reset if the controller |
* isn't already safely quiescent. |
*/ |
uhci_check_and_reset_hc(hc); |
hc->frame_base = (u32_t*)KernelAlloc(4096); |
hc->frame_dma = GetPgAddr(hc->frame_base); |
hc->frame_number = 0; |
qh_t *qh = alloc_qh(); |
qh->qlink = 1; |
qh->qelem = 1; |
hc->qh1 = qh; |
// dbgprintf("alloc qh %x dma %x\n", qh, qh->dma); |
for(i=0; i<1024; i++) |
hc->frame_base[i] = qh->dma | 2; |
/* Set the frame length to the default: 1 ms exactly */ |
out8(hc->iobase + USBSOF, USBSOF_DEFAULT); |
/* Store the frame list base address */ |
out32(hc->iobase + USBFLBASEADD, hc->frame_dma); |
/* Set the current frame number */ |
out16(hc->iobase + USBFRNUM, 0); |
out16(hc->iobase + USBSTS, 0x3F); |
out16(hc->iobase + USBCMD, USBCMD_RS | USBCMD_CF | |
USBCMD_MAXP); |
for (port = 0; port < hc->numports; ++port) |
out16(hc->iobase + USBPORTSC1 + (port * 2), 0x200); |
delay(100/10); |
for (port = 0; port < 2; ++port) |
{ |
time_t timeout; |
u32_t status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
dbgprintf("port%d status %x\n", port, status); |
out16(hc->iobase + USBPORTSC1 + (port * 2), 0); |
timeout = 100/10; |
while(timeout--) |
{ |
delay(10/10); |
status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
if(status & 1) |
{ |
udev_t *dev = malloc(sizeof(udev_t)); |
out16(hc->iobase + USBPORTSC1 + (port * 2), 0x0E); |
delay(20/10); |
dbgprintf("enable port\n"); |
status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
dbgprintf("port%d status %x\n", port, status); |
link_initialize(&dev->link); |
dev->id = 0; |
dev->host = hc; |
dev->addr = 0; |
dev->port = port; |
dev->ep0_size = 8; |
dev->status = status; |
dbgprintf("port%d connected", port); |
if(status & 4) |
dbgprintf(" enabled"); |
else |
dbgprintf(" disabled"); |
if(status & 0x100){ |
dev->speed = 0x4000000; |
dbgprintf(" low speed\n"); |
} else { |
dev->speed = 0; |
dbgprintf(" full speed\n"); |
}; |
if(set_address(dev)) { |
list_prepend(&dev->link, &newdev_list); |
hc->port_map |= 1<<port; |
} |
else { |
free(dev); |
out16(hc->iobase + USBPORTSC1 + (port * 2), 0); |
} |
break; |
}; |
}; |
}; |
return TRUE; |
}; |
u16_t __attribute__((aligned(16))) |
req_descr[4] = {0x0680,0x0100,0x0000,8}; |
/* |
IN(69) OUT(E1) SETUP(2D) |
SETUP(0) IN(1) |
SETUP(0) OUT(1) OUT(0) OUT(1)...IN(1) |
SETUP(0) IN(1) IN(0) IN(1)...OUT(0) |
*/ |
Bool set_address(udev_t *dev) |
{ |
static udev_id = 0; |
static udev_addr = 0; |
static u16_t __attribute__((aligned(16))) |
req_addr[4] = {0x0500,0x0001,0x0000,0x0000}; |
static u16_t __attribute__((aligned(16))) |
req_descr[4] = {0x0680,0x0100,0x0000,8}; |
static u32_t data[2] __attribute__((aligned(16))); |
qh_t *qh; |
td_t *td0, *td1, *td2; |
u32_t dev_status; |
count_t timeout; |
int address; |
address = ++udev_addr; |
req_addr[1] = address; |
if( !ctrl_request(dev, &req_addr, DOUT, NULL, 0)) |
return FALSE; |
dev->addr = address; |
dev->id = (++udev_id << 8) | address; |
dbgprintf("set address %d\n", address); |
data[0] = 0; |
data[1] = 0; |
if( !ctrl_request(dev, &req_descr, DIN, data, 8)) |
return FALSE; |
dev_descr_t *descr = (dev_descr_t*)&data; |
dev->ep0_size = descr->bMaxPacketSize0; |
return TRUE; |
} |
request_t *create_request(udev_t *dev, endp_t *enp, u32_t dir, |
void *data, size_t req_size) |
{ |
td_t *td, *td_prev; |
addr_t data_dma; |
request_t *rq = (request_t*)malloc(sizeof(request_t)); |
link_initialize(&rq->link); |
rq->td_head = 0; |
rq->td_tail = 0; |
rq->data = (addr_t)data; |
rq->size = req_size; |
rq->dev = dev; |
if(data) |
data_dma = DMA(data); |
td_prev = NULL; |
while(req_size >= enp->size) |
{ |
td = alloc_td(); |
td->link = 1; |
if(rq->td_head == NULL) |
rq->td_head = td; |
if( td_prev ) |
td_prev->link = td->dma | 4; |
td->status = 0x00800000 | dev->speed; |
td->token = TOKEN(enp->size,enp->toggle,enp->address, |
dev->addr,dir); |
td->buffer = data_dma; |
td->bk = td_prev; |
td_prev = td; |
data_dma+= enp->size; |
req_size-= enp->size; |
enp->toggle ^= DATA1; |
} |
if(req_size) |
{ |
td = alloc_td(); |
td->link = 1; |
if(rq->td_head == NULL) |
rq->td_head = td; |
if( td_prev ) |
td_prev->link = td->dma | 4; |
td->status = 0x00800000 | dev->speed; |
td->token = TOKEN( req_size, enp->toggle, enp->address, |
dev->addr, dir); |
td->buffer = data_dma; |
td->bk = td_prev; |
enp->toggle ^= DATA1; |
} |
rq->td_tail = td; |
/* |
dbgprintf("create request %x\n" |
"head %x\n" |
"tail %x\n" |
"data %x\n" |
"size %x\n", |
rq, rq->td_head, rq->td_tail, |
rq->data, rq->size); |
*/ |
return rq; |
} |
Bool ctrl_request(udev_t *dev, void *req, u32_t pid, |
void *data, size_t req_size) |
{ |
size_t packet_size = dev->ep0_size; |
size_t size = req_size; |
u32_t toggle = DATA1; |
td_t *td0, *td, *td_prev; |
qh_t *qh; |
addr_t data_dma = 0; |
Bool retval; |
td0 = alloc_td(); |
td0->status = 0x00800000 | dev->speed; |
td0->token = TOKEN( 8, DATA0, 0, dev->addr, 0x2D); |
td0->buffer = DMA(req); |
td0->bk = NULL; |
if(data) |
data_dma = DMA(data); |
td_prev = td0; |
while(size >= packet_size) |
{ |
td = alloc_td(); |
td_prev->link = td->dma | 4; |
td->status = 0x00800000 | dev->speed; |
td->token = TOKEN(packet_size, toggle, 0,dev->addr, pid); |
td->buffer = data_dma; |
td->bk = td_prev; |
td_prev = td; |
data_dma+= packet_size; |
size-= packet_size; |
toggle ^= DATA1; |
} |
if(size) |
{ |
td = alloc_td(); |
td_prev->link = td->dma | 4; |
td->status = 0x00800000 | dev->speed; |
td->token = ((size-1)<<21)|toggle|(dev->addr<<8)|pid; |
td->buffer = data_dma; |
td->bk = td_prev; |
td_prev = td; |
data_dma+= packet_size; |
size-= packet_size; |
toggle ^= DATA1; |
} |
td = alloc_td(); |
td_prev->link = td->dma | 4; |
pid = (pid == DIN) ? DOUT : DIN; |
td->link = 1; |
td->status = 0x00800000 | dev->speed; |
td->token = (0x7FF<<21)|DATA1|(dev->addr<<8)|pid; |
td->buffer = 0; |
td->bk = td_prev; |
qh = dev->host->qh1; |
qh->qelem = td0->dma; |
__asm__ __volatile__ ("":::"memory"); |
count_t timeout = 25; |
while(timeout--){ |
delay(10/10); |
if( !(td->status & TD_CTRL_ACTIVE)) |
break; |
} |
if( (td0->status & TD_ANY_ERROR) || |
(td_prev->status & TD_ANY_ERROR) || |
(td->status & TD_ANY_ERROR)) |
{ |
u32_t dev_status = in16(dev->host->iobase + USBSTS); |
dbgprintf("\nframe %x, cmd %x status %x\n", |
in16(dev->host->iobase + USBFRNUM), |
in16(dev->host->iobase + USBCMD), |
dev_status); |
dbgprintf("td0 status %x\n",td0->status); |
dbgprintf("td_prev status %x\n",td_prev->status); |
dbgprintf("td status %x\n",td->status); |
dbgprintf("qh %x \n", qh->qelem); |
retval = FALSE; |
} else retval = TRUE; |
do |
{ |
td_prev = td->bk; |
free_td(td); |
td = td_prev; |
}while( td != NULL); |
return retval; |
}; |
Bool init_device(udev_t *dev) |
{ |
static u16_t __attribute__((aligned(16))) |
req_descr[4] = {0x0680,0x0100,0x0000,18}; |
static u16_t __attribute__((aligned(16))) |
req_conf[4] = {0x0680,0x0200,0x0000,9}; |
static dev_descr_t __attribute__((aligned(16))) descr; |
interface_descr_t *interface; |
u32_t data[8]; |
u8_t *dptr; |
conf_descr_t *conf; |
dbgprintf("\ninit device %x, host %x, port %d\n\n", |
dev->id, dev->host->pciId, dev->port); |
if( !ctrl_request(dev, req_descr, DIN, &descr, 18)) |
return; |
dev->dev_descr = descr; |
dbgprintf("device descriptor:\n\n" |
"bLength %d\n" |
"bDescriptorType %d\n" |
"bcdUSB %x\n" |
"bDeviceClass %x\n" |
"bDeviceSubClass %x\n" |
"bDeviceProtocol %x\n" |
"bMaxPacketSize0 %d\n" |
"idVendor %x\n" |
"idProduct %x\n" |
"bcdDevice %x\n" |
"iManufacturer %x\n" |
"iProduct %x\n" |
"iSerialNumber %x\n" |
"bNumConfigurations %d\n\n", |
descr.bLength, descr.bDescriptorType, |
descr.bcdUSB, descr.bDeviceClass, |
descr.bDeviceSubClass, descr.bDeviceProtocol, |
descr.bMaxPacketSize0, descr.idVendor, |
descr.idProduct, descr.bcdDevice, |
descr.iManufacturer, descr.iProduct, |
descr.iSerialNumber, descr.bNumConfigurations); |
req_conf[3] = 8; |
if( !ctrl_request(dev, req_conf, DIN, &data, 8)) |
return; |
conf = (conf_descr_t*)&data; |
size_t conf_size = conf->wTotalLength; |
req_conf[3] = conf_size; |
conf = malloc(conf_size); |
if( !ctrl_request(dev, req_conf, DIN, conf, conf_size)) |
return; |
dptr = (u8_t*)conf; |
dptr+= conf->bLength; |
dbgprintf("configuration descriptor\n\n" |
"bLength %d\n" |
"bDescriptorType %d\n" |
"wTotalLength %d\n" |
"bNumInterfaces %d\n" |
"bConfigurationValue %x\n" |
"iConfiguration %d\n" |
"bmAttributes %x\n" |
"bMaxPower %dmA\n\n", |
conf->bLength, |
conf->bDescriptorType, |
conf->wTotalLength, |
conf->bNumInterfaces, |
conf->bConfigurationValue, |
conf->iConfiguration, |
conf->bmAttributes, |
conf->bMaxPower*2); |
interface = (interface_descr_t*)dptr; |
switch(interface->bInterfaceClass) |
{ |
case USB_CLASS_AUDIO: |
dbgprintf( "audio device\n"); |
break; |
case USB_CLASS_HID: |
dev->conf = conf; |
list_remove(&dev->link); |
return init_hid(dev); |
case USB_CLASS_PRINTER: |
dbgprintf("printer\n"); |
break; |
case USB_CLASS_MASS_STORAGE: |
dbgprintf("mass storage device\n"); |
break; |
case USB_CLASS_HUB: |
dbgprintf("hub device\n"); |
break; |
default: |
dbgprintf("unknown device\n"); |
}; |
}; |
/drivers/usb/uhci/hid.h |
---|
0,0 → 1,523 |
#ifndef __HID_H |
#define __HID_H |
/* |
* $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $ |
* |
* Copyright (c) 1999 Andreas Gal |
* Copyright (c) 2000-2001 Vojtech Pavlik |
* Copyright (c) 2006-2007 Jiri Kosina |
*/ |
/* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
* |
* Should you need to contact me, the author, you can do so either by |
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
*/ |
#include <linux/types.h> |
#include <linux/slab.h> |
#include <linux/list.h> |
#include <linux/timer.h> |
#include <linux/workqueue.h> |
#include <linux/input.h> |
/* |
* USB HID (Human Interface Device) interface class code |
*/ |
#define USB_INTERFACE_CLASS_HID 3 |
/* |
* USB HID interface subclass and protocol codes |
*/ |
#define USB_INTERFACE_SUBCLASS_BOOT 1 |
#define USB_INTERFACE_PROTOCOL_KEYBOARD 1 |
#define USB_INTERFACE_PROTOCOL_MOUSE 2 |
/* |
* HID class requests |
*/ |
#define HID_REQ_GET_REPORT 0x01 |
#define HID_REQ_GET_IDLE 0x02 |
#define HID_REQ_GET_PROTOCOL 0x03 |
#define HID_REQ_SET_REPORT 0x09 |
#define HID_REQ_SET_IDLE 0x0A |
#define HID_REQ_SET_PROTOCOL 0x0B |
/* |
* HID class descriptor types |
*/ |
#define HID_DT_HID (USB_TYPE_CLASS | 0x01) |
#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) |
#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) |
/* |
* We parse each description item into this structure. Short items data |
* values are expanded to 32-bit signed int, long items contain a pointer |
* into the data area. |
*/ |
struct hid_item { |
unsigned format; |
__u8 size; |
__u8 type; |
__u8 tag; |
union { |
__u8 u8; |
__s8 s8; |
__u16 u16; |
__s16 s16; |
__u32 u32; |
__s32 s32; |
__u8 *longdata; |
} data; |
}; |
/* |
* HID report item format |
*/ |
#define HID_ITEM_FORMAT_SHORT 0 |
#define HID_ITEM_FORMAT_LONG 1 |
/* |
* Special tag indicating long items |
*/ |
#define HID_ITEM_TAG_LONG 15 |
/* |
* HID report descriptor item type (prefix bit 2,3) |
*/ |
#define HID_ITEM_TYPE_MAIN 0 |
#define HID_ITEM_TYPE_GLOBAL 1 |
#define HID_ITEM_TYPE_LOCAL 2 |
#define HID_ITEM_TYPE_RESERVED 3 |
/* |
* HID report descriptor main item tags |
*/ |
#define HID_MAIN_ITEM_TAG_INPUT 8 |
#define HID_MAIN_ITEM_TAG_OUTPUT 9 |
#define HID_MAIN_ITEM_TAG_FEATURE 11 |
#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 |
#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 |
/* |
* HID report descriptor main item contents |
*/ |
#define HID_MAIN_ITEM_CONSTANT 0x001 |
#define HID_MAIN_ITEM_VARIABLE 0x002 |
#define HID_MAIN_ITEM_RELATIVE 0x004 |
#define HID_MAIN_ITEM_WRAP 0x008 |
#define HID_MAIN_ITEM_NONLINEAR 0x010 |
#define HID_MAIN_ITEM_NO_PREFERRED 0x020 |
#define HID_MAIN_ITEM_NULL_STATE 0x040 |
#define HID_MAIN_ITEM_VOLATILE 0x080 |
#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 |
/* |
* HID report descriptor collection item types |
*/ |
#define HID_COLLECTION_PHYSICAL 0 |
#define HID_COLLECTION_APPLICATION 1 |
#define HID_COLLECTION_LOGICAL 2 |
/* |
* HID report descriptor global item tags |
*/ |
#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 |
#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 |
#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 |
#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 |
#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 |
#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 |
#define HID_GLOBAL_ITEM_TAG_UNIT 6 |
#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 |
#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 |
#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 |
#define HID_GLOBAL_ITEM_TAG_PUSH 10 |
#define HID_GLOBAL_ITEM_TAG_POP 11 |
/* |
* HID report descriptor local item tags |
*/ |
#define HID_LOCAL_ITEM_TAG_USAGE 0 |
#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 |
#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 |
#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 |
#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 |
#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 |
#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 |
#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 |
#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 |
#define HID_LOCAL_ITEM_TAG_DELIMITER 10 |
/* |
* HID usage tables |
*/ |
#define HID_USAGE_PAGE 0xffff0000 |
#define HID_UP_UNDEFINED 0x00000000 |
#define HID_UP_GENDESK 0x00010000 |
#define HID_UP_SIMULATION 0x00020000 |
#define HID_UP_KEYBOARD 0x00070000 |
#define HID_UP_LED 0x00080000 |
#define HID_UP_BUTTON 0x00090000 |
#define HID_UP_ORDINAL 0x000a0000 |
#define HID_UP_CONSUMER 0x000c0000 |
#define HID_UP_DIGITIZER 0x000d0000 |
#define HID_UP_PID 0x000f0000 |
#define HID_UP_HPVENDOR 0xff7f0000 |
#define HID_UP_MSVENDOR 0xff000000 |
#define HID_UP_CUSTOM 0x00ff0000 |
#define HID_UP_LOGIVENDOR 0xffbc0000 |
#define HID_USAGE 0x0000ffff |
#define HID_GD_POINTER 0x00010001 |
#define HID_GD_MOUSE 0x00010002 |
#define HID_GD_JOYSTICK 0x00010004 |
#define HID_GD_GAMEPAD 0x00010005 |
#define HID_GD_KEYBOARD 0x00010006 |
#define HID_GD_KEYPAD 0x00010007 |
#define HID_GD_MULTIAXIS 0x00010008 |
#define HID_GD_X 0x00010030 |
#define HID_GD_Y 0x00010031 |
#define HID_GD_Z 0x00010032 |
#define HID_GD_RX 0x00010033 |
#define HID_GD_RY 0x00010034 |
#define HID_GD_RZ 0x00010035 |
#define HID_GD_SLIDER 0x00010036 |
#define HID_GD_DIAL 0x00010037 |
#define HID_GD_WHEEL 0x00010038 |
#define HID_GD_HATSWITCH 0x00010039 |
#define HID_GD_BUFFER 0x0001003a |
#define HID_GD_BYTECOUNT 0x0001003b |
#define HID_GD_MOTION 0x0001003c |
#define HID_GD_START 0x0001003d |
#define HID_GD_SELECT 0x0001003e |
#define HID_GD_VX 0x00010040 |
#define HID_GD_VY 0x00010041 |
#define HID_GD_VZ 0x00010042 |
#define HID_GD_VBRX 0x00010043 |
#define HID_GD_VBRY 0x00010044 |
#define HID_GD_VBRZ 0x00010045 |
#define HID_GD_VNO 0x00010046 |
#define HID_GD_FEATURE 0x00010047 |
#define HID_GD_UP 0x00010090 |
#define HID_GD_DOWN 0x00010091 |
#define HID_GD_RIGHT 0x00010092 |
#define HID_GD_LEFT 0x00010093 |
/* |
* HID report types --- Ouch! HID spec says 1 2 3! |
*/ |
#define HID_INPUT_REPORT 0 |
#define HID_OUTPUT_REPORT 1 |
#define HID_FEATURE_REPORT 2 |
/* |
* HID device quirks. |
*/ |
#define HID_QUIRK_INVERT 0x00000001 |
#define HID_QUIRK_NOTOUCH 0x00000002 |
#define HID_QUIRK_IGNORE 0x00000004 |
#define HID_QUIRK_NOGET 0x00000008 |
#define HID_QUIRK_HIDDEV 0x00000010 |
#define HID_QUIRK_BADPAD 0x00000020 |
#define HID_QUIRK_MULTI_INPUT 0x00000040 |
#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 |
#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 |
#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 |
#define HID_QUIRK_MIGHTYMOUSE 0x00000400 |
#define HID_QUIRK_CYMOTION 0x00000800 |
#define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 |
#define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 |
#define HID_QUIRK_INVERT_HWHEEL 0x00004000 |
#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000 |
#define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000 |
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 |
#define HID_QUIRK_IGNORE_MOUSE 0x00040000 |
#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000 |
#define HID_QUIRK_LOGITECH_S510_DESCRIPTOR 0x00100000 |
#define HID_QUIRK_DUPLICATE_USAGES 0x00200000 |
/* |
* This is the global environment of the parser. This information is |
* persistent for main-items. The global environment can be saved and |
* restored with PUSH/POP statements. |
*/ |
struct hid_global { |
unsigned usage_page; |
__s32 logical_minimum; |
__s32 logical_maximum; |
__s32 physical_minimum; |
__s32 physical_maximum; |
__s32 unit_exponent; |
unsigned unit; |
unsigned report_id; |
unsigned report_size; |
unsigned report_count; |
}; |
/* |
* This is the local environment. It is persistent up the next main-item. |
*/ |
#define HID_MAX_DESCRIPTOR_SIZE 4096 |
#define HID_MAX_USAGES 8192 |
#define HID_DEFAULT_NUM_COLLECTIONS 16 |
struct hid_local { |
unsigned usage[HID_MAX_USAGES]; /* usage array */ |
unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ |
unsigned usage_index; |
unsigned usage_minimum; |
unsigned delimiter_depth; |
unsigned delimiter_branch; |
}; |
/* |
* This is the collection stack. We climb up the stack to determine |
* application and function of each field. |
*/ |
struct hid_collection { |
unsigned type; |
unsigned usage; |
unsigned level; |
}; |
struct hid_usage { |
unsigned hid; /* hid usage code */ |
unsigned collection_index; /* index into collection array */ |
/* hidinput data */ |
__u16 code; /* input driver code */ |
__u8 type; /* input driver type */ |
__s8 hat_min; /* hat switch fun */ |
__s8 hat_max; /* ditto */ |
__s8 hat_dir; /* ditto */ |
}; |
struct hid_input; |
struct hid_field { |
unsigned physical; /* physical usage for this field */ |
unsigned logical; /* logical usage for this field */ |
unsigned application; /* application usage for this field */ |
struct hid_usage *usage; /* usage table for this function */ |
unsigned maxusage; /* maximum usage index */ |
unsigned flags; /* main-item flags (i.e. volatile,array,constant) */ |
unsigned report_offset; /* bit offset in the report */ |
unsigned report_size; /* size of this field in the report */ |
unsigned report_count; /* number of this field in the report */ |
unsigned report_type; /* (input,output,feature) */ |
__s32 *value; /* last known value(s) */ |
__s32 logical_minimum; |
__s32 logical_maximum; |
__s32 physical_minimum; |
__s32 physical_maximum; |
__s32 unit_exponent; |
unsigned unit; |
struct hid_report *report; /* associated report */ |
unsigned index; /* index into report->field[] */ |
/* hidinput data */ |
struct hid_input *hidinput; /* associated input structure */ |
__u16 dpad; /* dpad input code */ |
}; |
#define HID_MAX_FIELDS 64 |
struct hid_report { |
struct list_head list; |
unsigned id; /* id of this report */ |
unsigned type; /* report type */ |
struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ |
unsigned maxfield; /* maximum valid field index */ |
unsigned size; /* size of the report (bits) */ |
struct hid_device *device; /* associated device */ |
}; |
struct hid_report_enum { |
unsigned numbered; |
struct list_head report_list; |
struct hid_report *report_id_hash[256]; |
}; |
#define HID_REPORT_TYPES 3 |
#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ |
#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */ |
#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ |
#define HID_OUTPUT_FIFO_SIZE 64 |
struct hid_control_fifo { |
unsigned char dir; |
struct hid_report *report; |
}; |
#define HID_CLAIMED_INPUT 1 |
#define HID_CLAIMED_HIDDEV 2 |
#define HID_CTRL_RUNNING 1 |
#define HID_OUT_RUNNING 2 |
#define HID_IN_RUNNING 3 |
#define HID_RESET_PENDING 4 |
#define HID_SUSPENDED 5 |
#define HID_CLEAR_HALT 6 |
struct hid_input { |
struct list_head list; |
struct hid_report *report; |
struct input_dev *input; |
}; |
struct hid_device { /* device report descriptor */ |
__u8 *rdesc; |
unsigned rsize; |
struct hid_collection *collection; /* List of HID collections */ |
unsigned collection_size; /* Number of allocated hid_collections */ |
unsigned maxcollection; /* Number of parsed collections */ |
unsigned maxapplication; /* Number of applications */ |
unsigned short bus; /* BUS ID */ |
unsigned short vendor; /* Vendor ID */ |
unsigned short product; /* Product ID */ |
unsigned version; /* HID version */ |
unsigned country; /* HID country */ |
struct hid_report_enum report_enum[HID_REPORT_TYPES]; |
struct device *dev; /* device */ |
unsigned claimed; /* Claimed by hidinput, hiddev? */ |
unsigned quirks; /* Various quirks the device can pull on us */ |
struct list_head inputs; /* The list of inputs */ |
void *hiddev; /* The hiddev structure */ |
int minor; /* Hiddev minor number */ |
wait_queue_head_t wait; /* For sleeping */ |
int open; /* is the device open by anyone? */ |
char name[128]; /* Device name */ |
char phys[64]; /* Device physical location */ |
char uniq[64]; /* Device unique identifier (serial #) */ |
void *driver_data; |
/* device-specific function pointers */ |
int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int); |
int (*hid_open) (struct hid_device *); |
void (*hid_close) (struct hid_device *); |
/* hiddev event handler */ |
void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field, |
struct hid_usage *, __s32); |
void (*hiddev_report_event) (struct hid_device *, struct hid_report *); |
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK |
unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; |
unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; |
#endif |
}; |
#define HID_GLOBAL_STACK_SIZE 4 |
#define HID_COLLECTION_STACK_SIZE 4 |
struct hid_parser { |
struct hid_global global; |
struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; |
unsigned global_stack_ptr; |
struct hid_local local; |
unsigned collection_stack[HID_COLLECTION_STACK_SIZE]; |
unsigned collection_stack_ptr; |
struct hid_device *device; |
}; |
struct hid_class_descriptor { |
__u8 bDescriptorType; |
__u16 wDescriptorLength; |
} __attribute__ ((packed)); |
struct hid_descriptor { |
__u8 bLength; |
__u8 bDescriptorType; |
__u16 bcdHID; |
__u8 bCountryCode; |
__u8 bNumDescriptors; |
struct hid_class_descriptor desc[1]; |
} __attribute__ ((packed)); |
/* Applications from HID Usage Tables 4/8/99 Version 1.1 */ |
/* We ignore a few input applications that are not widely used */ |
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) |
/* HID core API */ |
extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); |
extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); |
extern int hidinput_connect(struct hid_device *); |
extern void hidinput_disconnect(struct hid_device *); |
int hid_set_field(struct hid_field *, unsigned, __s32); |
int hid_input_report(struct hid_device *, int type, u8 *, int, int); |
int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); |
void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt); |
void hid_output_report(struct hid_report *report, __u8 *data); |
void hid_free_device(struct hid_device *device); |
struct hid_device *hid_parse_report(__u8 *start, unsigned size); |
#ifdef CONFIG_HID_FF |
int hid_ff_init(struct hid_device *hid); |
int hid_lgff_init(struct hid_device *hid); |
int hid_plff_init(struct hid_device *hid); |
int hid_tmff_init(struct hid_device *hid); |
int hid_zpff_init(struct hid_device *hid); |
#ifdef CONFIG_HID_PID |
int hid_pidff_init(struct hid_device *hid); |
#else |
static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; } |
#endif |
#else |
static inline int hid_ff_init(struct hid_device *hid) { return -1; } |
#endif |
#ifdef DEBUG |
#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \ |
__FILE__ , ## arg) |
#else |
#define dbg(format, arg...) do {} while (0) |
#endif |
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , \ |
__FILE__ , ## arg) |
#endif |
/drivers/usb/uhci/hid.inc |
---|
0,0 → 1,154 |
struct hid_class_descriptor { |
u8_t bDescriptorType; |
u16_t wDescriptorLength; |
} __attribute__ ((packed)); |
struct hid_descriptor { |
u8_t bLength; |
u8_t bDescriptorType; |
u16_t bcdHID; |
u8_t bCountryCode; |
u8_t bNumDescriptors; |
struct hid_class_descriptor desc[1]; |
} __attribute__ ((packed)); |
void create_hid_mouse(udev_t *dev, endpoint_descr_t *en_d); |
Bool init_hid(udev_t *dev) |
{ |
interface_descr_t *interface; |
struct hid_descriptor *hds; |
struct hid_class_descriptor *hidclass; |
u8_t *dptr = (u8_t*)dev->conf; |
int i=0, j=0; |
dbgprintf( "init hid device\n"); |
dptr+= dev->conf->bLength; |
// for(i = 0; i < dev->conf->bNumInterfaces; i++) |
// { |
interface = (interface_descr_t*)dptr; |
dptr+= interface->bLength; |
dbgprintf("interface %d\n\n" |
"bLength %d\n" |
"bDescriptorType %d\n" |
"bInterfaceNumber %d\n" |
"bAlternateSetting %d\n" |
"bNumEndpoints %d\n" |
"bInterfaceClass %d\n" |
"bInterfaceSubClass %d\n" |
"bInterfaceProtocol %d\n" |
"iInterface %d\n\n", |
i+1, |
interface->bLength, |
interface->bDescriptorType, |
interface->bInterfaceNumber, |
interface->bAlternateSetting, |
interface->bNumEndpoints, |
interface->bInterfaceClass, |
interface->bInterfaceSubClass, |
interface->bInterfaceProtocol, |
interface->iInterface); |
hds = (struct hid_descriptor*) dptr; |
dbgprintf("hid descriptor\n\n" |
"bLength %d\n" |
"bDescriptorType %d\n" |
"bcdHID %x\n" |
"bCountryCode %d\n" |
"bNumDescriptors %d\n", |
hds->bLength, |
hds->bDescriptorType, |
hds->bcdHID, |
hds->bCountryCode, |
hds->bNumDescriptors); |
for(j=0; j < hds->bNumDescriptors; j++) |
{ |
dbgprintf("bDescriptorType %d\n" |
"wDescriptorLength %d\n", |
hds->desc[j].bDescriptorType, |
hds->desc[j].wDescriptorLength); |
}; |
dptr+= hds->bLength; |
endpoint_descr_t *ep; |
ep = (endpoint_descr_t*)dptr; |
dbgprintf("\nendpoint\n\n" |
"bLength %d\n" |
"bDescriptorType %d\n" |
"bEndpointAddress %d\n" |
"bmAttributes %d\n" |
"wMaxPacketSize %d\n" |
"bInterval %d\n", |
ep->bLength, ep->bDescriptorType, |
ep->bEndpointAddress, ep->bmAttributes, |
ep->wMaxPacketSize, ep->bInterval); |
dptr+= ep->bLength; |
if( interface->bInterfaceProtocol == 2) |
create_hid_mouse(dev, ep); |
// } |
return TRUE; |
}; |
Bool mouse_handler(udev_t *dev, struct tag_request *rq) |
{ |
td_t *td; |
td = rq->td_head; |
if( (td->status &0x7FF)==rq->size-1) |
{ |
struct boot_packet *pkt; |
pkt = (struct boot_packet *)rq->data; |
SetMouseData(pkt->buttons, pkt->x, -pkt->y, -pkt->z, 0); |
}; |
td->status = 0x00800000 | dev->speed; |
td->token ^= DATA1; |
return TRUE; |
}; |
void create_hid_mouse(udev_t *dev, endpoint_descr_t *en_d) |
{ |
request_t *rq; |
endp_t enp; |
addr_t address; |
addr_t size; |
u32_t toggle; |
void *packet; |
td_t *td; |
qh_t *qh; |
static u16_t __attribute__((aligned(16))) |
req_set_conf[4] = {0x0900,0x0001,0x0000,0x0000}; |
if( !ctrl_request(dev, req_set_conf, DOUT, 0, 0)) |
return; |
enp.address = en_d->bEndpointAddress; |
enp.size = en_d->wMaxPacketSize; |
enp.toggle = DATA0; |
packet = malloc(enp.size); |
memset(packet, 0, enp.size); |
rq = create_request(dev, &enp, DIN, packet, enp.size); |
rq->handler = &mouse_handler; |
list_prepend(&rq->link, &rq_list); |
dbgprintf("create_hid_mouse\n"); |
} |
/drivers/usb/uhci/makefile |
---|
0,0 → 1,42 |
CC = gcc |
FASM = e:/fasm/fasm.exe |
CFLAGS = -c -O2 -fomit-frame-pointer -fno-builtin-printf |
LDRHD = -shared -T ld.x -s --file-alignment 32 |
INCLUDES = -I ../../include |
HFILES:= ../../include/types.h \ |
../../include/syscall.h \ |
../../include/link.h \ |
../../include/pci.h \ |
usb.h |
SRC_DEP:= pci.inc \ |
detect.inc \ |
hcd.inc \ |
hid.inc |
USB_SRC:= usb.c |
USB_OBJ:= usb.obj |
USB = usb.dll |
all: $(USB) |
$(USB): $(USB_OBJ) $(SRC_DEP) $(HFILES) Makefile |
wlink name usb.dll SYS nt_dll lib libdrv op offset=0 op nod op maxe=25 op el op STUB=stub.exe op START=_drvEntry @usb.lk |
kpack.exe usb.dll usb.drv |
usb.obj : usb.c $(SRC_DEP) $(HFILES) Makefile |
$(CC) $(INCLUDES) $(CFLAGS) -o usb.obj usb.c |
%.obj : %.c $(HFILES) |
$(CC) $(CFLAGS) -o $@ $< |
%.obj: %.asm |
as -o $@ $< |
/drivers/usb/uhci/pci.inc |
---|
0,0 → 1,98 |
u32_t pciGetBaseSize(int bus, int devfn, int index, |
Bool destructive, Bool *min) |
{ |
int offset; |
u32_t addr1; |
u32_t addr2; |
u32_t mask1; |
u32_t mask2; |
int bits = 0; |
/* |
* silently ignore bogus index values. Valid values are 0-6. 0-5 are |
* the 6 base address registers, and 6 is the ROM base address register. |
*/ |
if (index < 0 || index > 6) |
return 0; |
if (min) |
*min = destructive; |
/* Get the PCI offset */ |
if (index == 6) |
offset = PCI_MAP_ROM_REG; |
else |
offset = PCI_MAP_REG_START + (index << 2); |
addr1 = PciRead32(bus, devfn, offset); |
/* |
* Check if this is the second part of a 64 bit address. |
* XXX need to check how endianness affects 64 bit addresses. |
*/ |
if (index > 0 && index < 6) { |
addr2 = PciRead32(bus, devfn, offset - 4); |
if (PCI_MAP_IS_MEM(addr2) && PCI_MAP_IS64BITMEM(addr2)) |
return 0; |
} |
if (destructive) { |
PciWrite32(bus, devfn, offset, 0xffffffff); |
mask1 = PciRead32(bus, devfn, offset); |
PciWrite32(bus, devfn, offset, addr1); |
} else { |
mask1 = addr1; |
} |
/* Check if this is the first part of a 64 bit address. */ |
if (index < 5 && PCI_MAP_IS_MEM(mask1) && PCI_MAP_IS64BITMEM(mask1)) |
{ |
if (PCIGETMEMORY(mask1) == 0) |
{ |
addr2 = PciRead32(bus, devfn, offset + 4); |
if (destructive) |
{ |
PciWrite32(bus, devfn, offset + 4, 0xffffffff); |
mask2 = PciRead32(bus, devfn, offset + 4); |
PciWrite32(bus, devfn, offset + 4, addr2); |
} |
else |
{ |
mask2 = addr2; |
} |
if (mask2 == 0) |
return 0; |
bits = 32; |
while ((mask2 & 1) == 0) |
{ |
bits++; |
mask2 >>= 1; |
} |
if (bits > 32) |
return bits; |
} |
} |
if (index < 6) |
if (PCI_MAP_IS_MEM(mask1)) |
mask1 = PCIGETMEMORY(mask1); |
else |
mask1 = PCIGETIO(mask1); |
else |
mask1 = PCIGETROM(mask1); |
if (mask1 == 0) |
return 0; |
bits = 0; |
while ((mask1 & 1) == 0) { |
bits++; |
mask1 >>= 1; |
} |
/* I/O maps can be no larger than 8 bits */ |
if ((index < 6) && PCI_MAP_IS_IO(addr1) && bits > 8) |
bits = 8; |
/* ROM maps can be no larger than 24 bits */ |
if (index == 6 && bits > 24) |
bits = 24; |
return bits; |
} |
/drivers/usb/uhci/usb.asm |
---|
0,0 → 1,27 |
use32 |
db 'MENUET01' |
dd 1 |
dd start |
dd i_end |
dd mem |
dd mem |
dd 0 |
dd 0 |
start: |
mov eax, 68 |
mov ebx, 21 |
mov ecx, sz_usb |
int 0x40 |
mov eax, -1 |
int 0x40 |
sz_usb db '/rd/1/drivers/usb.drv',0 |
align 4 |
i_end: |
rb 128 |
mem: |
/drivers/usb/uhci/usb.c |
---|
0,0 → 1,232 |
#include "types.h" |
#include "link.h" |
#include <stdio.h> |
#include <malloc.h> |
#include <memory.h> |
#include "pci.h" |
#include "syscall.h" |
#include "usb.h" |
static Bool FindPciDevice(); |
int __stdcall srv_usb(ioctl_t *io); |
Bool init_hc(hc_t *hc); |
static slab_t qh_slab; |
static slab_t td_slab; |
static link_t hc_list; |
static link_t newdev_list; |
static link_t rq_list; |
u32_t __stdcall drvEntry(int action) |
{ |
u32_t retval; |
hc_t *hc; |
udev_t *dev; |
int i; |
if(action != 1) |
return 0; |
if(!dbg_open("/rd/1/drivers/usb.log")) |
{ |
printf("Can't open /rd/1/drivers/usb.log\nExit\n"); |
return 0; |
} |
list_initialize(&hc_list); |
list_initialize(&newdev_list); |
list_initialize(&rq_list); |
if( !FindPciDevice() ) { |
dbgprintf("no uhci devices found\n"); |
return 0; |
}; |
qh_slab.available = 256; |
qh_slab.start = KernelAlloc(4096); |
qh_slab.nextavail = (addr_t)qh_slab.start; |
qh_slab.dma = GetPgAddr(qh_slab.start); |
qh_t *p; |
addr_t dma; |
for (i = 0, p = (qh_t*)qh_slab.start, dma = qh_slab.dma; |
i < 256; i++, p++, dma+= sizeof(qh_t)) |
{ |
p->qlink = (addr_t)(p+1); |
p->qelem = 1; |
p->dma = dma; |
p->r1 = 0; |
}; |
td_slab.available = 128; |
td_slab.start = KernelAlloc(4096); |
td_slab.nextavail = (addr_t)td_slab.start; |
td_slab.dma = GetPgAddr(td_slab.start); |
td_t *td; |
for (i = 0, td = (td_t*)td_slab.start, dma = td_slab.dma; |
i < 128; i++, td++, dma+= sizeof(td_t)) |
{ |
td->link = (addr_t)(td+1); |
td->status = 0; |
td->token = 0; |
td->buffer = 0; |
td->dma = dma; |
}; |
hc = (hc_t*)hc_list.next; |
while( &hc->link != &hc_list) |
{ |
init_hc(hc); |
hc = (hc_t*)hc->link.next; |
} |
dbgprintf("\n"); |
dev = (udev_t*)newdev_list.next; |
while( &dev->link != &newdev_list) |
{ |
udev_t *tmp = dev; |
dev = (udev_t*)dev->link.next; |
if(tmp->id != 0) |
init_device(tmp); |
} |
while(1) |
{ |
udev_t *dev; |
request_t *rq; |
rq = (request_t*)rq_list.next; |
while( &rq->link != &rq_list) |
{ |
qh_t *qh; |
td_t *td; |
td = rq->td_head; |
dev = rq->dev; |
qh = dev->host->qh1; |
qh->qelem = td->dma; |
__asm__ __volatile__ ("":::"memory"); |
rq = (request_t*)rq->link.next; |
}; |
delay(10/10); |
rq = (request_t*)rq_list.next; |
while( &rq->link != &rq_list) |
{ |
request_t *tmp; |
td_t *td; |
tmp = rq; |
rq = (request_t*)rq->link.next; |
td = tmp->td_head; |
if( td->status & TD_CTRL_ACTIVE) |
continue; |
tmp->handler(tmp->dev, tmp); |
}; |
}; |
retval = RegService("USB", srv_usb); |
dbgprintf("reg service USB as: %x\n", retval); |
return retval; |
}; |
#define API_VERSION 0x01000100 |
#define SRV_GETVERSION 0 |
int __stdcall srv_usb(ioctl_t *io) |
{ |
u32_t *inp; |
u32_t *outp; |
inp = io->input; |
outp = io->output; |
switch(io->io_code) |
{ |
case SRV_GETVERSION: |
if(io->out_size==4) |
{ |
*outp = API_VERSION; |
return 0; |
} |
break; |
default: |
return ERR_PARAM; |
}; |
return ERR_PARAM; |
} |
static qh_t* alloc_qh() |
{ |
if( qh_slab.available ) |
{ |
qh_t *qh; |
qh_slab.available--; |
qh = (qh_t*)qh_slab.nextavail; |
qh_slab.nextavail = qh->qlink; |
return qh; |
} |
return NULL; |
}; |
static void free_qh(qh_t *qh) |
{ |
qh->qlink = qh_slab.nextavail; |
qh_slab.nextavail = (addr_t)qh; |
qh_slab.available++; |
}; |
static td_t* alloc_td() |
{ |
if( td_slab.available ) |
{ |
td_t *td; |
td_slab.available--; |
td = (td_t*)td_slab.nextavail; |
td_slab.nextavail = td->link; |
return td; |
} |
return NULL; |
}; |
static void free_td(td_t *td) |
{ |
td->link = td_slab.nextavail; |
td_slab.nextavail = (addr_t)td; |
td_slab.available++; |
}; |
#include "pci.inc" |
#include "detect.inc" |
#include "hcd.inc" |
#include "hid.inc" |
/drivers/usb/uhci/usb.h |
---|
0,0 → 1,247 |
typedef struct { |
int available; /**< Count of available items in this slab. */ |
void *start; /**< Start address of first item. */ |
addr_t nextavail; /**< The index of next available item. */ |
addr_t dma; |
} slab_t; |
#define USB_CLASS_AUDIO 1 |
#define USB_CLASS_COMM 2 |
#define USB_CLASS_HID 3 |
#define USB_CLASS_PHYSICAL 5 |
#define USB_CLASS_STILL_IMAGE 6 |
#define USB_CLASS_PRINTER 7 |
#define USB_CLASS_MASS_STORAGE 8 |
#define USB_CLASS_HUB 9 |
#define USB_CLASS_CDC_DATA 0x0a |
#define USB_CLASS_CSCID 0x0b /* chip+ smart card */ |
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */ |
#define USB_CLASS_VIDEO 0x0e |
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0 |
#define USB_CLASS_MISC 0xef |
#define USB_CLASS_APP_SPEC 0xfe |
#define USB_CLASS_VENDOR_SPEC 0xff |
typedef struct |
{ |
addr_t qlink; |
addr_t qelem; |
addr_t dma; |
u32_t r1; |
}qh_t __attribute__((aligned(16))); |
typedef struct |
{ |
link_t link; |
addr_t iobase; |
u32_t *frame_base; |
count_t frame_number; |
addr_t frame_dma; |
qh_t *qh1; |
u32_t *data; |
addr_t data_dma; |
u32_t port_map; |
int numports; |
u32_t pciId; |
PCITAG PciTag; |
addr_t ioBase[6]; |
addr_t memBase[6]; |
size_t memSize[6]; |
u32_t memType[6]; |
}hc_t; |
typedef struct tag_td |
{ |
/* Hardware fields */ |
addr_t link; |
u32_t status; |
u32_t token; |
addr_t buffer; |
/* Software fields */ |
addr_t dma; |
struct tag_td *bk; |
// struct list_head list; |
// int frame; /* for iso: what frame? */ |
// struct list_head fl_list; |
u32_t reserved[2]; |
} td_t __attribute__((aligned(16))); |
#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */ |
#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */ |
#define TD_CTRL_C_ERR_SHIFT 27 |
#define TD_CTRL_LS (1 << 26) /* Low Speed Device */ |
#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */ |
#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */ |
#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */ |
#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */ |
#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */ |
#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */ |
#define TD_CTRL_NAK (1 << 19) /* NAK Received */ |
#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */ |
#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */ |
#define TD_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \ |
TD_CTRL_BABBLE | TD_CTRL_CRCTIMEO | \ |
TD_CTRL_BITSTUFF) |
typedef struct __attribute__ ((packed)) |
{ |
u8_t bLength; |
u8_t bDescriptorType; |
u16_t bcdUSB; |
u8_t bDeviceClass; |
u8_t bDeviceSubClass; |
u8_t bDeviceProtocol; |
u8_t bMaxPacketSize0; |
u16_t idVendor; |
u16_t idProduct; |
u16_t bcdDevice; |
u8_t iManufacturer; |
u8_t iProduct; |
u8_t iSerialNumber; |
u8_t bNumConfigurations; |
}dev_descr_t; |
typedef struct __attribute__ ((packed)) |
{ |
u8_t bLength; |
u8_t bDescriptorType; |
u16_t wTotalLength; |
u8_t bNumInterfaces; |
u8_t bConfigurationValue; |
u8_t iConfiguration; |
u8_t bmAttributes; |
u8_t bMaxPower; |
}conf_descr_t; |
typedef struct __attribute__ ((packed)) |
{ |
u8_t bLength; |
u8_t bDescriptorType; |
u8_t bInterfaceNumber; |
u8_t bAlternateSetting; |
u8_t bNumEndpoints; |
u8_t bInterfaceClass; |
u8_t bInterfaceSubClass; |
u8_t bInterfaceProtocol; |
u8_t iInterface; |
}interface_descr_t ; |
typedef struct __attribute__ ((packed)) |
{ |
u8_t bLength; |
u8_t bDescriptorType; |
u8_t bEndpointAddress; |
u8_t bmAttributes; |
u16_t wMaxPacketSize; |
u8_t bInterval; |
/* NOTE: these two are _only_ in audio endpoints. */ |
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ |
u8_t bRefresh; |
u8_t bSynchAddress; |
}endpoint_descr_t; |
typedef struct |
{ |
addr_t address; |
addr_t size; |
u32_t toggle; |
}endp_t; |
typedef struct __attribute__ ((packed)) |
{ |
u8_t bRequestType; |
u8_t bRequest; |
u16_t wValue; |
u16_t wIndex; |
u16_t wLength; |
}ctrl_request_t; |
typedef struct |
{ |
link_t link; |
u32_t id; |
hc_t *host; |
u32_t speed; |
addr_t addr; |
addr_t ep0_size; |
endp_t enp; |
u32_t status; |
int port; |
dev_descr_t dev_descr; |
conf_descr_t *conf; |
}udev_t; |
typedef struct tag_request |
{ |
link_t link; |
td_t *td_head; |
td_t *td_tail; |
addr_t data; |
size_t size; |
udev_t *dev; |
u32_t type; |
Bool (*handler)(udev_t *dev, struct tag_request *rq); |
}request_t; |
#define DMA(val) GetPgAddr(val)|(((addr_t)(val))&0xFFF) |
#define TOKEN( size, toggle, ep, addr, pid) \ |
( (((size)-1)<<21)|(toggle)|(((ep)&0xF)<<15)|((addr)<<8)|(pid)) |
Bool ctrl_request(udev_t *dev, void *req, u32_t dir, |
void *data, size_t req_size); |
Bool set_address(udev_t *dev); |
Bool init_device(udev_t *dev); |
Bool init_hid(udev_t *dev); |
struct boot_packet |
{ |
u8_t buttons; |
i8_t x; |
i8_t y; |
i8_t z; |
}__attribute__ ((packed)); |
#define DOUT 0xE1 |
#define DIN 0x69 |
#define DATA0 (0<<19) |
#define DATA1 (1<<19) |
/drivers/usb/uhci/usb.lk |
---|
0,0 → 1,22 |
IMP |
_KernelAlloc core.KernelAlloc, |
_KernelFree core.KernelFree, |
_UserAlloc core.UserAlloc, |
_UserFree core.UserFree, |
_MapIoMem core.MapIoMem, |
_GetPgAddr core.GetPgAddr, |
_PciApi core.PciApi, |
_PciRead8 core.PciRead8, |
_PciRead16 core.PciRead16, |
_PciRead32 core.PciRead32, |
_PciWrite16 core.PciWrite16, |
_PciWrite32 core.PciWrite32, |
_RegService core.RegService, |
_SysMsgBoardStr core.SysMsgBoardStr, |
_Delay core.Delay, |
_SetMouseData core.SetMouseData |
FIL usb.obj, |
vsprintf.obj, |
icompute.obj |