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