1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <ddk/debug.h>
6#include <ddk/device.h>
7#include <ddk/driver.h>
8#include <ddk/binding.h>
9#include <ddk/protocol/hidbus.h>
10#include <ddk/protocol/i2c.h>
11
12#include <zircon/assert.h>
13#include <zircon/types.h>
14#include <zircon/device/i2c.h>
15
16#include <endian.h>
17#include <stdbool.h>
18#include <stdlib.h>
19#include <string.h>
20#include <threads.h>
21#include <unistd.h>
22
23#define I2C_HID_DEBUG 0
24
25// Poll interval: 10 ms
26#define I2C_POLL_INTERVAL_USEC 10000
27
28#define to_i2c_hid(d) containerof(d, i2c_hid_device_t, hiddev)
29
30typedef struct i2c_hid_desc {
31    uint16_t wHIDDescLength;
32    uint16_t bcdVersion;
33    uint16_t wReportDescLength;
34    uint16_t wReportDescRegister;
35    uint16_t wInputRegister;
36    uint16_t wMaxInputLength;
37    uint16_t wOutputRegister;
38    uint16_t wMaxOutputLength;
39    uint16_t wCommandRegister;
40    uint16_t wDataRegister;
41    uint16_t wVendorID;
42    uint16_t wProductID;
43    uint16_t wVersionID;
44    uint8_t RESERVED[4];
45} __PACKED i2c_hid_desc_t;
46
47typedef struct i2c_hid_device {
48    zx_device_t* i2cdev;
49
50    mtx_t ifc_lock;
51    hidbus_ifc_t* ifc;
52    void* cookie;
53
54    i2c_hid_desc_t* hiddesc;
55
56    mtx_t i2c_lock;
57    cnd_t i2c_reset_cnd; // Signaled when reset received
58    bool i2c_pending_reset; // True if reset-in-progress
59    thrd_t irq_thread;
60    zx_handle_t irq;
61} i2c_hid_device_t;
62
63// Send the device a HOST initiated RESET.  Caller must call
64// i2c_wait_for_ready_locked() afterwards to guarantee completion.
65// If |force| is false, do not issue a reset if there is one outstanding.
66static zx_status_t i2c_hid_reset(i2c_hid_device_t* dev, bool force) {
67    uint16_t cmd_reg = letoh16(dev->hiddesc->wCommandRegister);
68    uint8_t buf[4] = { cmd_reg & 0xff, cmd_reg >> 8, 0x00, 0x01 };
69    size_t actual;
70
71    mtx_lock(&dev->i2c_lock);
72
73    if (!force && dev->i2c_pending_reset) {
74        mtx_unlock(&dev->i2c_lock);
75        return ZX_OK;
76    }
77
78    dev->i2c_pending_reset = true;
79    zx_status_t status = device_write(dev->i2cdev, buf, sizeof(buf), 0, &actual);
80
81    mtx_unlock(&dev->i2c_lock);
82
83    if (status != ZX_OK) {
84        zxlogf(ERROR, "i2c-hid: could not issue reset: %d\n", status);
85        return status;
86    }
87    if (actual != sizeof(buf)) {
88        zxlogf(ERROR, "i2c-hid: could not issue reset: short write?\n");
89        return ZX_ERR_IO;
90    }
91
92    return ZX_OK;
93}
94
95// Must be called with i2c_lock held.
96static void i2c_wait_for_ready_locked(i2c_hid_device_t* dev) {
97    while (dev->i2c_pending_reset) {
98        cnd_wait(&dev->i2c_reset_cnd, &dev->i2c_lock);
99    }
100}
101
102static zx_status_t i2c_hid_query(void* ctx, uint32_t options, hid_info_t* info) {
103    if (!info) {
104        return ZX_ERR_INVALID_ARGS;
105    }
106    info->dev_num = 0;
107    info->dev_class = HID_DEV_CLASS_OTHER;
108    info->boot_device = false;
109    return ZX_OK;
110}
111
112static zx_status_t i2c_hid_start(void* ctx, hidbus_ifc_t* ifc, void* cookie) {
113    i2c_hid_device_t* hid = ctx;
114    mtx_lock(&hid->ifc_lock);
115    if (hid->ifc) {
116        mtx_unlock(&hid->ifc_lock);
117        return ZX_ERR_ALREADY_BOUND;
118    }
119    hid->ifc = ifc;
120    hid->cookie = cookie;
121    mtx_unlock(&hid->ifc_lock);
122    return ZX_OK;
123}
124
125static void i2c_hid_stop(void* ctx) {
126    i2c_hid_device_t* hid = ctx;
127    mtx_lock(&hid->ifc_lock);
128    hid->ifc = NULL;
129    hid->cookie = NULL;
130    mtx_unlock(&hid->ifc_lock);
131}
132
133static zx_status_t i2c_hid_get_descriptor(void* ctx, uint8_t desc_type,
134        void** data, size_t* len) {
135    if (desc_type != HID_DESC_TYPE_REPORT) {
136        return ZX_ERR_NOT_FOUND;
137    }
138
139    i2c_hid_device_t* hid = ctx;
140    size_t desc_len = letoh16(hid->hiddesc->wReportDescLength);
141    uint16_t desc_reg = letoh16(hid->hiddesc->wReportDescRegister);
142    uint16_t buf = htole16(desc_reg);
143    uint8_t* out = malloc(desc_len);
144    if (out == NULL) {
145        return ZX_ERR_NO_MEMORY;
146    }
147    i2c_protocol_t i2c;
148    zx_status_t status;
149    status = device_get_protocol(hid->i2cdev, ZX_PROTOCOL_I2C, &i2c);
150    if (status != ZX_OK) {
151        zxlogf(ERROR, "i2c-hid: could not get I2C protocol: %d\n", status);
152        return ZX_ERR_NOT_SUPPORTED;
153    }
154
155    mtx_lock(&hid->i2c_lock);
156    i2c_wait_for_ready_locked(hid);
157
158    status = i2c_write_read_sync(&i2c, &buf, sizeof(uint16_t), out, desc_len);
159    mtx_unlock(&hid->i2c_lock);
160    if (status < 0) {
161        zxlogf(ERROR, "i2c-hid: could not read HID report descriptor from reg 0x%04x: %d\n",
162               desc_reg, status);
163        free(out);
164        return ZX_ERR_NOT_SUPPORTED;
165    }
166
167    *data = out;
168    *len = desc_len;
169    return ZX_OK;
170}
171
172// TODO: implement the rest of the HID protocol
173static zx_status_t i2c_hid_get_report(void* ctx, uint8_t rpt_type, uint8_t rpt_id,
174        void* data, size_t len, size_t* out_len) {
175    return ZX_ERR_NOT_SUPPORTED;
176}
177
178static zx_status_t i2c_hid_set_report(void* ctx, uint8_t rpt_type, uint8_t rpt_id,
179        void* data, size_t len) {
180    return ZX_ERR_NOT_SUPPORTED;
181}
182
183static zx_status_t i2c_hid_get_idle(void* ctx, uint8_t rpt_id, uint8_t* duration) {
184    return ZX_ERR_NOT_SUPPORTED;
185}
186
187static zx_status_t i2c_hid_set_idle(void* ctx, uint8_t rpt_id, uint8_t duration) {
188    return ZX_OK;
189}
190
191static zx_status_t i2c_hid_get_protocol(void* ctx, uint8_t* protocol) {
192    return ZX_ERR_NOT_SUPPORTED;
193}
194
195static zx_status_t i2c_hid_set_protocol(void* ctx, uint8_t protocol) {
196    return ZX_OK;
197}
198
199
200static hidbus_protocol_ops_t i2c_hidbus_ops = {
201    .query = i2c_hid_query,
202    .start = i2c_hid_start,
203    .stop = i2c_hid_stop,
204    .get_descriptor = i2c_hid_get_descriptor,
205    .get_report = i2c_hid_get_report,
206    .set_report = i2c_hid_set_report,
207    .get_idle = i2c_hid_get_idle,
208    .set_idle = i2c_hid_set_idle,
209    .get_protocol = i2c_hid_get_protocol,
210    .set_protocol = i2c_hid_set_protocol,
211};
212
213static inline size_t bcdtoa(uint16_t val, char str[static 6], bool pad) {
214    memset(str, 0, 6);
215    size_t idx = 0;
216    if (val >> 12) {
217        str[idx++] = (val >> 12) + '0';
218    }
219    str[idx++] = ((val >> 8) & 0xf) + '0';
220    str[idx++] = '.';
221    str[idx++] = ((val >> 4) & 0xf) + '0';
222    str[idx++] = (val & 0xf) + '0';
223    return idx;
224}
225
226// TODO(teisenbe/tkilbourn): Remove this once we pipe IRQs from ACPI
227static int i2c_hid_noirq_thread(void* arg) {
228    zxlogf(INFO, "i2c-hid: using noirq\n");
229
230    i2c_hid_device_t* dev = (i2c_hid_device_t*)arg;
231
232    zx_status_t status = i2c_hid_reset(dev, true);
233    if (status != ZX_OK) {
234        zxlogf(ERROR, "i2c-hid: failed to reset i2c device\n");
235        return 0;
236    }
237
238    uint16_t len = letoh16(dev->hiddesc->wMaxInputLength);
239    uint8_t* buf = malloc(len);
240
241    // Last report received, so we can deduplicate.  This is only necessary since
242    // we haven't wired through interrupts yet, and some devices always return
243    // the last received report when you attempt to read from them.
244    uint8_t* last_report = malloc(len);
245    size_t last_report_len = 0;
246
247    zx_time_t last_timeout_warning = 0;
248    const zx_duration_t kMinTimeBetweenWarnings = ZX_SEC(10);
249
250    // Until we have a way to map the GPIO associated with an i2c slave to an
251    // IRQ, we just poll.
252    while (true) {
253        usleep(I2C_POLL_INTERVAL_USEC);
254        size_t actual = 0;
255        mtx_lock(&dev->i2c_lock);
256        zx_status_t status = device_read(dev->i2cdev, buf, len, 0, &actual);
257        if (status != ZX_OK) {
258            if (status == ZX_ERR_TIMED_OUT) {
259                zx_time_t now = zx_clock_get_monotonic();
260                if (now - last_timeout_warning > kMinTimeBetweenWarnings) {
261                    zxlogf(TRACE, "i2c-hid: device_read timed out\n");
262                    last_timeout_warning = now;
263                }
264                mtx_unlock(&dev->i2c_lock);
265                continue;
266            }
267            zxlogf(ERROR, "i2c-hid: device_read failure %d\n", status);
268            mtx_unlock(&dev->i2c_lock);
269            continue;
270        }
271        if (actual < 2) {
272            zxlogf(ERROR, "i2c-hid: short read (%zd < 2)!!!\n", actual);
273            mtx_unlock(&dev->i2c_lock);
274            continue;
275        }
276
277        uint16_t report_len = letoh16(*(uint16_t*)buf);
278        if (report_len == 0x0) {
279            dev->i2c_pending_reset = false;
280            cnd_broadcast(&dev->i2c_reset_cnd);
281            mtx_unlock(&dev->i2c_lock);
282            continue;
283        }
284        mtx_unlock(&dev->i2c_lock);
285
286        if (dev->i2c_pending_reset) {
287            zxlogf(INFO, "i2c-hid: received event while waiting for reset? %u\n", report_len);
288            continue;
289        }
290        if ((report_len == 0xffff) || (report_len == 0x3fff)) {
291            // nothing to read
292            continue;
293        }
294        if ((report_len > actual) || (report_len < 2)) {
295            zxlogf(ERROR, "i2c-hid: bad report len (rlen %hu, bytes read %zd)!!!\n",
296                    report_len, actual);
297            continue;
298        }
299
300        // Check for duplicates.  See comment by |last_report| definition.
301        if (last_report_len == report_len && !memcmp(buf, last_report, report_len)) {
302            continue;
303        }
304
305        mtx_lock(&dev->ifc_lock);
306        if (dev->ifc) {
307            dev->ifc->io_queue(dev->cookie, buf + 2, report_len - 2);
308        }
309        mtx_unlock(&dev->ifc_lock);
310
311        last_report_len = report_len;
312
313        // Swap buffers
314        uint8_t* tmp = last_report;
315        last_report = buf;
316        buf = tmp;
317    }
318
319    // TODO: figure out how to clean up
320    free(buf);
321    free(last_report);
322    return 0;
323}
324
325static int i2c_hid_irq_thread(void* arg) {
326    zxlogf(TRACE, "i2c-hid: using irq\n");
327
328    i2c_hid_device_t* dev = (i2c_hid_device_t*)arg;
329
330    zx_status_t status = i2c_hid_reset(dev, true);
331    if (status != ZX_OK) {
332        zxlogf(ERROR, "i2c-hid: failed to reset i2c device\n");
333        return 0;
334    }
335
336    uint16_t len = letoh16(dev->hiddesc->wMaxInputLength);
337    uint8_t* buf = malloc(len);
338
339    zx_time_t last_timeout_warning = 0;
340    const zx_duration_t kMinTimeBetweenWarnings = ZX_SEC(10);
341
342    while (true) {
343        zx_status_t status = zx_interrupt_wait(dev->irq, NULL);
344        if (status != ZX_OK) {
345            zxlogf(ERROR, "i2c-hid: interrupt wait failed %d\n", status);
346            break;
347        }
348
349        mtx_lock(&dev->i2c_lock);
350
351        size_t actual = 0;
352        status = device_read(dev->i2cdev, buf, len, 0, &actual);
353        if (status != ZX_OK) {
354            if (status == ZX_ERR_TIMED_OUT) {
355                zx_time_t now = zx_clock_get_monotonic();
356                if (now - last_timeout_warning > kMinTimeBetweenWarnings) {
357                    zxlogf(TRACE, "i2c-hid: device_read timed out\n");
358                    last_timeout_warning = now;
359                }
360                mtx_unlock(&dev->i2c_lock);
361                continue;
362            }
363            zxlogf(ERROR, "i2c-hid: device_read failure %d\n", status);
364            mtx_unlock(&dev->i2c_lock);
365            continue;
366        }
367        if (actual < 2) {
368            zxlogf(ERROR, "i2c-hid: short read (%zd < 2)!!!\n", actual);
369            mtx_unlock(&dev->i2c_lock);
370            continue;
371        }
372
373        uint16_t report_len = letoh16(*(uint16_t*)buf);
374        if (report_len == 0x0) {
375            zxlogf(INFO, "i2c-hid reset detected\n");
376            // Either host or device reset.
377            dev->i2c_pending_reset = false;
378            cnd_broadcast(&dev->i2c_reset_cnd);
379            mtx_unlock(&dev->i2c_lock);
380            continue;
381        }
382
383        if (dev->i2c_pending_reset) {
384            zxlogf(INFO, "i2c-hid: received event while waiting for reset? %u\n", report_len);
385            mtx_unlock(&dev->i2c_lock);
386            continue;
387        }
388
389        if ((report_len > actual) || (report_len < 2)) {
390            zxlogf(ERROR, "i2c-hid: bad report len (rlen %hu, bytes read %zd)!!!\n",
391                    report_len, actual);
392            mtx_unlock(&dev->i2c_lock);
393            continue;
394        }
395
396        mtx_unlock(&dev->i2c_lock);
397
398        mtx_lock(&dev->ifc_lock);
399        if (dev->ifc) {
400            dev->ifc->io_queue(dev->cookie, buf + 2, report_len - 2);
401        }
402        mtx_unlock(&dev->ifc_lock);
403    }
404
405    // TODO: figure out how to clean up
406    free(buf);
407    return 0;
408}
409
410static void i2c_hid_release(void* ctx) {
411    ZX_PANIC("cannot release an i2c hid device yet!\n");
412}
413
414static zx_protocol_device_t i2c_hid_dev_ops = {
415    .version = DEVICE_OPS_VERSION,
416    .release = i2c_hid_release,
417};
418
419static zx_status_t i2c_hid_bind(void* ctx, zx_device_t* dev) {
420    zxlogf(TRACE, "i2c_hid_bind\n");
421
422    // Read the i2c HID descriptor
423    // TODO: get the address out of ACPI
424    uint8_t buf[2];
425    uint8_t* data = buf;
426    *data++ = 0x01;
427    *data++ = 0x00;
428    uint8_t out[4];
429    i2c_protocol_t i2c;
430    zx_status_t status = device_get_protocol(dev, ZX_PROTOCOL_I2C, &i2c);
431    if (status != ZX_OK) {
432        zxlogf(ERROR, "i2c-hid: could not get I2C protocol: %d\n", status);
433        return ZX_ERR_NOT_SUPPORTED;
434    }
435    if (i2c_write_read_sync(&i2c, buf, sizeof(buf), out, sizeof(out)) != ZX_OK) {
436        zxlogf(ERROR, "i2c-hid: could not read HID descriptor: %d\n", status);
437        return ZX_ERR_NOT_SUPPORTED;
438    }
439
440    i2c_hid_desc_t* i2c_hid_desc_hdr = (i2c_hid_desc_t*)out;
441    uint16_t desc_len = letoh16(i2c_hid_desc_hdr->wHIDDescLength);
442
443    i2c_hid_device_t* i2chid = calloc(1, sizeof(i2c_hid_device_t));
444    if (i2chid == NULL) {
445        return ZX_ERR_NO_MEMORY;
446    }
447    mtx_init(&i2chid->ifc_lock, mtx_plain);
448    mtx_init(&i2chid->i2c_lock, mtx_plain);
449    cnd_init(&i2chid->i2c_reset_cnd);
450    i2chid->i2cdev = dev;
451    i2chid->hiddesc = malloc(desc_len);
452    // Mark as pending reset, so no external requests will complete until we
453    // reset the device in the IRQ thread.
454    i2chid->i2c_pending_reset = true;
455
456    if (i2c_write_read_sync(&i2c, buf, sizeof(buf), i2chid->hiddesc, desc_len) != ZX_OK) {
457        zxlogf(ERROR, "i2c-hid: could not read HID descriptor: %d\n", status);
458        free(i2chid->hiddesc);
459        free(i2chid);
460        return ZX_ERR_NOT_SUPPORTED;
461    }
462
463    zxlogf(TRACE, "i2c-hid: desc:\n");
464    zxlogf(TRACE, "  report desc len: %u\n", letoh16(i2chid->hiddesc->wReportDescLength));
465    zxlogf(TRACE, "  report desc reg: %u\n", letoh16(i2chid->hiddesc->wReportDescRegister));
466    zxlogf(TRACE, "  input reg:       %u\n", letoh16(i2chid->hiddesc->wInputRegister));
467    zxlogf(TRACE, "  max input len:   %u\n", letoh16(i2chid->hiddesc->wMaxInputLength));
468    zxlogf(TRACE, "  output reg:      %u\n", letoh16(i2chid->hiddesc->wOutputRegister));
469    zxlogf(TRACE, "  max output len:  %u\n", letoh16(i2chid->hiddesc->wMaxOutputLength));
470    zxlogf(TRACE, "  command reg:     %u\n", letoh16(i2chid->hiddesc->wCommandRegister));
471    zxlogf(TRACE, "  data reg:        %u\n", letoh16(i2chid->hiddesc->wDataRegister));
472    zxlogf(TRACE, "  vendor id:       %x\n", i2chid->hiddesc->wVendorID);
473    zxlogf(TRACE, "  product id:      %x\n", i2chid->hiddesc->wProductID);
474    zxlogf(TRACE, "  version id:      %x\n", i2chid->hiddesc->wVersionID);
475
476    device_add_args_t args = {
477        .version = DEVICE_ADD_ARGS_VERSION,
478        .name = "i2c-hid",
479        .ctx = i2chid,
480        .ops = &i2c_hid_dev_ops,
481        .proto_id = ZX_PROTOCOL_HIDBUS,
482        .proto_ops = &i2c_hidbus_ops,
483    };
484
485    status = device_add(i2chid->i2cdev, &args, NULL);
486    if (status != ZX_OK) {
487        zxlogf(ERROR, "i2c-hid: could not add device: %d\n", status);
488        free(i2chid->hiddesc);
489        free(i2chid);
490        return status;
491    }
492    status = i2c_get_interrupt(&i2c, 0, &i2chid->irq);
493    int ret;
494    if (status != ZX_OK) {
495        ret = thrd_create_with_name(&i2chid->irq_thread, i2c_hid_noirq_thread, i2chid,
496                                    "i2c-hid-noirq");
497    } else {
498        ret = thrd_create_with_name(&i2chid->irq_thread, i2c_hid_irq_thread, i2chid,
499                                    "i2c-hid-irq");
500    }
501    if (ret != thrd_success) {
502        zxlogf(ERROR, "i2c-hid: could not create irq thread: %d\n", ret);
503        free(i2chid->hiddesc);
504        free(i2chid);
505        // TODO: map thrd_* status codes to ZX_ERR_* status codes
506        return ZX_ERR_INTERNAL;
507    }
508
509    return ZX_OK;
510}
511
512static zx_driver_ops_t i2c_hid_driver_ops = {
513    .version = DRIVER_OPS_VERSION,
514    .bind = i2c_hid_bind,
515};
516
517ZIRCON_DRIVER_BEGIN(i2c_hid, i2c_hid_driver_ops, "zircon", "0.1", 2)
518    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_I2C),
519    BI_MATCH_IF(EQ, BIND_I2C_CLASS, I2C_CLASS_HID),
520ZIRCON_DRIVER_END(i2c_hid)
521