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