forked from KolibriOS/kolibrios
remove old attempts to write something USB-related, they are not actual anymore
git-svn-id: svn://kolibrios.org@3568 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
c4636d1b86
commit
3fc8b505e2
@ -1,577 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
@ -1,229 +0,0 @@
|
||||
|
||||
|
||||
bool FindUSBControllers()
|
||||
{
|
||||
bool retval = false;
|
||||
u32_t bus, last_bus;
|
||||
PCITAG tag;
|
||||
|
||||
if( (last_bus = PciApi(1))==-1)
|
||||
return retval;
|
||||
|
||||
dbgprintf("last bus %x\n", last_bus);
|
||||
|
||||
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;
|
||||
u8_t interface;
|
||||
int i;
|
||||
|
||||
interface = PciRead8(bus,devfn, 0x09);
|
||||
devclass = PciRead16(bus,devfn, 0x0A);
|
||||
if( devclass != 0x0C03)
|
||||
continue;
|
||||
|
||||
if( interface != 0)
|
||||
continue;
|
||||
|
||||
pcicmd = PciRead16(bus,devfn, PCI_COMMAND);
|
||||
if (! pcicmd & PCI_COMMAND_IO)
|
||||
continue;
|
||||
|
||||
hc = (hc_t*)kmalloc(sizeof(hc_t), 0);
|
||||
INIT_LIST_HEAD(&hc->list);
|
||||
INIT_LIST_HEAD(&hc->rq_list);
|
||||
|
||||
hc->pciId = PciRead32(bus,devfn, 0);
|
||||
hc->PciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7);
|
||||
|
||||
hc->irq_line = PciRead32(bus,devfn, 0x3C) & 0xFF;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
dbgprintf("host controller %x bus %x devfn %x, IRQ %d\n",
|
||||
hc->pciId, bus, devfn, hc->irq_line);
|
||||
|
||||
list_add_tail(&hc->list, &hc_list);
|
||||
retval = true;
|
||||
};
|
||||
};
|
||||
return retval;
|
||||
};
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
/* these helpers provide future and backwards compatibility
|
||||
* for accessing popular PCI BAR info */
|
||||
#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
|
||||
#define pci_resource_end(dev, bar) ((dev)->resource[(bar)].end)
|
||||
#define pci_resource_flags(dev, bar) ((dev)->resource[(bar)].flags)
|
||||
#define pci_resource_len(dev,bar) \
|
||||
((pci_resource_start((dev), (bar)) == 0 && \
|
||||
pci_resource_end((dev), (bar)) == \
|
||||
pci_resource_start((dev), (bar))) ? 0 : \
|
||||
\
|
||||
(pci_resource_end((dev), (bar)) - \
|
||||
pci_resource_start((dev), (bar)) + 1))
|
||||
|
||||
static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx)
|
||||
{
|
||||
return pci_resource_start(pdev, idx) && mmio_enabled(pdev);
|
||||
}
|
||||
|
||||
static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
|
||||
{
|
||||
int wait_time, delta;
|
||||
void __iomem *base, *op_reg_base;
|
||||
u32 hcc_params, val;
|
||||
u8 offset, cap_length;
|
||||
int count = 256/4;
|
||||
int tried_handoff = 0;
|
||||
|
||||
if (!mmio_resource_enabled(pdev, 0))
|
||||
return;
|
||||
|
||||
base = pci_ioremap_bar(pdev, 0);
|
||||
if (base == NULL)
|
||||
return;
|
||||
|
||||
cap_length = readb(base);
|
||||
op_reg_base = base + cap_length;
|
||||
|
||||
/* EHCI 0.96 and later may have "extended capabilities"
|
||||
* spec section 5.1 explains the bios handoff, e.g. for
|
||||
* booting from USB disk or using a usb keyboard
|
||||
*/
|
||||
hcc_params = readl(base + EHCI_HCC_PARAMS);
|
||||
offset = (hcc_params >> 8) & 0xff;
|
||||
while (offset && --count) {
|
||||
u32 cap;
|
||||
int msec;
|
||||
|
||||
pci_read_config_dword(pdev, offset, &cap);
|
||||
switch (cap & 0xff) {
|
||||
case 1: /* BIOS/SMM/... handoff support */
|
||||
if ((cap & EHCI_USBLEGSUP_BIOS)) {
|
||||
dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n");
|
||||
|
||||
#if 0
|
||||
/* aleksey_gorelov@phoenix.com reports that some systems need SMI forced on,
|
||||
* but that seems dubious in general (the BIOS left it off intentionally)
|
||||
* and is known to prevent some systems from booting. so we won't do this
|
||||
* unless maybe we can determine when we're on a system that needs SMI forced.
|
||||
*/
|
||||
/* BIOS workaround (?): be sure the
|
||||
* pre-Linux code receives the SMI
|
||||
*/
|
||||
pci_read_config_dword(pdev,
|
||||
offset + EHCI_USBLEGCTLSTS,
|
||||
&val);
|
||||
pci_write_config_dword(pdev,
|
||||
offset + EHCI_USBLEGCTLSTS,
|
||||
val | EHCI_USBLEGCTLSTS_SOOE);
|
||||
#endif
|
||||
|
||||
/* some systems get upset if this semaphore is
|
||||
* set for any other reason than forcing a BIOS
|
||||
* handoff..
|
||||
*/
|
||||
pci_write_config_byte(pdev, offset + 3, 1);
|
||||
}
|
||||
|
||||
/* if boot firmware now owns EHCI, spin till
|
||||
* it hands it over.
|
||||
*/
|
||||
msec = 1000;
|
||||
while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
|
||||
tried_handoff = 1;
|
||||
msleep(10);
|
||||
msec -= 10;
|
||||
pci_read_config_dword(pdev, offset, &cap);
|
||||
}
|
||||
|
||||
if (cap & EHCI_USBLEGSUP_BIOS) {
|
||||
/* well, possibly buggy BIOS... try to shut
|
||||
* it down, and hope nothing goes too wrong
|
||||
*/
|
||||
dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
|
||||
" (BIOS bug?) %08x\n", cap);
|
||||
pci_write_config_byte(pdev, offset + 2, 0);
|
||||
}
|
||||
|
||||
/* just in case, always disable EHCI SMIs */
|
||||
pci_write_config_dword(pdev,
|
||||
offset + EHCI_USBLEGCTLSTS,
|
||||
0);
|
||||
|
||||
/* If the BIOS ever owned the controller then we
|
||||
* can't expect any power sessions to remain intact.
|
||||
*/
|
||||
if (tried_handoff)
|
||||
writel(0, op_reg_base + EHCI_CONFIGFLAG);
|
||||
break;
|
||||
case 0: /* illegal reserved capability */
|
||||
cap = 0;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
dev_warn(&pdev->dev, "EHCI: unrecognized capability "
|
||||
"%02x\n", cap & 0xff);
|
||||
break;
|
||||
}
|
||||
offset = (cap >> 8) & 0xff;
|
||||
}
|
||||
if (!count)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "EHCI: capability loop?\n");
|
||||
|
||||
/*
|
||||
* halt EHCI & disable its interrupts in any case
|
||||
*/
|
||||
val = readl(op_reg_base + EHCI_USBSTS);
|
||||
if ((val & EHCI_USBSTS_HALTED) == 0) {
|
||||
val = readl(op_reg_base + EHCI_USBCMD);
|
||||
val &= ~EHCI_USBCMD_RUN;
|
||||
writel(val, op_reg_base + EHCI_USBCMD);
|
||||
|
||||
wait_time = 2000;
|
||||
delta = 100;
|
||||
do {
|
||||
writel(0x3f, op_reg_base + EHCI_USBSTS);
|
||||
udelay(delta);
|
||||
wait_time -= delta;
|
||||
val = readl(op_reg_base + EHCI_USBSTS);
|
||||
if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
|
||||
break;
|
||||
}
|
||||
} while (wait_time > 0);
|
||||
}
|
||||
writel(0, op_reg_base + EHCI_USBINTR);
|
||||
writel(0x3f, op_reg_base + EHCI_USBSTS);
|
||||
|
||||
iounmap(base);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,747 +0,0 @@
|
||||
|
||||
#define UHCI_USBLEGSUP 0x00c0 /* legacy support */
|
||||
#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
|
||||
#define UHCI_USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
|
||||
#define UHCI_USBLEGSUP_RO 0x5040 /* R/O and reserved bits */
|
||||
|
||||
|
||||
#define UHCI_USBCMD 0 /* command register */
|
||||
#define UHCI_USBINTR 4 /* interrupt register */
|
||||
#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.
|
||||
*/
|
||||
|
||||
out16(hc->iobase + UHCI_USBCMD, 0);
|
||||
out16(hc->iobase + UHCI_USBINTR, 0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int hc_interrupt(void *data)
|
||||
{
|
||||
hc_t *hc = (hc_t*)data;
|
||||
|
||||
// printf("USB interrupt\n");
|
||||
|
||||
request_t *rq;
|
||||
u16_t status;
|
||||
|
||||
status = in16(hc->iobase + USBSTS);
|
||||
if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */
|
||||
return 0;
|
||||
|
||||
out16(hc->iobase + USBSTS, status); /* Clear it */
|
||||
|
||||
rq = (request_t*)hc->rq_list.next;
|
||||
|
||||
while( &rq->list != &hc->rq_list)
|
||||
{
|
||||
request_t *rtmp;
|
||||
td_t *td;
|
||||
|
||||
rtmp = rq;
|
||||
rq = (request_t*)rq->list.next;
|
||||
|
||||
td = rtmp->td_tail;
|
||||
|
||||
if( td->status & TD_CTRL_ACTIVE)
|
||||
continue;
|
||||
|
||||
list_del(&rtmp->list);
|
||||
|
||||
RaiseEvent(rtmp->evh, 0, &rtmp->event);
|
||||
};
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
bool init_hc(hc_t *hc)
|
||||
{
|
||||
int port;
|
||||
u32_t ifl;
|
||||
u16_t dev_status;
|
||||
td_t *td;
|
||||
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;
|
||||
|
||||
hc->td_pool = dma_pool_create("uhci_td", NULL,
|
||||
sizeof(td_t), 16, 0);
|
||||
if (!hc->td_pool)
|
||||
{
|
||||
dbgprintf("unable to create td dma_pool\n");
|
||||
goto err_create_td_pool;
|
||||
}
|
||||
|
||||
for (i = 0; i < UHCI_NUM_SKELQH; i++)
|
||||
{
|
||||
qh_t *qh = alloc_qh();
|
||||
|
||||
qh->qlink = 1;
|
||||
qh->qelem = 1;
|
||||
|
||||
hc->qh[i] = qh;
|
||||
}
|
||||
for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
|
||||
hc->qh[i]->qlink = hc->qh[SKEL_ASYNC]->dma | 2;
|
||||
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
int qnum;
|
||||
|
||||
qnum = 8 - (int) __bsf( i | 1024);
|
||||
|
||||
if (qnum <= 1)
|
||||
qnum = 9;
|
||||
|
||||
hc->frame_base[i] = hc->qh[qnum]->dma | 2;
|
||||
}
|
||||
|
||||
mb();
|
||||
|
||||
/* 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 + UHCI_USBINTR, 4);
|
||||
|
||||
printf("set handler %d ", hc->irq_line);
|
||||
delay(100/10);
|
||||
AttachIntHandler(hc->irq_line, hc_interrupt, hc);
|
||||
printf("done\n");
|
||||
|
||||
delay(100/10);
|
||||
|
||||
|
||||
pciWriteWord(hc->PciTag, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
|
||||
|
||||
out16(hc->iobase + USBCMD, USBCMD_RS | USBCMD_CF |
|
||||
USBCMD_MAXP);
|
||||
|
||||
for (port = 0; port < hc->numports; ++port)
|
||||
out16(hc->iobase + USBPORTSC1 + (port * 2), 0x200);
|
||||
|
||||
for (port = 0; port < 2; ++port)
|
||||
{
|
||||
time_t timeout;
|
||||
|
||||
delay(100/10);
|
||||
|
||||
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 = kmalloc(sizeof(udev_t),0);
|
||||
|
||||
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);
|
||||
|
||||
INIT_LIST_HEAD(&dev->list);
|
||||
|
||||
dev->host = hc;
|
||||
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_add_tail(&dev->list, &newdev_list);
|
||||
hc->port_map |= 1<<port;
|
||||
}
|
||||
else {
|
||||
free(dev);
|
||||
out16(hc->iobase + USBPORTSC1 + (port * 2), 0);
|
||||
}
|
||||
break;
|
||||
};
|
||||
};
|
||||
};
|
||||
return true;
|
||||
|
||||
err_create_td_pool:
|
||||
|
||||
KernelFree(hc->frame_base);
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#define ALIGN16(x) (((x)+15)&~15)
|
||||
|
||||
#define MakePtr( cast, ptr, addValue ) (cast)((addr_t)(ptr)+(addr_t)(addValue))
|
||||
|
||||
request_t *alloc_rq_buffer(udev_t *dev, endp_t *enp, u32_t dir,
|
||||
size_t data_size)
|
||||
{
|
||||
size_t packet_size = dev->ep0_size;
|
||||
int dsize = data_size;
|
||||
size_t buf_size;
|
||||
|
||||
addr_t buf_dma;
|
||||
addr_t td_dma;
|
||||
addr_t data_dma;
|
||||
|
||||
request_t *rq;
|
||||
|
||||
td_t *td, *td_prev;
|
||||
int td_count = 0;
|
||||
|
||||
while(dsize > 0)
|
||||
{
|
||||
td_count++;
|
||||
dsize-= packet_size;
|
||||
};
|
||||
|
||||
buf_size = ALIGN16(sizeof(request_t)) + ALIGN16(data_size) +
|
||||
td_count*sizeof(td_t);
|
||||
|
||||
rq = (request_t*)hcd_buffer_alloc(buf_size, &buf_dma);
|
||||
memset(rq, 0, buf_size);
|
||||
|
||||
data_dma = buf_dma + ALIGN16(sizeof(request_t));
|
||||
td_dma = data_dma + ALIGN16(data_size);
|
||||
|
||||
INIT_LIST_HEAD(&rq->list);
|
||||
|
||||
rq->data = MakePtr(addr_t, rq, ALIGN16(sizeof(request_t)));
|
||||
td = MakePtr(td_t*, rq->data, ALIGN16(data_size));
|
||||
rq->td_head = td;
|
||||
rq->size = data_size;
|
||||
rq->dev = dev;
|
||||
|
||||
td_prev = NULL;
|
||||
|
||||
dsize = data_size;
|
||||
|
||||
while(dsize != 0)
|
||||
{
|
||||
if ( dsize < packet_size)
|
||||
{
|
||||
packet_size = dsize;
|
||||
};
|
||||
|
||||
td->dma = td_dma;
|
||||
|
||||
td->link = 1;
|
||||
|
||||
if( td_prev )
|
||||
td_prev->link = td->dma | 4;
|
||||
td->status = TD_CTRL_ACTIVE | dev->speed;
|
||||
td->token = TOKEN(packet_size,enp->toggle,enp->address,
|
||||
dev->addr,dir);
|
||||
td->buffer = data_dma;
|
||||
td->bk = td_prev;
|
||||
|
||||
td_prev = td;
|
||||
|
||||
td++;
|
||||
td_dma+= sizeof(td_t);
|
||||
data_dma+= packet_size;
|
||||
|
||||
dsize-= packet_size;
|
||||
enp->toggle ^= DATA1;
|
||||
};
|
||||
|
||||
td_prev->status |= TD_CTRL_IOC;
|
||||
rq->td_tail = td_prev;
|
||||
|
||||
rq->evh = CreateEvent(NULL, MANUAL_DESTROY);
|
||||
|
||||
if(rq->evh.handle == 0)
|
||||
printf("%s: epic fail\n", __FUNCTION__);
|
||||
|
||||
rq->event.code = 0xFF000001;
|
||||
rq->event.data[0] = (addr_t)rq;
|
||||
|
||||
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;
|
||||
hc_t *hc = dev->host;
|
||||
|
||||
addr_t td_dma = 0;
|
||||
|
||||
bool retval;
|
||||
|
||||
|
||||
request_t *rq = (request_t*)kmalloc(sizeof(request_t),0);
|
||||
|
||||
INIT_LIST_HEAD(&rq->list);
|
||||
|
||||
rq->data = (addr_t)data;
|
||||
rq->size = req_size;
|
||||
rq->dev = dev;
|
||||
|
||||
td0 = dma_pool_alloc(hc->td_pool, 0, &td_dma);
|
||||
td0->dma = td_dma;
|
||||
|
||||
// dbgprintf("alloc td0 %x dma %x\n", td0, td_dma);
|
||||
|
||||
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 > 0)
|
||||
{
|
||||
if ( size < packet_size)
|
||||
{
|
||||
packet_size = size;
|
||||
};
|
||||
|
||||
td = dma_pool_alloc(hc->td_pool, 0, &td_dma);
|
||||
td->dma = td_dma;
|
||||
|
||||
// dbgprintf("alloc td %x dma %x\n", td, td->dma);
|
||||
|
||||
td_prev->link = td->dma | 4;
|
||||
td->status = TD_CTRL_ACTIVE | 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;
|
||||
}
|
||||
|
||||
td = dma_pool_alloc(hc->td_pool, 0, &td_dma);
|
||||
td->dma = td_dma;
|
||||
|
||||
// dbgprintf("alloc td %x dma %x\n", td, td->dma);
|
||||
|
||||
td_prev->link = td->dma | 4;
|
||||
|
||||
pid = (pid == DIN) ? DOUT : DIN;
|
||||
|
||||
td->link = 1;
|
||||
td->status = TD_CTRL_ACTIVE | TD_CTRL_IOC | dev->speed ;
|
||||
td->token = (0x7FF<<21)|DATA1|(dev->addr<<8)|pid;
|
||||
td->buffer = 0;
|
||||
td->bk = td_prev;
|
||||
|
||||
rq->td_head = td0;
|
||||
rq->td_tail = td;
|
||||
|
||||
rq->evh = CreateEvent(NULL, MANUAL_DESTROY);
|
||||
|
||||
if(rq->evh.handle == 0)
|
||||
printf("%s: epic fail\n", __FUNCTION__);
|
||||
|
||||
rq->event.code = 0xFF000001;
|
||||
rq->event.data[0] = (addr_t)rq;
|
||||
|
||||
u32_t efl = safe_cli();
|
||||
|
||||
list_add_tail(&rq->list, &dev->host->rq_list);
|
||||
|
||||
qh = dev->host->qh[SKEL_ASYNC];
|
||||
|
||||
qh->qelem = td0->dma;
|
||||
|
||||
mb();
|
||||
|
||||
safe_sti(efl);
|
||||
|
||||
WaitEvent(rq->evh);
|
||||
|
||||
dbgprintf("td0 status 0x%0x\n", td0->status);
|
||||
dbgprintf("td status 0x%0x\n", td->status);
|
||||
|
||||
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;
|
||||
|
||||
qh->qelem = 1;
|
||||
|
||||
mb();
|
||||
|
||||
do
|
||||
{
|
||||
td_prev = td->bk;
|
||||
dma_pool_free(hc->td_pool, td, td->dma);
|
||||
td = td_prev;
|
||||
}while( td != NULL);
|
||||
|
||||
/*
|
||||
delete event;
|
||||
*/
|
||||
kfree(rq);
|
||||
|
||||
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))
|
||||
{
|
||||
dbgprintf("%s epic fail\n",__FUNCTION__);
|
||||
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_del(&dev->list);
|
||||
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");
|
||||
};
|
||||
};
|
@ -1,523 +0,0 @@
|
||||
#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
|
||||
|
@ -1,382 +0,0 @@
|
||||
|
||||
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);
|
||||
void create_hid_keyboard(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;
|
||||
|
||||
switch(interface->bInterfaceProtocol)
|
||||
{
|
||||
case 1:
|
||||
create_hid_keyboard(dev, ep);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
create_hid_mouse(dev, ep);
|
||||
break;
|
||||
}
|
||||
// }
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
bool mouse_handler(udev_t *dev, struct tag_request *rq)
|
||||
{
|
||||
td_t *td;
|
||||
qh_t *qh;
|
||||
|
||||
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);
|
||||
memset(pkt,0, sizeof(*pkt));
|
||||
};
|
||||
td->status = TD_CTRL_ACTIVE | TD_CTRL_IOC | dev->speed;
|
||||
td->token ^= DATA1;
|
||||
|
||||
u32_t efl = safe_cli();
|
||||
list_add_tail(&rq->list, &dev->host->rq_list);
|
||||
qh = dev->host->qh[rq->qnum];
|
||||
qh->qelem = rq->td_head->dma;
|
||||
mb();
|
||||
safe_sti(efl);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint16_t value;
|
||||
struct
|
||||
{
|
||||
uint8_t code;
|
||||
uint8_t ecode;
|
||||
};
|
||||
}scancode_t;
|
||||
|
||||
static const uint16_t usb_keycode[256] =
|
||||
{
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
/* 8 9 A B C D E F */
|
||||
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x001E, 0x0030, 0x002E, 0x0020, /* 0x00 */
|
||||
0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
|
||||
|
||||
0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001F, 0x0014, /* 0x10 */
|
||||
0x0016, 0x002F, 0x0011, 0x002D, 0x0015, 0x002C, 0x0002, 0x0003,
|
||||
|
||||
0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, /* 0x20 */
|
||||
0x001C, 0x0001, 0x000E, 0x000F, 0x0039, 0x000C, 0x000D, 0x001A,
|
||||
|
||||
0x001B, 0x002B, 0x002B, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034, /* 0x30 */
|
||||
0x0035, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040,
|
||||
|
||||
0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xE037, 0x0046, /* 0x40 */
|
||||
0x0000, 0xE052, 0xE047, 0xE049, 0xE053, 0xE04F, 0xE051, 0xE04D,
|
||||
|
||||
0xE04B, 0xE050, 0xE048, 0x0045, 0xE035, 0x0037, 0x004A, 0x004E, /* 0x50 */
|
||||
0xE01C, 0x004F, 0x0050, 0x0051, 0x004B, 0x004C, 0x004D, 0x0047,
|
||||
|
||||
0x0048, 0x0049, 0x0052, 0x0053, 0x0056, 0xE05D, 0xE05E, 0x0059, /* 0x60 */
|
||||
0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B,
|
||||
|
||||
0x006C, 0x006D, 0x006E, 0x0076, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x70 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x007E, 0x0000, 0x0073, /* 0x80 */
|
||||
0x0070, 0x007D, 0x0079, 0x007B, 0x005C, 0x0000, 0x0000, 0x0000,
|
||||
|
||||
0x00F2, 0x00F1, 0x0078, 0x0077, 0x0076, 0x0000, 0x0000, 0x0000, /* 0x90 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xA0 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xB0 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xC0 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xD0 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
|
||||
0x001D, 0x002A, 0x0038, 0xE05B, 0xE01D, 0x0036, 0xE038, 0xE05C, /* 0xE0 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xFE0 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
|
||||
};
|
||||
|
||||
static uint8_t kbd_old[8];
|
||||
|
||||
bool keyboard_handler(udev_t *dev, struct tag_request *rq)
|
||||
{
|
||||
td_t *td;
|
||||
qh_t *qh;
|
||||
|
||||
uint8_t *data;
|
||||
int i;
|
||||
|
||||
td = rq->td_head;
|
||||
|
||||
if( (td->status &0x7FF)==rq->size-1)
|
||||
{
|
||||
uint8_t action;
|
||||
scancode_t scan;
|
||||
|
||||
data = (uint8_t*)rq->data;
|
||||
|
||||
action = data[0] ^ kbd_old[0];
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if(action & 1)
|
||||
{
|
||||
scan.value = usb_keycode[i+224];
|
||||
|
||||
if(data[0]>>i & 1)
|
||||
{
|
||||
if(scan.ecode)
|
||||
SetKeyboardData(scan.ecode);
|
||||
SetKeyboardData(scan.code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(scan.ecode)
|
||||
SetKeyboardData(scan.ecode);
|
||||
SetKeyboardData(scan.code|0x80);
|
||||
};
|
||||
}
|
||||
action >>= 1;
|
||||
}
|
||||
|
||||
|
||||
for (i = 2; i < 8; i++)
|
||||
{
|
||||
if ((kbd_old[i] > 3) && (memscan(data+2, kbd_old[i], 6) == data+8))
|
||||
{
|
||||
scan.value = usb_keycode[kbd_old[i]];
|
||||
|
||||
if (scan.value)
|
||||
{
|
||||
if(scan.ecode)
|
||||
SetKeyboardData(scan.ecode);
|
||||
SetKeyboardData(scan.code|0x80);
|
||||
// input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
|
||||
}
|
||||
else
|
||||
dbgprintf("Unknown key (scancode %#x) released.\n", kbd_old[i]);
|
||||
}
|
||||
|
||||
if ((data[i] > 3) && (memscan(kbd_old+2, data[i], 6) == kbd_old+8))
|
||||
{
|
||||
scan.value = usb_keycode[data[i]];
|
||||
|
||||
if (scan.value)
|
||||
{
|
||||
if(scan.ecode)
|
||||
SetKeyboardData(scan.ecode);
|
||||
SetKeyboardData(scan.code);
|
||||
//input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
|
||||
}
|
||||
else
|
||||
dbgprintf("Unknown key (scancode %#x) released.\n", data[i]);
|
||||
}
|
||||
}
|
||||
memcpy(kbd_old, data, 8);
|
||||
};
|
||||
|
||||
td->status = TD_CTRL_ACTIVE | TD_CTRL_IOC | dev->speed;
|
||||
td->token ^= DATA1;
|
||||
|
||||
u32_t efl = safe_cli();
|
||||
list_add_tail(&rq->list, &dev->host->rq_list);
|
||||
qh = dev->host->qh[rq->qnum];
|
||||
qh->qelem = rq->td_head->dma;
|
||||
mb();
|
||||
safe_sti(efl);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
rq = alloc_rq_buffer(dev, &enp, DIN, enp.size);
|
||||
|
||||
rq->qnum = 6;
|
||||
rq->handler = &mouse_handler;
|
||||
|
||||
u32_t efl = safe_cli();
|
||||
list_add_tail(&rq->list, &dev->host->rq_list);
|
||||
qh = dev->host->qh[rq->qnum];
|
||||
qh->qelem = rq->td_head->dma;
|
||||
mb();
|
||||
safe_sti(efl);
|
||||
|
||||
dbgprintf("%s\n",__FUNCTION__);
|
||||
}
|
||||
|
||||
void create_hid_keyboard(udev_t *dev, endpoint_descr_t *en_d)
|
||||
{
|
||||
request_t *rq;
|
||||
endp_t enp;
|
||||
|
||||
addr_t address;
|
||||
addr_t size;
|
||||
u32_t toggle;
|
||||
|
||||
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;
|
||||
|
||||
rq = alloc_rq_buffer(dev, &enp, DIN, enp.size);
|
||||
|
||||
rq->qnum = 4;
|
||||
rq->handler = &keyboard_handler;
|
||||
|
||||
u32_t efl = safe_cli();
|
||||
list_add_tail(&rq->list, &dev->host->rq_list);
|
||||
qh = dev->host->qh[rq->qnum];
|
||||
qh->qelem = rq->td_head->dma;
|
||||
mb();
|
||||
safe_sti(efl);
|
||||
|
||||
dbgprintf("%s\n",__FUNCTION__);
|
||||
}
|
||||
|
||||
void *memscan(void *addr, int c, size_t size)
|
||||
{
|
||||
if (!size)
|
||||
return addr;
|
||||
__asm__ __volatile__(
|
||||
"repnz; scasb \n\t"
|
||||
"jnz 1f \n\t"
|
||||
"dec %%edi \n\t"
|
||||
"1:"
|
||||
: "=D" (addr), "=c" (size)
|
||||
: "D" (addr), "1" (size), "a" (c)
|
||||
: "memory");
|
||||
return addr;
|
||||
}
|
||||
|
@ -1,50 +0,0 @@
|
||||
|
||||
CC = gcc
|
||||
|
||||
DRV_DIR = $(CURDIR)/../..
|
||||
|
||||
DRV_INCLUDES = $(DRV_DIR)/include
|
||||
|
||||
INCLUDES = -I$(DRV_INCLUDES) -I$(DRV_INCLUDES)/linux
|
||||
|
||||
DEFINES = -D__KERNEL__ -DCONFIG_X86_32
|
||||
|
||||
CFLAGS = -c -O2 -fomit-frame-pointer -fno-builtin-printf
|
||||
|
||||
LDFLAGS = -nostdlib -shared -s -Map acpi.map --image-base 0\
|
||||
--file-alignment 512 --section-alignment 4096
|
||||
|
||||
LIBPATH:= -L$(DRV_DIR)/ddk
|
||||
|
||||
LIBS:= -lgcc -lddk -lcore
|
||||
|
||||
|
||||
NAME= usb
|
||||
|
||||
NAME_SRCS= usb.c \
|
||||
buffer.c
|
||||
|
||||
SRC_DEP = hcd.inc \
|
||||
detect.inc \
|
||||
hid.inc \
|
||||
pci.inc \
|
||||
|
||||
|
||||
all: $(NAME).dll
|
||||
|
||||
NAME_OBJS = $(patsubst %.S, %.o, $(patsubst %.asm, %.o,\
|
||||
$(patsubst %.c, %.o, $(NAME_SRCS))))
|
||||
|
||||
|
||||
$(NAME).dll: $(NAME_OBJS) usb.lds Makefile
|
||||
ld $(LIBPATH) $(LDFLAGS) -T usb.lds -o $@ $(NAME_OBJS) $(LIBS)
|
||||
kpack $(NAME).dll $(NAME).drv
|
||||
|
||||
%.o: %.c $(HFILES) $(SRC_DEP) Makefile
|
||||
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $<
|
||||
|
||||
%.o: %.S $(HFILES) Makefile
|
||||
as -o $@ $<
|
||||
|
||||
|
||||
|
@ -1,116 +0,0 @@
|
||||
|
||||
#define PCI_MAP_REG_START 0x10
|
||||
#define PCI_MAP_ROM_REG 0x30
|
||||
|
||||
#define PCI_MAP_MEMORY 0x00000000
|
||||
#define PCI_MAP_IO 0x00000001
|
||||
|
||||
#define PCI_MAP_MEMORY_TYPE 0x00000007
|
||||
#define PCI_MAP_IO_TYPE 0x00000003
|
||||
|
||||
#define PCI_MAP_MEMORY_TYPE_32BIT 0x00000000
|
||||
#define PCI_MAP_MEMORY_TYPE_32BIT_1M 0x00000002
|
||||
#define PCI_MAP_MEMORY_TYPE_64BIT 0x00000004
|
||||
#define PCI_MAP_MEMORY_TYPE_MASK 0x00000006
|
||||
#define PCI_MAP_MEMORY_CACHABLE 0x00000008
|
||||
#define PCI_MAP_MEMORY_ATTR_MASK 0x0000000e
|
||||
#define PCI_MAP_MEMORY_ADDRESS_MASK 0xfffffff0
|
||||
|
||||
#define PCI_MAP_IO_ATTR_MASK 0x00000003
|
||||
|
||||
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;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
|
||||
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:
|
@ -1,174 +0,0 @@
|
||||
|
||||
|
||||
#include <ddk.h>
|
||||
#include <mutex.h>
|
||||
#include <linux/errno.h>
|
||||
#include <pci.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/string.h>
|
||||
#include <syscall.h>
|
||||
#include "usb.h"
|
||||
|
||||
int __stdcall srv_usb(ioctl_t *io);
|
||||
|
||||
bool init_hc(hc_t *hc);
|
||||
|
||||
static slab_t qh_slab;
|
||||
|
||||
LIST_HEAD( hc_list );
|
||||
LIST_HEAD( newdev_list );
|
||||
LIST_HEAD( rq_list );
|
||||
|
||||
u32_t drvEntry(int action, char *cmdline)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if( !FindUSBControllers() ) {
|
||||
dbgprintf("no uhci devices found\n");
|
||||
return 0;
|
||||
};
|
||||
|
||||
hcd_buffer_create();
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
hc = (hc_t*)hc_list.next;
|
||||
|
||||
while( &hc->list != &hc_list)
|
||||
{
|
||||
hc_t *tmp = hc;
|
||||
hc = (hc_t*)hc->list.next;
|
||||
|
||||
if( !init_hc(tmp))
|
||||
list_del(&tmp->list);
|
||||
};
|
||||
|
||||
dbgprintf("\n");
|
||||
|
||||
dev = (udev_t*)newdev_list.next;
|
||||
while( &dev->list != &newdev_list)
|
||||
{
|
||||
udev_t *tmp = dev;
|
||||
dev = (udev_t*)dev->list.next;
|
||||
|
||||
if(tmp->id != 0)
|
||||
init_device(tmp);
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
udev_t *dev;
|
||||
request_t *rq;
|
||||
kevent_t event;
|
||||
u32_t handle;
|
||||
|
||||
event.code = 0;
|
||||
event.data[0] = 0;
|
||||
|
||||
handle = GetEvent(&event);
|
||||
|
||||
// dbgprintf("event handle 0x%0x code 0x%0x\n",
|
||||
// handle, event.code);
|
||||
|
||||
if(event.code != 0xFF000001)
|
||||
continue;
|
||||
|
||||
rq = (request_t*)event.data[0];
|
||||
|
||||
// dbgprintf("rq = 0x%0x\n", rq);
|
||||
|
||||
rq->handler(rq->dev, rq);
|
||||
};
|
||||
|
||||
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++;
|
||||
};
|
||||
|
||||
|
||||
#include "pci.inc"
|
||||
#include "detect.inc"
|
||||
#include "hcd.inc"
|
||||
#include "hid.inc"
|
@ -1,275 +0,0 @@
|
||||
|
||||
typedef struct list_head list_t;
|
||||
|
||||
|
||||
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)));
|
||||
|
||||
|
||||
#define UHCI_NUM_SKELQH 11
|
||||
|
||||
#define SKEL_ISO 1
|
||||
#define SKEL_ASYNC 9
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
list_t list;
|
||||
|
||||
addr_t iobase;
|
||||
|
||||
struct dma_pool *td_pool;
|
||||
|
||||
u32_t *frame_base;
|
||||
count_t frame_number;
|
||||
addr_t frame_dma;
|
||||
|
||||
qh_t *qh[UHCI_NUM_SKELQH];
|
||||
|
||||
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];
|
||||
u32_t irq_line;
|
||||
|
||||
list_t rq_list;
|
||||
}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
|
||||
{
|
||||
list_t list;
|
||||
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
|
||||
{
|
||||
list_t list;
|
||||
td_t *td_head;
|
||||
td_t *td_tail;
|
||||
addr_t data;
|
||||
size_t size;
|
||||
udev_t *dev;
|
||||
u32_t type;
|
||||
int qnum;
|
||||
evhandle_t evh;
|
||||
kevent_t event;
|
||||
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 FindUSBControllers();
|
||||
|
||||
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;
|
||||
char x;
|
||||
char y;
|
||||
char z;
|
||||
}__attribute__ ((packed));
|
||||
|
||||
#define DOUT 0xE1
|
||||
#define DIN 0x69
|
||||
|
||||
#define DATA0 (0<<19)
|
||||
#define DATA1 (1<<19)
|
||||
|
||||
|
||||
|
||||
static inline u32_t __bsf(u32_t val)
|
||||
{
|
||||
asm("bsf %1,%0"
|
||||
:"=r" (val)
|
||||
:"rm" (val));
|
||||
return val;
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
|
||||
|
||||
OUTPUT_FORMAT(pei-i386)
|
||||
|
||||
ENTRY("_drvEntry")
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = SIZEOF_HEADERS;
|
||||
. = ALIGN(__section_alignment__);
|
||||
|
||||
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :
|
||||
|
||||
{
|
||||
*(.text) *(.rdata)
|
||||
}
|
||||
|
||||
.data ALIGN(__section_alignment__) :
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss ALIGN(__section_alignment__):
|
||||
{
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.debug$S)
|
||||
*(.debug$T)
|
||||
*(.debug$F)
|
||||
*(.drectve)
|
||||
*(.edata)
|
||||
}
|
||||
|
||||
.idata ALIGN(__section_alignment__):
|
||||
{
|
||||
SORT(*)(.idata$2)
|
||||
SORT(*)(.idata$3)
|
||||
/* These zeroes mark the end of the import list. */
|
||||
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
|
||||
SORT(*)(.idata$4)
|
||||
SORT(*)(.idata$5)
|
||||
SORT(*)(.idata$6)
|
||||
SORT(*)(.idata$7)
|
||||
}
|
||||
|
||||
.reloc ALIGN(__section_alignment__) :
|
||||
{
|
||||
*(.reloc)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,121 +0,0 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2007-2011. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
struc URB
|
||||
{
|
||||
.fd dd ?
|
||||
.bk dd ?
|
||||
.dev dd ? ; pointer to associated device
|
||||
.pipe dd ? ; pipe information
|
||||
.status dd ? ; non-ISO status
|
||||
.transfer_flags dd ? ; URB_SHORT_NOT_OK | ...
|
||||
.transfer_buffer dd ? ; associated data buffer
|
||||
.transfer_dma dd ? ; dma addr for transfer_buffer
|
||||
.transfer_buffer_length dd ? ; data buffer length
|
||||
.actual_length dd ? ; actual transfer length
|
||||
.setup_packet dd ? ; setup packet (control only)
|
||||
.setup_dma dd ? ; dma addr for setup_packet
|
||||
.start_frame dd ? ; start frame (ISO)
|
||||
.number_of_packets dd ? ; number of ISO packets
|
||||
.interval dd ? ; transfer interval
|
||||
|
||||
.error_count dd ? ; number of ISO errors
|
||||
.context dd ? ; context for completion
|
||||
.complete dd ? ; (in) completion routine
|
||||
.iso_frame_desc:
|
||||
}
|
||||
|
||||
virtual at 0
|
||||
URB URB
|
||||
end virtual
|
||||
|
||||
|
||||
struc REQ ;usb request
|
||||
{
|
||||
.request_type db ?
|
||||
.request db ?
|
||||
.value dw ?
|
||||
.index dw ?
|
||||
.length dw ?
|
||||
}
|
||||
|
||||
virtual at 0
|
||||
REQ REQ
|
||||
end virtual
|
||||
|
||||
align 4
|
||||
proc usb_control_msg stdcall, dev:dword, pipe:dword, request:dword,\
|
||||
requesttype:dword, value:dword, index:dword,\
|
||||
data:dword, size:dword, timeout:dword
|
||||
|
||||
locals
|
||||
req REQ
|
||||
endl
|
||||
|
||||
lea eax, [req]
|
||||
mov ecx, [request]
|
||||
mov ebx, [requesttupe]
|
||||
mov edx, [value]
|
||||
mov esi, [index]
|
||||
mov edi, [size]
|
||||
|
||||
mov [eax+REQ.request_type], bl
|
||||
mov [eax+REQ.request], cl
|
||||
mov [eax+REQ.value], dx
|
||||
mov [eax+REQ.index], si
|
||||
mov [eax+REQ.length], di
|
||||
|
||||
stdcall usb_internal_control_msg, [dev], [pipe], \
|
||||
eax, [data], [size], [timeout]
|
||||
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
; returns status (negative) or length (positive)
|
||||
static int usb_internal_control_msg(struct usb_device *usb_dev,
|
||||
unsigned int pipe,
|
||||
struct usb_ctrlrequest *cmd,
|
||||
void *data, int len, int timeout)
|
||||
{
|
||||
struct urb *urb;
|
||||
int retv;
|
||||
int length;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_NOIO);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
|
||||
len, usb_api_blocking_completion, NULL);
|
||||
|
||||
retv = usb_start_wait_urb(urb, timeout, &length);
|
||||
if (retv < 0)
|
||||
return retv;
|
||||
else
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
;void usb_fill_control_urb (struct urb *urb,
|
||||
; struct usb_device *dev,
|
||||
; unsigned int pipe,
|
||||
; unsigned char *setup_packet,
|
||||
; void *transfer_buffer,
|
||||
; int buffer_length,
|
||||
; usb_complete_t complete_fn,
|
||||
; void *context)
|
||||
;{
|
||||
;
|
||||
; urb->dev = dev;
|
||||
; urb->pipe = pipe;
|
||||
; urb->setup_packet = setup_packet;
|
||||
; urb->transfer_buffer = transfer_buffer;
|
||||
; urb->transfer_buffer_length = buffer_length;
|
||||
; urb->complete = complete_fn;
|
||||
; urb->context = context;
|
||||
;}
|
||||
;
|
@ -1,435 +0,0 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;driver sceletone
|
||||
|
||||
format MS COFF
|
||||
|
||||
API_VERSION equ 0 ;debug
|
||||
|
||||
include '../proc32.inc'
|
||||
include '../imports.inc'
|
||||
include 'urb.inc'
|
||||
|
||||
struc UHCI
|
||||
{
|
||||
.bus dd ?
|
||||
.devfn dd ?
|
||||
.io_base dd ?
|
||||
.mm_base dd ?
|
||||
.irq dd ?
|
||||
.flags dd ?
|
||||
.reset dd ?
|
||||
.start dd ?
|
||||
.stop dd ?
|
||||
|
||||
.port_c_suspend dd ?
|
||||
.resuming_ports dd ?
|
||||
.rh_state dd ?
|
||||
.rh_numports dd ?
|
||||
.is_stopped dd ?
|
||||
.dead dd ?
|
||||
|
||||
.sizeof:
|
||||
}
|
||||
|
||||
virtual at 0
|
||||
UHCI UHCI
|
||||
end virtual
|
||||
|
||||
struc IOCTL
|
||||
{ .handle dd ?
|
||||
.io_code dd ?
|
||||
.input dd ?
|
||||
.inp_size dd ?
|
||||
.output dd ?
|
||||
.out_size dd ?
|
||||
}
|
||||
|
||||
virtual at 0
|
||||
IOCTL IOCTL
|
||||
end virtual
|
||||
|
||||
struc TD ;transfer descriptor
|
||||
{
|
||||
.link dd ?
|
||||
.status dd ?
|
||||
.token dd ?
|
||||
.buffer dd ?
|
||||
|
||||
.addr dd ?
|
||||
.frame dd ?
|
||||
.fd dd ?
|
||||
.bk dd ?
|
||||
.sizeof:
|
||||
}
|
||||
|
||||
virtual at 0
|
||||
TD TD
|
||||
end virtual
|
||||
|
||||
public START
|
||||
public service_proc
|
||||
public version
|
||||
|
||||
DEBUG equ 1
|
||||
|
||||
DRV_ENTRY equ 1
|
||||
DRV_EXIT equ -1
|
||||
STRIDE equ 4 ;size of row in devices table
|
||||
|
||||
SRV_GETVERSION equ 0
|
||||
|
||||
section '.flat' code readable align 16
|
||||
|
||||
proc START stdcall, state:dword
|
||||
|
||||
cmp [state], 1
|
||||
jne .exit
|
||||
.entry:
|
||||
|
||||
if DEBUG
|
||||
mov esi, msgInit
|
||||
call SysMsgBoardStr
|
||||
end if
|
||||
|
||||
call init
|
||||
|
||||
stdcall RegService, my_service, service_proc
|
||||
ret
|
||||
.fail:
|
||||
.exit:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
handle equ IOCTL.handle
|
||||
io_code equ IOCTL.io_code
|
||||
input equ IOCTL.input
|
||||
inp_size equ IOCTL.inp_size
|
||||
output equ IOCTL.output
|
||||
out_size equ IOCTL.out_size
|
||||
|
||||
align 4
|
||||
proc service_proc stdcall, ioctl:dword
|
||||
|
||||
mov ebx, [ioctl]
|
||||
mov eax, [ebx+io_code]
|
||||
cmp eax, SRV_GETVERSION
|
||||
jne @F
|
||||
|
||||
mov eax, [ebx+output]
|
||||
cmp [ebx+out_size], 4
|
||||
jne .fail
|
||||
mov [eax], dword API_VERSION
|
||||
xor eax, eax
|
||||
ret
|
||||
@@:
|
||||
.fail:
|
||||
or eax, -1
|
||||
ret
|
||||
endp
|
||||
|
||||
restore handle
|
||||
restore io_code
|
||||
restore input
|
||||
restore inp_size
|
||||
restore output
|
||||
restore out_size
|
||||
|
||||
align 4
|
||||
proc detect
|
||||
locals
|
||||
last_bus dd ?
|
||||
bus dd ?
|
||||
devfn dd ?
|
||||
endl
|
||||
|
||||
xor eax, eax
|
||||
mov [bus], eax
|
||||
inc eax
|
||||
call PciApi
|
||||
cmp eax, -1
|
||||
je .err
|
||||
|
||||
mov [last_bus], eax
|
||||
|
||||
.next_bus:
|
||||
and [devfn], 0
|
||||
.next_dev:
|
||||
stdcall PciRead32, [bus], [devfn], dword 0
|
||||
test eax, eax
|
||||
jz .next
|
||||
cmp eax, -1
|
||||
je .next
|
||||
|
||||
mov edi, devices
|
||||
@@:
|
||||
mov ebx, [edi]
|
||||
test ebx, ebx
|
||||
jz .next
|
||||
|
||||
cmp eax, ebx
|
||||
je .found
|
||||
|
||||
add edi, STRIDE
|
||||
jmp @B
|
||||
.next:
|
||||
inc [devfn]
|
||||
cmp [devfn], 256
|
||||
jb .next_dev
|
||||
mov eax, [bus]
|
||||
inc eax
|
||||
mov [bus], eax
|
||||
cmp eax, [last_bus]
|
||||
jna .next_bus
|
||||
xor eax, eax
|
||||
ret
|
||||
.found:
|
||||
mov eax, UHCI.sizeof
|
||||
call Kmalloc
|
||||
test eax, eax
|
||||
jz .mem_fail
|
||||
|
||||
mov ebx, [bus]
|
||||
mov [eax+UHCI.bus], ebx
|
||||
|
||||
mov ecx, [devfn]
|
||||
mov [eax+UHCI.devfn], ecx
|
||||
ret
|
||||
.mem_fail:
|
||||
if DEBUG
|
||||
mov esi, msgMemFail
|
||||
call SysMsgBoardStr
|
||||
end if
|
||||
.err:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
PCI_BASE equ 0x20
|
||||
USB_LEGKEY equ 0xC0
|
||||
|
||||
align 4
|
||||
proc init
|
||||
locals
|
||||
uhci dd ?
|
||||
endl
|
||||
|
||||
call detect
|
||||
test eax, eax
|
||||
jz .fail
|
||||
|
||||
mov [uhci], eax
|
||||
|
||||
stdcall PciRead32, [eax+UHCI.bus], [eax+UHCI.devfn], PCI_BASE
|
||||
and eax, 0xFFC0
|
||||
mov esi, [uhci]
|
||||
mov [esi+UHCI.io_base], eax
|
||||
|
||||
stdcall uhci_reset, esi
|
||||
|
||||
stdcall finish_reset, [uhci]
|
||||
|
||||
.fail:
|
||||
if DEBUG
|
||||
mov esi, msgDevNotFound
|
||||
call SysMsgBoardStr
|
||||
end if
|
||||
ret
|
||||
endp
|
||||
|
||||
UHCI_USBINTR equ 4 ; interrupt register
|
||||
|
||||
UHCI_USBLEGSUP_RWC equ 0x8f00 ; the R/WC bits
|
||||
UHCI_USBLEGSUP_RO equ 0x5040 ; R/O and reserved bits
|
||||
|
||||
UHCI_USBCMD_RUN equ 0x0001 ; RUN/STOP bit
|
||||
UHCI_USBCMD_HCRESET equ 0x0002 ; Host Controller reset
|
||||
UHCI_USBCMD_EGSM equ 0x0008 ; Global Suspend Mode
|
||||
UHCI_USBCMD_CONFIGURE equ 0x0040 ; Config Flag
|
||||
UHCI_USBINTR_RESUME equ 0x0002 ; Resume interrupt enable
|
||||
|
||||
PORTSC0 equ 0x10
|
||||
PORTSC1 equ 0x12
|
||||
|
||||
|
||||
UHCI_RH_RESET equ 0
|
||||
UHCI_RH_SUSPENDED equ 1
|
||||
UHCI_RH_AUTO_STOPPED equ 2
|
||||
UHCI_RH_RESUMING equ 3
|
||||
|
||||
; In this state the HC changes from running to halted
|
||||
; so it can legally appear either way.
|
||||
UHCI_RH_SUSPENDING equ 4
|
||||
|
||||
; In the following states it's an error if the HC is halted.
|
||||
; These two must come last.
|
||||
UHCI_RH_RUNNING equ 5 ; The normal state
|
||||
UHCI_RH_RUNNING_NODEVS equ 6 ; Running with no devices
|
||||
|
||||
UHCI_IS_STOPPED equ 9999
|
||||
|
||||
align 4
|
||||
proc uhci_reset stdcall, uhci:dword
|
||||
mov esi, [uhci]
|
||||
stdcall PciRead16, [esi+UHCI.bus], [esi+UHCI.devfn], USB_LEGKEY
|
||||
test eax, not (UHCI_USBLEGSUP_RO or UHCI_USBLEGSUP_RWC)
|
||||
jnz .reset
|
||||
|
||||
mov edx, [esi+UHCI.io_base]
|
||||
in ax, dx
|
||||
test ax, UHCI_USBCMD_RUN
|
||||
jnz .reset
|
||||
|
||||
test ax, UHCI_USBCMD_CONFIGURE
|
||||
jz .reset
|
||||
|
||||
test ax, UHCI_USBCMD_EGSM
|
||||
jz .reset
|
||||
|
||||
add edx, UHCI_USBINTR
|
||||
in ax, dx
|
||||
test ax, not UHCI_USBINTR_RESUME
|
||||
jnz .reset
|
||||
ret
|
||||
.reset:
|
||||
stdcall PciWrite16, [esi+UHCI.bus], [esi+UHCI.devfn], USB_LEGKEY, UHCI_USBLEGSUP_RWC
|
||||
|
||||
mov edx, [esi+UHCI.io_base]
|
||||
mov ax, UHCI_USBCMD_HCRESET
|
||||
out dx, ax
|
||||
|
||||
xor eax, eax
|
||||
out dx, ax
|
||||
add edx, UHCI_USBINTR
|
||||
out dx, ax
|
||||
ret
|
||||
endp
|
||||
|
||||
proc finish_reset stdcall, uhci:dword
|
||||
|
||||
mov esi, [uhci]
|
||||
mov edx, [esi+UHCI.io_base]
|
||||
add edx, PORTSC0
|
||||
xor eax, eax
|
||||
out dx, ax
|
||||
add edx, (PORTSC1-PORTSC0)
|
||||
out dx, ax
|
||||
|
||||
mov [esi+UHCI.port_c_suspend], eax
|
||||
mov [esi+UHCI.resuming_ports], eax
|
||||
mov [esi+UHCI.rh_state], UHCI_RH_RESET
|
||||
mov [esi+UHCI.rh_numports], 2
|
||||
|
||||
mov [esi+UHCI.is_stopped], UHCI_IS_STOPPED
|
||||
; mov [ uhci_to_hcd(uhci)->state = HC_STATE_HALT;
|
||||
; uhci_to_hcd(uhci)->poll_rh = 0;
|
||||
|
||||
mov [esi+UHCI.dead], eax ; Full reset resurrects the controller
|
||||
|
||||
ret
|
||||
endp
|
||||
|
||||
proc insert_td stdcall, td:dword, frame:dword
|
||||
|
||||
mov edi, [td]
|
||||
mov eax, [frame]
|
||||
and eax, -1024
|
||||
mov [edi+TD.frame], eax
|
||||
|
||||
mov ebx, [framelist]
|
||||
mov edx, [dma_framelist]
|
||||
shl eax, 5
|
||||
|
||||
mov ecx, [eax+ebx]
|
||||
test ecx, ecx
|
||||
jz .empty
|
||||
|
||||
mov ecx, [ecx+TD.bk] ;last TD
|
||||
|
||||
mov edx, [ecx+TD.fd]
|
||||
mov [edi+TD.fd], edx
|
||||
mov [edi+TD.bk], ecx
|
||||
mov [ecx+TD.fd], edi
|
||||
mov [edx+TD.bk], edi
|
||||
|
||||
mov eax, [ecx+TD.link]
|
||||
mov [edi+TD.link], eax
|
||||
mov ebx, [edi+TD.addr]
|
||||
mov [ecx+TD.link], ebx
|
||||
ret
|
||||
.empty:
|
||||
mov ecx, [eax+edx]
|
||||
mov [edi+TD.link], ecx
|
||||
mov [ebx+eax], edi
|
||||
mov ecx, [edi+TD.addr]
|
||||
mov [eax+edx], ecx
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
align 4
|
||||
proc usb_get_descriptor stdcall, dev:dword, type:dword, index:dword,\
|
||||
buf:dword, size:dword
|
||||
|
||||
locals
|
||||
count dd ?
|
||||
endl
|
||||
|
||||
mov esi, [buf]
|
||||
mov ecx, [size]
|
||||
xor eax, eax
|
||||
cld
|
||||
rep stosb
|
||||
|
||||
mov [count], 3
|
||||
@@:
|
||||
mov eax, [type]
|
||||
shl eax, 8
|
||||
add eax, [index]
|
||||
stdcall usb_control_msg, [dev], pipe, USB_REQ_GET_DESCRIPTOR, \
|
||||
USB_DIR_IN, eax,0,[buf], [size],\
|
||||
USB_CTRL_GET_TIMEOUT
|
||||
test eax, eax
|
||||
jz .next
|
||||
cmp eax, -1
|
||||
je .next
|
||||
jmp. ok
|
||||
.next:
|
||||
dec [count]
|
||||
jnz @B
|
||||
mov eax, -1
|
||||
.ok:
|
||||
ret
|
||||
endp
|
||||
|
||||
DEVICE_ID equ 0x24D2 ; pci device id
|
||||
VENDOR_ID equ 0x8086 ; device vendor id
|
||||
QEMU_USB equ 0x7020
|
||||
|
||||
;all initialized data place here
|
||||
|
||||
align 4
|
||||
devices dd (DEVICE_ID shl 16)+VENDOR_ID
|
||||
dd (QEMU_USB shl 16)+VENDOR_ID
|
||||
dd 0 ;terminator
|
||||
|
||||
version dd (5 shl 16) or (API_VERSION and 0xFFFF)
|
||||
|
||||
my_service db 'UHCI',0 ;max 16 chars include zero
|
||||
|
||||
msgInit db 'detect hardware...',13,10,0
|
||||
msgPCI db 'PCI accsess not supported',13,10,0
|
||||
msgDevNotFound db 'device not found',13,10,0
|
||||
msgMemFail db 'Kmalloc failed', 10,10,0
|
||||
;msgFail db 'device not found',13,10,0
|
||||
|
||||
section '.data' data readable writable align 16
|
||||
|
||||
;all uninitialized data place here
|
||||
|
Loading…
Reference in New Issue
Block a user