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 #ifdef TRACE_VIRTIO_INPUT 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 #endif 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 void 212 ScheduleReadyPacket(VirtioInputDevice* dev, Packet* pkt) 213 { 214 if (dev->readyPackets < 0) 215 dev->readyPackets = pkt - dev->packets; 216 else 217 dev->packets[dev->lastReadyPacket].next = pkt - dev->packets; 218 219 dev->lastReadyPacket = pkt - dev->packets; 220 } 221 222 223 static Packet* 224 ConsumeReadyPacket(VirtioInputDevice* dev) 225 { 226 if (dev->readyPackets < 0) 227 return NULL; 228 Packet* pkt = &dev->packets[dev->readyPackets]; 229 dev->readyPackets = pkt->next; 230 if (dev->readyPackets < 0) 231 dev->lastReadyPacket = -1; 232 return pkt; 233 } 234 235 236 static void 237 virtio_input_callback(void* driverCookie, void* cookie) 238 { 239 CALLED(); 240 VirtioInputDevice* dev = (VirtioInputDevice*)cookie; 241 242 Packet* pkt; 243 while (dev->virtio->queue_dequeue(dev->virtio_queue, (void**)&pkt, NULL)) { 244 #ifdef TRACE_VIRTIO_INPUT 245 TRACE("%" B_PRIdSSIZE ": ", pkt - dev->packets); 246 WriteInputPacket(pkt->data); 247 TRACE("\n"); 248 #endif 249 ScheduleReadyPacket(dev, pkt); 250 release_sem_etc(dev->sem_cb.Get(), 1, B_DO_NOT_RESCHEDULE); 251 } 252 } 253 254 255 // #pragma mark - device module API 256 257 258 static status_t 259 virtio_input_init_device(void* _info, void** _cookie) 260 { 261 CALLED(); 262 VirtioInputDevice* info = (VirtioInputDevice*)_info; 263 264 DeviceNodePutter<&gDeviceManager> parent( 265 gDeviceManager->get_parent_node(info->node)); 266 267 gDeviceManager->get_driver(parent.Get(), 268 (driver_module_info **)&info->virtio, 269 (void **)&info->virtio_device); 270 271 info->virtio->negotiate_features(info->virtio_device, 0, 272 &info->features, NULL); 273 274 status_t status = B_OK; 275 /* 276 status = info->virtio->read_device_config( 277 info->virtio_device, 0, &info->config, 278 sizeof(struct virtio_blk_config)); 279 if (status != B_OK) 280 return status; 281 */ 282 283 InitPackets(info, 8); 284 285 status = info->virtio->alloc_queues(info->virtio_device, 1, 286 &info->virtio_queue); 287 if (status != B_OK) { 288 ERROR("queue allocation failed (%s)\n", strerror(status)); 289 return status; 290 } 291 TRACE(" queue: %p\n", info->virtio_queue); 292 293 status = info->virtio->queue_setup_interrupt(info->virtio_queue, 294 virtio_input_callback, info); 295 if (status < B_OK) 296 return status; 297 298 for (uint32 i = 0; i < info->packetCnt; i++) { 299 Packet* pkt = &info->packets[i]; 300 physical_entry pe = PacketPhysEntry(info, pkt); 301 info->virtio->queue_request(info->virtio_queue, NULL, &pe, pkt); 302 } 303 304 *_cookie = info; 305 return B_OK; 306 } 307 308 309 static void 310 virtio_input_uninit_device(void* _cookie) 311 { 312 CALLED(); 313 VirtioInputDevice* info = (VirtioInputDevice*)_cookie; 314 (void)info; 315 } 316 317 318 static status_t 319 virtio_input_open(void* _info, const char* path, int openMode, void** _cookie) 320 { 321 CALLED(); 322 VirtioInputDevice* info = (VirtioInputDevice*)_info; 323 324 ObjectDeleter<VirtioInputHandle> 325 handle(new(std::nothrow) (VirtioInputHandle)); 326 327 if (!handle.IsSet()) 328 return B_NO_MEMORY; 329 330 handle->info = info; 331 332 *_cookie = handle.Detach(); 333 return B_OK; 334 } 335 336 337 static status_t 338 virtio_input_close(void* cookie) 339 { 340 CALLED(); 341 return B_OK; 342 } 343 344 345 static status_t 346 virtio_input_free(void* cookie) 347 { 348 CALLED(); 349 ObjectDeleter<VirtioInputHandle> handle((VirtioInputHandle*)cookie); 350 return B_OK; 351 } 352 353 354 static status_t 355 virtio_input_read(void* cookie, off_t pos, void* buffer, size_t* _length) 356 { 357 return B_ERROR; 358 } 359 360 361 static status_t 362 virtio_input_write(void* cookie, off_t pos, const void* buffer, 363 size_t* _length) 364 { 365 *_length = 0; 366 return B_ERROR; 367 } 368 369 370 static status_t 371 virtio_input_ioctl(void* cookie, uint32 op, void* buffer, size_t length) 372 { 373 CALLED(); 374 375 VirtioInputHandle* handle = (VirtioInputHandle*)cookie; 376 VirtioInputDevice* info = handle->info; 377 (void)info; 378 379 TRACE("ioctl(op = %" B_PRIu32 ")\n", op); 380 381 switch (op) { 382 case virtioInputRead: { 383 TRACE("virtioInputRead\n"); 384 if (buffer == NULL || length < sizeof(VirtioInputPacket)) 385 return B_BAD_VALUE; 386 387 status_t res = acquire_sem(info->sem_cb.Get()); 388 if (res < B_OK) 389 return res; 390 391 Packet* pkt = ConsumeReadyPacket(info); 392 TRACE(" pkt: %" B_PRIdSSIZE "\n", pkt - info->packets); 393 394 physical_entry pe = PacketPhysEntry(info, pkt); 395 info->virtio->queue_request(info->virtio_queue, NULL, &pe, pkt); 396 397 res = user_memcpy(buffer, pkt, sizeof(Packet)); 398 if (res < B_OK) 399 return res; 400 401 return B_OK; 402 } 403 } 404 405 return B_DEV_INVALID_IOCTL; 406 } 407 408 409 // #pragma mark - driver module API 410 411 412 static float 413 virtio_input_supports_device(device_node *parent) 414 { 415 CALLED(); 416 417 const char *bus; 418 uint16 deviceType; 419 420 // make sure parent is really the Virtio bus manager 421 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 422 return -1; 423 424 if (strcmp(bus, "virtio")) 425 return 0.0; 426 427 // check whether it's really a Direct Access Device 428 if (gDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM, 429 &deviceType, true) != B_OK || deviceType != kVirtioDevInput) 430 return 0.0; 431 432 TRACE("Virtio input device found!\n"); 433 434 return 0.6; 435 } 436 437 438 static status_t 439 virtio_input_register_device(device_node *node) 440 { 441 CALLED(); 442 443 device_attr attrs[] = { 444 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "VirtIO input" }}, 445 { NULL } 446 }; 447 448 return gDeviceManager->register_node(node, VIRTIO_INPUT_DRIVER_MODULE_NAME, 449 attrs, NULL, NULL); 450 } 451 452 453 static status_t 454 virtio_input_init_driver(device_node *node, void **cookie) 455 { 456 CALLED(); 457 458 ObjectDeleter<VirtioInputDevice> 459 info(new(std::nothrow) VirtioInputDevice()); 460 461 if (!info.IsSet()) 462 return B_NO_MEMORY; 463 464 memset(info.Get(), 0, sizeof(*info.Get())); 465 466 info->sem_cb.SetTo(create_sem(0, "virtio_input_cb")); 467 if (!info->sem_cb.IsSet()) 468 return info->sem_cb.Get(); 469 470 info->node = node; 471 472 *cookie = info.Detach(); 473 return B_OK; 474 } 475 476 477 static void 478 virtio_input_uninit_driver(void *_cookie) 479 { 480 CALLED(); 481 ObjectDeleter<VirtioInputDevice> info((VirtioInputDevice*)_cookie); 482 } 483 484 485 static status_t 486 virtio_input_register_child_devices(void* _cookie) 487 { 488 CALLED(); 489 VirtioInputDevice* info = (VirtioInputDevice*)_cookie; 490 status_t status; 491 492 int32 id = gDeviceManager->create_id(VIRTIO_INPUT_DEVICE_ID_GENERATOR); 493 if (id < 0) 494 return id; 495 496 char name[64]; 497 snprintf(name, sizeof(name), "input/virtio/%" B_PRId32 "/raw", id); 498 499 status = gDeviceManager->publish_device(info->node, name, 500 VIRTIO_INPUT_DEVICE_MODULE_NAME); 501 502 if (status < B_OK) { 503 ERROR("publish_device error: 0x%" B_PRIx32 "(%s) \n", status, 504 strerror(status)); 505 } 506 507 return status; 508 } 509 510 511 // #pragma mark - 512 513 514 module_dependency module_dependencies[] = { 515 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 516 { NULL } 517 }; 518 519 520 struct device_module_info sVirtioInputDevice = { 521 { 522 VIRTIO_INPUT_DEVICE_MODULE_NAME, 523 0, 524 NULL 525 }, 526 527 virtio_input_init_device, 528 virtio_input_uninit_device, 529 NULL, // remove, 530 531 virtio_input_open, 532 virtio_input_close, 533 virtio_input_free, 534 virtio_input_read, 535 virtio_input_write, 536 NULL, 537 virtio_input_ioctl, 538 539 NULL, // select 540 NULL, // deselect 541 }; 542 543 struct driver_module_info sVirtioInputDriver = { 544 { 545 VIRTIO_INPUT_DRIVER_MODULE_NAME, 546 0, 547 NULL 548 }, 549 550 virtio_input_supports_device, 551 virtio_input_register_device, 552 virtio_input_init_driver, 553 virtio_input_uninit_driver, 554 virtio_input_register_child_devices, 555 NULL, // rescan 556 NULL, // removed 557 }; 558 559 module_info* modules[] = { 560 (module_info*)&sVirtioInputDriver, 561 (module_info*)&sVirtioInputDevice, 562 NULL 563 }; 564