The Pedigree Project 0.1
UsbHumanInterfaceDevice.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "UsbHumanInterfaceDevice.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/panic.h"
23#include "pedigree/kernel/processor/types.h"
24#include "pedigree/kernel/utilities/PointerGuard.h"
25#include "pedigree/kernel/utilities/Vector.h"
26#include "pedigree/kernel/utilities/utility.h"
27
28#include "modules/drivers/common/hid/HidReport.h"
29#include "modules/system/usb/UsbConstants.h"
30#include "modules/system/usb/UsbDevice.h"
31
32UsbHumanInterfaceDevice::UsbHumanInterfaceDevice(UsbDevice* pDev)
33 : UsbDevice(pDev),
34 m_pInEndpoint(nullptr),
35 m_pReport(nullptr),
36 m_InterruptIn(),
37 m_pInReportBuffer(nullptr),
38 m_pOldInReportBuffer(nullptr),
39 m_ReceivedInput(false) {}
40
41UsbHumanInterfaceDevice::~UsbHumanInterfaceDevice() {
42 if (!m_InterruptIn.reset()) {
43 panic("USB HID destroyed from its running interrupt callback");
44 }
45 // Release held input only after the controller has drained report callbacks.
46 delete m_pReport;
47 delete[] m_pInReportBuffer;
48 delete[] m_pOldInReportBuffer;
49}
50
52 // Get the HID descriptor
53 HidDescriptor* pHidDescriptor = 0;
54 for (size_t i = 0; i < m_pInterface->otherDescriptorList.count(); i++) {
55 UnknownDescriptor* pDescriptor = m_pInterface->otherDescriptorList[i];
56 if (pDescriptor->nType == 0x21 && pDescriptor->nLength >= sizeof(HidDescriptor::Descriptor)) {
57 pHidDescriptor = new HidDescriptor(pDescriptor);
58 break;
59 }
60 }
61 if (!pHidDescriptor) {
62 ERROR("USB: HID: No HID descriptor");
63 return;
64 }
65 PointerGuard<HidDescriptor> guard(pHidDescriptor);
66
67 // Set Idle Rate to 0
68 controlRequest(static_cast<uint8_t>(static_cast<uint8_t>(UsbRequestType::Class) |
69 static_cast<uint8_t>(UsbRequestRecipient::Interface)),
70 0x0a, 0, m_pInterface->nInterface);
71
72 // Get the report descriptor
73 uint16_t nReportDescriptorSize = pHidDescriptor->nDescriptorLength;
74 uint8_t* pReportDescriptor = static_cast<uint8_t*>(
75 getDescriptor(0x22, 0, nReportDescriptorSize, UsbRequestRecipient::Interface));
76 PointerGuard<uint8_t> guard2(pReportDescriptor, true);
77 if (!pReportDescriptor) {
78 ERROR("USB: HID: Could not read report descriptor");
79 return;
80 }
81
82 // Create a new report instance and use it to parse the report descriptor
83 m_pReport = new HidReport();
84 m_pReport->parseDescriptor(pReportDescriptor, nReportDescriptorSize);
85 if (!m_pReport->valid()) {
86 WARNING("USB: HID: invalid or unsupported report descriptor");
87 return;
88 }
89
90 // Search for an interrupt IN endpoint
91 for (size_t i = 0; i < m_pInterface->endpointList.count(); i++) {
92 Endpoint* pEndpoint = m_pInterface->endpointList[i];
93 if (pEndpoint->nTransferType == Endpoint::Interrupt && pEndpoint->bIn) {
94 m_pInEndpoint = pEndpoint;
95 break;
96 }
97 }
98
99 // Did we end up with no interrupt IN endpoint?
100 if (!m_pInEndpoint) {
101 ERROR("USB: HID: No Interrupt IN endpoint");
102 return;
103 }
104
105 // Allocate the input report buffers and zero them
106 m_pInReportBuffer = new uint8_t[m_pInEndpoint->nMaxPacketSize];
107 m_pOldInReportBuffer = new uint8_t[m_pInEndpoint->nMaxPacketSize];
108 ByteSet(m_pInReportBuffer, 0, m_pInEndpoint->nMaxPacketSize);
109 ByteSet(m_pOldInReportBuffer, 0, m_pInEndpoint->nMaxPacketSize);
110
111 // Add the input handler
112 if (!addInterruptInHandler(m_pInEndpoint, reinterpret_cast<uintptr_t>(m_pInReportBuffer),
113 m_pInEndpoint->nMaxPacketSize, callback, m_InterruptIn,
114 reinterpret_cast<uintptr_t>(this))) {
115 ERROR("USB: HID: recurring interrupt-IN submission failed");
116 return;
117 }
118
119 m_UsbState = HasDriver;
120 NOTICE("USB: HID: ready, device " << m_pDescriptor->nVendorId << ":" << m_pDescriptor->nProductId
121 << ", address " << Dec << m_nAddress << ", interface "
122 << m_pInterface->nInterface << ", protocol "
123 << m_pInterface->nProtocol << Hex);
124}
125
126void UsbHumanInterfaceDevice::callback(uintptr_t pParam, ssize_t ret) {
127 UsbHumanInterfaceDevice* pHid = reinterpret_cast<UsbHumanInterfaceDevice*>(pParam);
128 if (ret > 0 && static_cast<size_t>(ret) <= pHid->m_pInEndpoint->nMaxPacketSize)
129 pHid->inputHandler(ret);
130}
131
132void UsbHumanInterfaceDevice::inputHandler(size_t bytes) {
133 // Do we have a report instance?
134 if (!m_pReport)
135 return;
136
137 if (!m_ReceivedInput) {
138 m_ReceivedInput = true;
139 NOTICE("USB: HID: first input report, device "
140 << m_pDescriptor->nVendorId << ":" << m_pDescriptor->nProductId << ", address " << Dec
141 << m_nAddress << ", interface " << m_pInterface->nInterface << ", bytes " << bytes
142 << Hex);
143 }
144
145 // Feed the report instance with the input we just got
147}
void parseDescriptor(uint8_t *pDescriptor, size_t nDescriptorLength)
Parses a HID report descriptor and stores the resulted data.
Definition HidReport.cc:69
void feedInput(uint8_t *pBuffer, uint8_t *pOldBuffer, size_t nBufferSize)
Feeds the input interpreter with a new input buffer.
Definition HidReport.cc:309
uint8_t m_nAddress
The current address of the device.
Definition UsbDevice.h:297
Interface * m_pInterface
Interface in use.
Definition UsbDevice.h:320
bool controlRequest(uint8_t nRequestType, uint8_t nRequest, uint16_t nValue, uint16_t nIndex, uint16_t nLength=0, uintptr_t pBuffer=0, uint32_t timeout=5000)
Performs an USB control request.
Definition UsbDevice.cc:558
UsbState m_UsbState
The current state of the device.
Definition UsbDevice.h:311
DeviceDescriptor * m_pDescriptor
Device descriptor for this device.
Definition UsbDevice.h:314
DeviceDescriptor * getDescriptor()
Returns the device descriptor of the device.
Definition UsbDevice.h:216
virtual void initialiseDriver()
Implemented by the driver class, initialises driver-specific stuff.
uint8_t * m_pInReportBuffer
Input report buffer.
HidReport * m_pReport
The report instance used for input parsing.
uint8_t * m_pOldInReportBuffer
Old input report buffer.
Endpoint * m_pInEndpoint
The endpoint used to receive input reports from the device.
UsbInterruptInHandle m_InterruptIn
Owns and synchronously cancels the recurring controller callback.
MUST_USE_RESULT bool reset()
Definition UsbHub.cc:99
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:118
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124