16b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood/* 26b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * Copyright (C) 2012 The Android Open Source Project 36b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * 46b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 56b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * you may not use this file except in compliance with the License. 66b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * You may obtain a copy of the License at 76b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * 86b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 96b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * 106b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * Unless required by applicable law or agreed to in writing, software 116b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 126b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * See the License for the specific language governing permissions and 146b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * limitations under the License. 156b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood */ 166b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 176b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <unistd.h> 186b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <stdio.h> 196b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <string.h> 206b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <stdlib.h> 216b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 226b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <sys/types.h> 236b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <sys/stat.h> 246b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <sys/ioctl.h> 256b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <fcntl.h> 266b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <errno.h> 276b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <pthread.h> 286b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <time.h> 296b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 306b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <sys/inotify.h> 316b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <linux/hidraw.h> 326b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <usbhost/usbhost.h> 336b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 346b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include "f_accessory.h" 356b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include "accessory.h" 366b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 376b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 386b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 396b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic int next_id = 1; 406b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 416b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic void milli_sleep(int millis) { 426b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood struct timespec tm; 436b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 446b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood tm.tv_sec = 0; 456b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood tm.tv_nsec = millis * 1000000; 466b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood nanosleep(&tm, NULL); 476b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood} 486b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 496b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic void* hid_thread(void* arg) { 506b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int fd = (int)arg; 516b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood char buffer[4096]; 526b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int id, ret, offset; 536b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood struct usb_device *device; 546b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood struct usb_device_descriptor *device_desc; 556b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int max_packet; 566b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood struct hidraw_report_descriptor desc; 576b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int desc_length; 586b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 596b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "hid_thread start fd: %d\n", fd); 606b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 616b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if (ioctl(fd, HIDIOCGRDESCSIZE, &desc_length)) { 626b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "HIDIOCGRDESCSIZE failed\n"); 636b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood close(fd); 646b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood goto err; 656b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 666b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 676b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood desc.size = HID_MAX_DESCRIPTOR_SIZE - 1; 686b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if (ioctl(fd, HIDIOCGRDESC, &desc)) { 696b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "HIDIOCGRDESC failed\n"); 706b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood close(fd); 716b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood goto err; 726b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 736b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 746b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodwait_for_device: 756b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "waiting for device fd: %d\n", fd); 766b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood device = usb_wait_for_device(); 776b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood max_packet = usb_device_get_device_descriptor(device)->bMaxPacketSize0; 786b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood // FIXME 796b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood max_packet--; 806b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 816b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood // FIXME 826b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood milli_sleep(500); 836b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 846b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood pthread_mutex_lock(&mutex); 856b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood id = next_id++; 866b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 876b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 886b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood ACCESSORY_REGISTER_HID, id, desc_length, NULL, 0, 1000); 896b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "ACCESSORY_REGISTER_HID returned %d\n", ret); 906b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 916b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood // FIXME 926b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood milli_sleep(500); 936b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 946b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood for (offset = 0; offset < desc_length; ) { 956b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int count = desc_length - offset; 966b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if (count > max_packet) count = max_packet; 976b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 986b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "sending ACCESSORY_SET_HID_REPORT_DESC offset: %d count: %d desc_length: %d\n", 996b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood offset, count, desc_length); 1006b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 1016b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood ACCESSORY_SET_HID_REPORT_DESC, id, offset, &desc.value[offset], count, 1000); 1026b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "ACCESSORY_SET_HID_REPORT_DESC returned %d errno %d\n", ret, errno); 1036b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood offset += count; 1046b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 1056b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1066b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood pthread_mutex_unlock(&mutex); 1076b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1086b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood while (1) { 1096b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood ret = read(fd, buffer, sizeof(buffer)); 1106b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if (ret < 0) { 1116b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodfprintf(stderr, "read failed, errno: %d, fd: %d\n", errno, fd); 1126b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood break; 1136b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 1146b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1156b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 1166b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood ACCESSORY_SEND_HID_EVENT, id, 0, buffer, ret, 1000); 1176b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if (ret < 0 && errno != EPIPE) { 1186b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodfprintf(stderr, "ACCESSORY_SEND_HID_EVENT returned %d errno: %d\n", ret, errno); 1196b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood goto wait_for_device; 1206b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 1216b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 1226b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1236b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodfprintf(stderr, "ACCESSORY_UNREGISTER_HID\n"); 1246b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 1256b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood ACCESSORY_UNREGISTER_HID, id, 0, NULL, 0, 1000); 1266b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1276b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodfprintf(stderr, "hid thread exiting\n"); 1286b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwooderr: 1296b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood return NULL; 1306b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood} 1316b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1326b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic void open_hid(const char* name) 1336b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{ 1346b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood char path[100]; 1356b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1366b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood snprintf(path, sizeof(path), "/dev/%s", name); 1376b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int fd = open(path, O_RDWR); 1386b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if (fd < 0) return; 1396b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1406b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "opened /dev/%s\n", name); 1416b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood pthread_t th; 1426b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood pthread_create(&th, NULL, hid_thread, (void *)fd); 1436b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood} 1446b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1456b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic void* inotify_thread(void* arg) 1466b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{ 1476b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw0"); 1486b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw1"); 1496b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw2"); 1506b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw3"); 1516b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw4"); 1526b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw5"); 1536b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw6"); 1546b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw7"); 1556b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw8"); 1566b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid("hidraw9"); 1576b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1586b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int inotify_fd = inotify_init(); 1596b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood inotify_add_watch(inotify_fd, "/dev", IN_DELETE | IN_CREATE); 1606b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1616b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood while (1) { 1626b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood char event_buf[512]; 1636b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood struct inotify_event *event; 1646b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int event_pos = 0; 1656b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int event_size; 1666b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1676b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood int count = read(inotify_fd, event_buf, sizeof(event_buf)); 1686b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if (count < (int)sizeof(*event)) { 1696b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if(errno == EINTR) 1706b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood continue; 1716b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "could not get event, %s\n", strerror(errno)); 1726b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood break; 1736b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 1746b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood while (count >= (int)sizeof(*event)) { 1756b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood event = (struct inotify_event *)(event_buf + event_pos); 1766b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood //fprintf(stderr, "%d: %08x \"%s\"\n", event->wd, event->mask, 1776b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood // event->len ? event->name : ""); 1786b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if (event->len) { 1796b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood if(event->mask & IN_CREATE) { 1806b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "created %s\n", event->name); 1816b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood // FIXME 1826b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood milli_sleep(50); 1836b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood open_hid(event->name); 1846b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } else { 1856b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood fprintf(stderr, "lost %s\n", event->name); 1866b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 1876b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 1886b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood event_size = sizeof(*event) + event->len; 1896b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood count -= event_size; 1906b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood event_pos += event_size; 1916b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 1926b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood } 1936b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1946b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood close(inotify_fd); 1956b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood return NULL; 1966b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood} 1976b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood 1986b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodvoid init_hid() 1996b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{ 2006b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood pthread_t th; 2016b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood pthread_create(&th, NULL, inotify_thread, NULL); 2026b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood} 203