/* * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. * Distributed under the terms of the MIT License. */ #include #include #include #include "Driver.h" #include "HIDCollection.h" #include "HIDDevice.h" #include "HIDReport.h" #include "ProtocolHandler.h" // includes for the different protocol handlers #include "JoystickProtocolHandler.h" #include "KeyboardProtocolHandler.h" #include "MouseProtocolHandler.h" #include "TabletProtocolHandler.h" ProtocolHandler::ProtocolHandler(HIDDevice *device, const char *basePath, size_t ringBufferSize) : fStatus(B_NO_INIT), fDevice(device), fBasePath(basePath), fPublishPath(NULL), fRingBuffer(NULL), fNextHandler(NULL) { if (ringBufferSize > 0) { fRingBuffer = create_ring_buffer(ringBufferSize); if (fRingBuffer == NULL) { TRACE_ALWAYS("failed to create requested ring buffer\n"); fStatus = B_NO_MEMORY; return; } } fStatus = B_OK; } ProtocolHandler::~ProtocolHandler() { if (fRingBuffer) { delete_ring_buffer(fRingBuffer); fRingBuffer = NULL; } free(fPublishPath); } void ProtocolHandler::SetPublishPath(char *publishPath) { free(fPublishPath); fPublishPath = publishPath; } void ProtocolHandler::AddHandlers(HIDDevice &device, ProtocolHandler *&handlerList, uint32 &handlerCount) { TRACE("adding protocol handlers\n"); HIDParser &parser = device.Parser(); HIDCollection *rootCollection = parser.RootCollection(); if (rootCollection == NULL) return; uint32 appCollectionCount = rootCollection->CountChildrenFlat( COLLECTION_APPLICATION); TRACE("root collection holds %" B_PRIu32 " application collection%s\n", appCollectionCount, appCollectionCount != 1 ? "s" : ""); for (uint32 i = 0; i < appCollectionCount; i++) { HIDCollection *collection = rootCollection->ChildAtFlat( COLLECTION_APPLICATION, i); if (collection == NULL) continue; TRACE("collection usage page %u usage id %u\n", collection->UsagePage(), collection->UsageID()); // NOTE: The driver publishes devices for all added handlers. // TODO: How does this work if a device is not a compound device // like a keyboard with built-in touchpad, but allows multiple // alternative configurations like a tablet that works as either // regular (relative) mouse, or (absolute) tablet? KeyboardProtocolHandler::AddHandlers(device, *collection, handlerList); JoystickProtocolHandler::AddHandlers(device, *collection, handlerList); MouseProtocolHandler::AddHandlers(device, *collection, handlerList); TabletProtocolHandler::AddHandlers(device, *collection, handlerList); } handlerCount = 0; ProtocolHandler *handler = handlerList; while (handler != NULL) { handler = handler->NextHandler(); handlerCount++; } if (handlerCount == 0) { TRACE_ALWAYS("no handlers for hid device\n"); return; } TRACE("added %" B_PRId32 " handlers for hid device\n", handlerCount); } status_t ProtocolHandler::Open(uint32 flags, uint32 *cookie) { return fDevice->Open(this, flags); } status_t ProtocolHandler::Close(uint32 *cookie) { *cookie |= PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED; // This lets the handlers know that this user is gone. return fDevice->Close(this); } status_t ProtocolHandler::Read(uint32 *cookie, off_t position, void *buffer, size_t *numBytes) { TRACE_ALWAYS("unhandled read on protocol handler\n"); *numBytes = 0; return B_ERROR; } status_t ProtocolHandler::Write(uint32 *cookie, off_t position, const void *buffer, size_t *numBytes) { TRACE_ALWAYS("unhandled write on protocol handler\n"); *numBytes = 0; return B_ERROR; } status_t ProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer, size_t length) { TRACE_ALWAYS("unhandled control on protocol handler\n"); return B_ERROR; } int32 ProtocolHandler::RingBufferReadable() { return ring_buffer_readable(fRingBuffer); } status_t ProtocolHandler::RingBufferRead(void *buffer, size_t length) { ring_buffer_user_read(fRingBuffer, (uint8 *)buffer, length); return B_OK; } status_t ProtocolHandler::RingBufferWrite(const void *buffer, size_t length) { ring_buffer_write(fRingBuffer, (const uint8 *)buffer, length); return B_OK; } void ProtocolHandler::SetNextHandler(ProtocolHandler *nextHandler) { fNextHandler = nextHandler; } status_t ProtocolHandler::IOGetDeviceName(const char *name, void *buffer, size_t length) { if (!IS_USER_ADDRESS(buffer)) return B_BAD_ADDRESS; if (user_strlcpy((char *)buffer, name, length) > 0) return B_OK; return B_ERROR; }