1/*
2 * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <stdlib.h>
8#include <ring_buffer.h>
9#include <kernel.h>
10
11#include "Driver.h"
12#include "HIDCollection.h"
13#include "HIDDevice.h"
14#include "HIDReport.h"
15#include "ProtocolHandler.h"
16
17// includes for the different protocol handlers
18#include "JoystickProtocolHandler.h"
19#include "KeyboardProtocolHandler.h"
20#include "MouseProtocolHandler.h"
21#include "TabletProtocolHandler.h"
22
23
24ProtocolHandler::ProtocolHandler(HIDDevice *device, const char *basePath,
25	size_t ringBufferSize)
26	:	fStatus(B_NO_INIT),
27		fDevice(device),
28		fBasePath(basePath),
29		fPublishPath(NULL),
30		fRingBuffer(NULL),
31		fNextHandler(NULL)
32{
33	if (ringBufferSize > 0) {
34		fRingBuffer = create_ring_buffer(ringBufferSize);
35		if (fRingBuffer == NULL) {
36			TRACE_ALWAYS("failed to create requested ring buffer\n");
37			fStatus = B_NO_MEMORY;
38			return;
39		}
40	}
41
42	fStatus = B_OK;
43}
44
45
46ProtocolHandler::~ProtocolHandler()
47{
48	if (fRingBuffer) {
49		delete_ring_buffer(fRingBuffer);
50		fRingBuffer = NULL;
51	}
52
53	free(fPublishPath);
54}
55
56
57void
58ProtocolHandler::SetPublishPath(char *publishPath)
59{
60	free(fPublishPath);
61	fPublishPath = publishPath;
62}
63
64
65void
66ProtocolHandler::AddHandlers(HIDDevice &device, ProtocolHandler *&handlerList,
67	uint32 &handlerCount)
68{
69	TRACE("adding protocol handlers\n");
70
71	HIDParser &parser = device.Parser();
72	HIDCollection *rootCollection = parser.RootCollection();
73	if (rootCollection == NULL)
74		return;
75
76	uint32 appCollectionCount = rootCollection->CountChildrenFlat(
77		COLLECTION_APPLICATION);
78	TRACE("root collection holds %" B_PRIu32 " application collection%s\n",
79		appCollectionCount, appCollectionCount != 1 ? "s" : "");
80
81	for (uint32  i = 0; i < appCollectionCount; i++) {
82		HIDCollection *collection = rootCollection->ChildAtFlat(
83			COLLECTION_APPLICATION, i);
84		if (collection == NULL)
85			continue;
86
87		TRACE("collection usage page %u usage id %u\n",
88			collection->UsagePage(), collection->UsageID());
89
90		// NOTE: The driver publishes devices for all added handlers.
91
92		// TODO: How does this work if a device is not a compound device
93		// like a keyboard with built-in touchpad, but allows multiple
94		// alternative configurations like a tablet that works as either
95		// regular (relative) mouse, or (absolute) tablet?
96		KeyboardProtocolHandler::AddHandlers(device, *collection, handlerList);
97		JoystickProtocolHandler::AddHandlers(device, *collection, handlerList);
98		MouseProtocolHandler::AddHandlers(device, *collection, handlerList);
99		TabletProtocolHandler::AddHandlers(device, *collection, handlerList);
100	}
101
102	handlerCount = 0;
103	ProtocolHandler *handler = handlerList;
104	while (handler != NULL) {
105		handler = handler->NextHandler();
106		handlerCount++;
107	}
108
109	if (handlerCount == 0) {
110		TRACE_ALWAYS("no handlers for hid device\n");
111		return;
112	}
113
114	TRACE("added %" B_PRId32 " handlers for hid device\n", handlerCount);
115}
116
117
118status_t
119ProtocolHandler::Open(uint32 flags, uint32 *cookie)
120{
121	return fDevice->Open(this, flags);
122}
123
124
125status_t
126ProtocolHandler::Close(uint32 *cookie)
127{
128	*cookie |= PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED;
129		// This lets the handlers know that this user is gone.
130
131	return fDevice->Close(this);
132}
133
134
135status_t
136ProtocolHandler::Read(uint32 *cookie, off_t position, void *buffer,
137	size_t *numBytes)
138{
139	TRACE_ALWAYS("unhandled read on protocol handler\n");
140	*numBytes = 0;
141	return B_ERROR;
142}
143
144
145status_t
146ProtocolHandler::Write(uint32 *cookie, off_t position, const void *buffer,
147	size_t *numBytes)
148{
149	TRACE_ALWAYS("unhandled write on protocol handler\n");
150	*numBytes = 0;
151	return B_ERROR;
152}
153
154
155status_t
156ProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer, size_t length)
157{
158	TRACE_ALWAYS("unhandled control on protocol handler\n");
159	return B_ERROR;
160}
161
162
163int32
164ProtocolHandler::RingBufferReadable()
165{
166	return ring_buffer_readable(fRingBuffer);
167}
168
169
170status_t
171ProtocolHandler::RingBufferRead(void *buffer, size_t length)
172{
173	ring_buffer_user_read(fRingBuffer, (uint8 *)buffer, length);
174	return B_OK;
175}
176
177
178status_t
179ProtocolHandler::RingBufferWrite(const void *buffer, size_t length)
180{
181	ring_buffer_write(fRingBuffer, (const uint8 *)buffer, length);
182	return B_OK;
183}
184
185
186void
187ProtocolHandler::SetNextHandler(ProtocolHandler *nextHandler)
188{
189	fNextHandler = nextHandler;
190}
191
192status_t
193ProtocolHandler::IOGetDeviceName(const char *name, void *buffer, size_t length)
194{
195
196	if (!IS_USER_ADDRESS(buffer))
197		return B_BAD_ADDRESS;
198
199	if (user_strlcpy((char *)buffer, name, length) > 0)
200		return B_OK;
201
202	return B_ERROR;
203}
204