1 /* 2 * Copyright 2013, Jérôme Duval, korli@users.berlios.de. 3 * Copyright 2021, Haiku, Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <virtio.h> 9 #include <virtio_defs.h> 10 11 #include <stdio.h> 12 #include <string.h> 13 #include <stdlib.h> 14 #include <new> 15 16 #include <kernel.h> 17 #include <fs/devfs.h> 18 #include <int.h> 19 20 #include <virtio_input_driver.h> 21 22 #include <AutoDeleter.h> 23 #include <AutoDeleterOS.h> 24 #include <AutoDeleterDrivers.h> 25 #include <debug.h> 26 27 28 //#define TRACE_VIRTIO_INPUT 29 #ifdef TRACE_VIRTIO_INPUT 30 # define TRACE(x...) dprintf("virtio_input: " x) 31 #else 32 # define TRACE(x...) ; 33 #endif 34 #define ERROR(x...) dprintf("virtio_input: " x) 35 #define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 36 37 #define VIRTIO_INPUT_DRIVER_MODULE_NAME "drivers/input/virtio_input/driver_v1" 38 #define VIRTIO_INPUT_DEVICE_MODULE_NAME "drivers/input/virtio_input/device_v1" 39 #define VIRTIO_INPUT_DEVICE_ID_GENERATOR "virtio_input/device_id" 40 41 42 struct Packet { 43 VirtioInputPacket data; 44 int32 next; 45 }; 46 47 48 struct VirtioInputDevice { 49 device_node* node; 50 ::virtio_device virtio_device; 51 virtio_device_interface* virtio; 52 ::virtio_queue virtio_queue; 53 54 uint32 features; 55 56 uint32 packetCnt; 57 int32 freePackets; 58 int32 readyPackets, lastReadyPacket; 59 AreaDeleter packetArea; 60 phys_addr_t physAdr; 61 Packet* packets; 62 63 SemDeleter sem_cb; 64 }; 65 66 67 struct VirtioInputHandle { 68 VirtioInputDevice* info; 69 }; 70 71 72 device_manager_info* gDeviceManager; 73 74 75 static void 76 WriteInputPacket(const VirtioInputPacket &pkt) 77 { 78 switch (pkt.type) { 79 case kVirtioInputEvSyn: 80 TRACE("syn"); 81 break; 82 case kVirtioInputEvKey: 83 TRACE("key, "); 84 switch (pkt.code) { 85 case kVirtioInputBtnLeft: 86 TRACE("left"); 87 break; 88 case kVirtioInputBtnRight: 89 TRACE("middle"); 90 break; 91 case kVirtioInputBtnMiddle: 92 TRACE("right"); 93 break; 94 case kVirtioInputBtnGearDown: 95 TRACE("gearDown"); 96 break; 97 case kVirtioInputBtnGearUp: 98 TRACE("gearUp"); 99 break; 100 default: 101 TRACE("%d", pkt.code); 102 } 103 break; 104 case kVirtioInputEvRel: 105 TRACE("rel, "); 106 switch (pkt.code) { 107 case kVirtioInputRelX: 108 TRACE("relX"); 109 break; 110 case kVirtioInputRelY: 111 TRACE("relY"); 112 break; 113 case kVirtioInputRelZ: 114 TRACE("relZ"); 115 break; 116 case kVirtioInputRelWheel: 117 TRACE("relWheel"); 118 break; 119 default: 120 TRACE("%d", pkt.code); 121 } 122 break; 123 case kVirtioInputEvAbs: 124 TRACE("abs, "); 125 switch (pkt.code) { 126 case kVirtioInputAbsX: 127 TRACE("absX"); 128 break; 129 case kVirtioInputAbsY: 130 TRACE("absY"); 131 break; 132 case kVirtioInputAbsZ: 133 TRACE("absZ"); 134 break; 135 default: 136 TRACE("%d", pkt.code); 137 } 138 break; 139 case kVirtioInputEvRep: 140 TRACE("rep"); 141 break; 142 default: 143 TRACE("?(%d)", pkt.type); 144 } 145 switch (pkt.type) { 146 case kVirtioInputEvSyn: 147 break; 148 case kVirtioInputEvKey: 149 TRACE(", "); 150 if (pkt.value == 0) { 151 TRACE("up"); 152 } else if (pkt.value == 1) { 153 TRACE("down"); 154 } else { 155 TRACE("%" B_PRId32, pkt.value); 156 } 157 break; 158 default: 159 TRACE(", %" B_PRId32, pkt.value); 160 } 161 } 162 163 164 static void 165 InitPackets(VirtioInputDevice* dev, uint32 count) 166 { 167 TRACE("InitPackets(%p, %" B_PRIu32 ")\n", dev, count); 168 size_t size = ROUNDUP(sizeof(Packet)*count, B_PAGE_SIZE); 169 170 dev->packetArea.SetTo(create_area("VirtIO input packets", 171 (void**)&dev->packets, B_ANY_KERNEL_ADDRESS, size, 172 B_CONTIGUOUS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA)); 173 if (!dev->packetArea.IsSet()) { 174 ERROR("Unable to set packet area!"); 175 return; 176 } 177 178 physical_entry pe; 179 if (get_memory_map(dev->packets, size, &pe, 1) < B_OK) { 180 ERROR("Unable to get memory map for input packets!"); 181 return; 182 } 183 dev->physAdr = pe.address; 184 memset(dev->packets, 0, size); 185 dprintf(" size: 0x%" B_PRIxSIZE "\n", size); 186 dprintf(" virt: %p\n", dev->packets); 187 dprintf(" phys: %p\n", (void*)dev->physAdr); 188 189 dev->packetCnt = count; 190 191 dev->freePackets = 0; 192 for (uint32 i = 0; i < dev->packetCnt - 1; i++) 193 dev->packets[i].next = i + 1; 194 dev->packets[dev->packetCnt - 1].next = -1; 195 196 dev->readyPackets = -1; 197 dev->lastReadyPacket = -1; 198 } 199 200 201 static const physical_entry 202 PacketPhysEntry(VirtioInputDevice* dev, Packet* pkt) 203 { 204 physical_entry pe; 205 pe.address = dev->physAdr + (uint8*)pkt - (uint8*)dev->packets; 206 pe.size = sizeof(VirtioInputPacket); 207 return pe; 208 } 209 210 211 static Packet* 212 AllocPacket(VirtioInputDevice* dev) 213 { 214 int32 idx = dev->freePackets; 215 if (idx < 0) 216 return NULL; 217 dev->freePackets = dev->packets[idx].next; 218 219 return &dev->packets[idx]; 220 } 221 222 223 static void 224 FreePacket(VirtioInputDevice* dev, Packet* pkt) 225 { 226 pkt->next = dev->freePackets; 227 dev->freePackets = pkt - dev->packets; 228 } 229 230 231 static void 232 ScheduleReadyPacket(VirtioInputDevice* dev, Packet* pkt) 233 { 234 if (dev->readyPackets < 0) 235 dev->readyPackets = pkt - dev->packets; 236 else 237 dev->packets[dev->lastReadyPacket].next = pkt - dev->packets; 238 239 dev->lastReadyPacket = pkt - dev->packets; 240 } 241 242 243 static Packet* 244 ConsumeReadyPacket(VirtioInputDevice* dev) 245 { 246 if (dev->readyPackets < 0) 247 return NULL; 248 Packet* pkt = &dev->packets[dev->readyPackets]; 249 dev->readyPackets = pkt->next; 250 if (dev->readyPackets < 0) 251 dev->lastReadyPacket = -1; 252 return pkt; 253 } 254 255 256 static void 257 virtio_input_callback(void* driverCookie, void* cookie) 258 { 259 CALLED(); 260 VirtioInputDevice* dev = (VirtioInputDevice*)cookie; 261 262 Packet* pkt; 263 while (dev->virtio->queue_dequeue(dev->virtio_queue, (void**)&pkt, NULL)) { 264 #ifdef TRACE_VIRTIO_INPUT 265 TRACE("%" B_PRIdSSIZE ": ", pkt - dev->packets); 266 WriteInputPacket(pkt->data); 267 TRACE("\n"); 268 #endif 269 ScheduleReadyPacket(dev, pkt); 270 release_sem_etc(dev->sem_cb.Get(), 1, B_DO_NOT_RESCHEDULE); 271 } 272 } 273 274 275 // #pragma mark - device module API 276 277 278 static status_t 279 virtio_input_init_device(void* _info, void** _cookie) 280 { 281 CALLED(); 282 VirtioInputDevice* info = (VirtioInputDevice*)_info; 283 284 DeviceNodePutter<&gDeviceManager> parent( 285 gDeviceManager->get_parent_node(info->node)); 286 287 gDeviceManager->get_driver(parent.Get(), 288 (driver_module_info **)&info->virtio, 289 (void **)&info->virtio_device); 290 291 info->virtio->negotiate_features(info->virtio_device, 0, 292 &info->features, NULL); 293 294 status_t status = B_OK; 295 /* 296 status = info->virtio->read_device_config( 297 info->virtio_device, 0, &info->config, 298 sizeof(struct virtio_blk_config)); 299 if (status != B_OK) 300 return status; 301 */ 302 303 InitPackets(info, 8); 304 305 status = info->virtio->alloc_queues(info->virtio_device, 1, 306 &info->virtio_queue); 307 if (status != B_OK) { 308 ERROR("queue allocation failed (%s)\n", strerror(status)); 309 return status; 310 } 311 TRACE(" queue: %p\n", info->virtio_queue); 312 313 status = info->virtio->queue_setup_interrupt(info->virtio_queue, 314 virtio_input_callback, info); 315 if (status < B_OK) 316 return status; 317 318 for (uint32 i = 0; i < info->packetCnt; i++) { 319 Packet* pkt = &info->packets[i]; 320 physical_entry pe = PacketPhysEntry(info, pkt); 321 info->virtio->queue_request(info->virtio_queue, NULL, &pe, pkt); 322 } 323 324 *_cookie = info; 325 return B_OK; 326 } 327 328 329 static void 330 virtio_input_uninit_device(void* _cookie) 331 { 332 CALLED(); 333 VirtioInputDevice* info = (VirtioInputDevice*)_cookie; 334 (void)info; 335 } 336 337 338 static status_t 339 virtio_input_open(void* _info, const char* path, int openMode, void** _cookie) 340 { 341 CALLED(); 342 VirtioInputDevice* info = (VirtioInputDevice*)_info; 343 344 ObjectDeleter<VirtioInputHandle> 345 handle(new(std::nothrow) (VirtioInputHandle)); 346 347 if (!handle.IsSet()) 348 return B_NO_MEMORY; 349 350 handle->info = info; 351 352 *_cookie = handle.Detach(); 353 return B_OK; 354 } 355 356 357 static status_t 358 virtio_input_close(void* cookie) 359 { 360 CALLED(); 361 return B_OK; 362 } 363 364 365 static status_t 366 virtio_input_free(void* cookie) 367 { 368 CALLED(); 369 ObjectDeleter<VirtioInputHandle> handle((VirtioInputHandle*)cookie); 370 return B_OK; 371 } 372 373 374 static status_t 375 virtio_input_read(void* cookie, off_t pos, void* buffer, size_t* _length) 376 { 377 return B_ERROR; 378 } 379 380 381 static status_t 382 virtio_input_write(void* cookie, off_t pos, const void* buffer, 383 size_t* _length) 384 { 385 *_length = 0; 386 return B_ERROR; 387 } 388 389 390 static status_t 391 virtio_input_ioctl(void* cookie, uint32 op, void* buffer, size_t length) 392 { 393 CALLED(); 394 395 VirtioInputHandle* handle = (VirtioInputHandle*)cookie; 396 VirtioInputDevice* info = handle->info; 397 (void)info; 398 399 TRACE("ioctl(op = %" B_PRIu32 ")\n", op); 400 401 switch (op) { 402 case virtioInputRead: { 403 TRACE("virtioInputRead\n"); 404 if (buffer == NULL || length < sizeof(VirtioInputPacket)) 405 return B_BAD_VALUE; 406 407 status_t res = acquire_sem(info->sem_cb.Get()); 408 if (res < B_OK) 409 return res; 410 411 Packet* pkt = ConsumeReadyPacket(info); 412 TRACE(" pkt: %" B_PRIdSSIZE "\n", pkt - info->packets); 413 414 physical_entry pe = PacketPhysEntry(info, pkt); 415 info->virtio->queue_request(info->virtio_queue, NULL, &pe, pkt); 416 417 res = user_memcpy(buffer, pkt, sizeof(Packet)); 418 if (res < B_OK) 419 return res; 420 421 return B_OK; 422 } 423 } 424 425 return B_DEV_INVALID_IOCTL; 426 } 427 428 429 // #pragma mark - driver module API 430 431 432 static float 433 virtio_input_supports_device(device_node *parent) 434 { 435 CALLED(); 436 437 const char *bus; 438 uint16 deviceType; 439 440 // make sure parent is really the Virtio bus manager 441 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 442 return -1; 443 444 if (strcmp(bus, "virtio")) 445 return 0.0; 446 447 // check whether it's really a Direct Access Device 448 if (gDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM, 449 &deviceType, true) != B_OK || deviceType != kVirtioDevInput) 450 return 0.0; 451 452 TRACE("Virtio input device found!\n"); 453 454 return 0.6; 455 } 456 457 458 static status_t 459 virtio_input_register_device(device_node *node) 460 { 461 CALLED(); 462 463 device_attr attrs[] = { 464 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "VirtIO input" }}, 465 { NULL } 466 }; 467 468 return gDeviceManager->register_node(node, VIRTIO_INPUT_DRIVER_MODULE_NAME, 469 attrs, NULL, NULL); 470 } 471 472 473 static status_t 474 virtio_input_init_driver(device_node *node, void **cookie) 475 { 476 CALLED(); 477 478 ObjectDeleter<VirtioInputDevice> 479 info(new(std::nothrow) VirtioInputDevice()); 480 481 if (!info.IsSet()) 482 return B_NO_MEMORY; 483 484 memset(info.Get(), 0, sizeof(*info.Get())); 485 486 info->sem_cb.SetTo(create_sem(0, "virtio_input_cb")); 487 if (!info->sem_cb.IsSet()) 488 return info->sem_cb.Get(); 489 490 info->node = node; 491 492 *cookie = info.Detach(); 493 return B_OK; 494 } 495 496 497 static void 498 virtio_input_uninit_driver(void *_cookie) 499 { 500 CALLED(); 501 ObjectDeleter<VirtioInputDevice> info((VirtioInputDevice*)_cookie); 502 } 503 504 505 static status_t 506 virtio_input_register_child_devices(void* _cookie) 507 { 508 CALLED(); 509 VirtioInputDevice* info = (VirtioInputDevice*)_cookie; 510 status_t status; 511 512 int32 id = gDeviceManager->create_id(VIRTIO_INPUT_DEVICE_ID_GENERATOR); 513 if (id < 0) 514 return id; 515 516 char name[64]; 517 snprintf(name, sizeof(name), "input/virtio/%" B_PRId32 "/raw", id); 518 519 status = gDeviceManager->publish_device(info->node, name, 520 VIRTIO_INPUT_DEVICE_MODULE_NAME); 521 522 if (status < B_OK) { 523 ERROR("publish_device error: 0x%" B_PRIx32 "(%s) \n", status, 524 strerror(status)); 525 } 526 527 return status; 528 } 529 530 531 // #pragma mark - 532 533 534 module_dependency module_dependencies[] = { 535 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 536 { NULL } 537 }; 538 539 540 struct device_module_info sVirtioInputDevice = { 541 { 542 VIRTIO_INPUT_DEVICE_MODULE_NAME, 543 0, 544 NULL 545 }, 546 547 virtio_input_init_device, 548 virtio_input_uninit_device, 549 NULL, // remove, 550 551 virtio_input_open, 552 virtio_input_close, 553 virtio_input_free, 554 virtio_input_read, 555 virtio_input_write, 556 NULL, 557 virtio_input_ioctl, 558 559 NULL, // select 560 NULL, // deselect 561 }; 562 563 struct driver_module_info sVirtioInputDriver = { 564 { 565 VIRTIO_INPUT_DRIVER_MODULE_NAME, 566 0, 567 NULL 568 }, 569 570 virtio_input_supports_device, 571 virtio_input_register_device, 572 virtio_input_init_driver, 573 virtio_input_uninit_driver, 574 virtio_input_register_child_devices, 575 NULL, // rescan 576 NULL, // removed 577 }; 578 579 module_info* modules[] = { 580 (module_info*)&sVirtioInputDriver, 581 (module_info*)&sVirtioInputDevice, 582 NULL 583 }; 584