1 /* 2 * Copyright 2009-2010, François Revol, <revol@free.fr>. 3 * Sponsored by TuneTracker Systems. 4 * Based on the Haiku usb_serial driver which is: 5 * 6 * Copyright (c) 2007-2008 by Michael Lotz 7 * Heavily based on the original usb_serial driver which is: 8 * 9 * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li> 10 * Distributed under the terms of the MIT License. 11 */ 12 #include <KernelExport.h> 13 #include <Drivers.h> 14 #include <image.h> 15 #include <malloc.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 19 #include "Driver.h" 20 #include "SerialDevice.h" 21 22 int32 api_version = B_CUR_DRIVER_API_VERSION; 23 static const char *sDeviceBaseName = DEVFS_BASE; 24 SerialDevice *gSerialDevices[DEVICES_COUNT]; 25 char *gDeviceNames[DEVICES_COUNT + 1]; 26 config_manager_for_driver_module_info *gConfigManagerModule = NULL; 27 isa_module_info *gISAModule = NULL; 28 pci_module_info *gPCIModule = NULL; 29 #ifdef __HAIKU__ 30 tty_module_info *gTTYModule = NULL; 31 #else 32 tty_module_info_v1_bone *gTTYModule = NULL; 33 #endif 34 #ifdef __BEOS__ 35 struct ddomain gSerialDomain; 36 #endif 37 sem_id gDriverLock = -1; 38 bool gHandleISA = false; 39 40 // 24 MHz clock 41 static const uint32 sDefaultRates[] = { 42 0, //B0 43 2304, //B50 44 1536, //B75 45 1047, //B110 46 857, //B134 47 768, //B150 48 512, //B200 49 384, //B300 50 192, //B600 51 0, //B1200 52 0, //B1800 53 48, //B2400 54 24, //B4800 55 12, //B9600 56 6, //B19200 57 3, //B38400 58 2, //B57600 59 1, //B115200 60 0, //B230400 61 4, //460800 !? B31250! 62 0, //921600 !? 63 }; 64 65 // 8MHz clock on serial3 and 4 on the BeBox 66 #if 0 67 static const uint32 sBeBoxRates[] = { 68 0, //B0 69 //... TODO 70 }; 71 #endif 72 73 // XXX: should really be generated from metadata (CSV ?) 74 75 static const struct serial_support_descriptor sSupportedDevices[] = { 76 77 #ifdef HANDLE_ISA_COM 78 // ISA devices 79 { B_ISA_BUS, "Generic 16550 Serial Port", sDefaultRates, NULL, { 8, 8, 8 }, 80 { PCI_simple_communications, PCI_serial, PCI_serial_16550 } }, 81 #endif 82 // PCI devices 83 84 // vendor/device matches first 85 86 /* 87 // vendor: OxfordSemi 88 #define VN "OxfordSemi" 89 { B_PCI_BUS, "OxfordSemi 16950 Serial Port", sDefaultRates, NULL, { 32, 32, 8 }, 90 { PCI_simple_communications, PCI_serial, PCI_serial_16950, 91 0x1415, 0x9501, PCI_INVAL, PCI_INVAL } }, 92 */ 93 94 95 // vendor: NetMos 96 #define VN "MosChip" 97 98 // used in Manhattan cards 99 // 1 function / port 100 // http://www.moschip.com/data/products/MCS9865/Data%20Sheet_9865.pdf 101 { B_PCI_BUS, VN" 16550 Serial Port", sDefaultRates, NULL, { 8, 8, 8, 0, 0, 0 }, 102 { PCI_simple_communications, PCI_serial, PCI_serial_16550, 103 0x9710, 0x9865, PCI_INVAL, PCI_INVAL } }, 104 105 // single function with all ports 106 // only BAR 0 & 1 are UART 107 // http://www.moschip.com/data/products/NM9835/Data%20Sheet_9835.pdf 108 { B_PCI_BUS, VN" 16550 Serial Port", sDefaultRates, NULL, { 8, 8, 8, ~0x3, 2, 0x000f }, 109 { PCI_simple_communications, PCI_serial, PCI_serial_16550, 110 0x9710, 0x9835, PCI_INVAL, PCI_INVAL } }, 111 112 #undef VN 113 114 115 116 // generic fallback matches 117 /* 118 { B_PCI_BUS, "Generic XT Serial Port", NULL }, 119 { PCI_INVAL, PCI_INVAL, PCI_simple_communications, 120 PCI_serial, PCI_serial_xt, PCI_INVAL, PCI_INVAL } }, 121 122 { B_PCI_BUS, "Generic 16450 Serial Port", NULL }, 123 { PCI_INVAL, PCI_INVAL, PCI_simple_communications, 124 PCI_serial, PCI_serial_16450, PCI_INVAL, PCI_INVAL } }, 125 126 */ 127 { B_PCI_BUS, "Generic 16550 Serial Port", sDefaultRates, NULL, { 8, 8, 8 }, 128 { PCI_simple_communications, PCI_serial, PCI_serial_16550, 129 PCI_INVAL, PCI_INVAL, PCI_INVAL, PCI_INVAL } }, 130 131 { B_PCI_BUS, "Generic 16650 Serial Port", sDefaultRates, NULL, { 8, 8, 8 }, 132 { PCI_simple_communications, PCI_serial, PCI_serial_16650, 133 PCI_INVAL, PCI_INVAL, PCI_INVAL, PCI_INVAL } }, 134 135 { B_PCI_BUS, "Generic 16750 Serial Port", sDefaultRates, NULL, { 8, 8, 8 }, 136 { PCI_simple_communications, PCI_serial, PCI_serial_16750, 137 PCI_INVAL, PCI_INVAL, PCI_INVAL, PCI_INVAL } }, 138 139 { B_PCI_BUS, "Generic 16850 Serial Port", sDefaultRates, NULL, { 8, 8, 8 }, 140 { PCI_simple_communications, PCI_serial, PCI_serial_16850, 141 PCI_INVAL, PCI_INVAL, PCI_INVAL, PCI_INVAL } }, 142 143 { B_PCI_BUS, "Generic 16950 Serial Port", sDefaultRates, NULL, { 8, 8, 8 }, 144 { PCI_simple_communications, PCI_serial, PCI_serial_16950, 145 PCI_INVAL, PCI_INVAL, PCI_INVAL, PCI_INVAL } }, 146 147 // non PCI_serial devices 148 149 // beos zz driver supported that one 150 { B_PCI_BUS, "Lucent Modem", sDefaultRates, NULL, { 8, 8, 8 }, 151 { PCI_simple_communications, PCI_simple_communications_other, 0x00, 152 0x11C1, 0x0480, PCI_INVAL, PCI_INVAL } }, 153 154 { B_PCI_BUS, NULL, NULL, NULL, {0}, {0} } 155 }; 156 157 158 #if 0 159 status_t 160 pc_serial_device_added(pc_device device, void **cookie) 161 { 162 TRACE_FUNCALLS("> pc_serial_device_added(0x%08x, 0x%08x)\n", device, cookie); 163 164 status_t status = B_OK; 165 const pc_device_descriptor *descriptor 166 = gUSBModule->get_device_descriptor(device); 167 168 TRACE_ALWAYS("probing device: 0x%04x/0x%04x\n", descriptor->vendor_id, 169 descriptor->product_id); 170 171 *cookie = NULL; 172 SerialDevice *serialDevice = SerialDevice::MakeDevice(device, 173 descriptor->vendor_id, descriptor->product_id); 174 175 const pc_configuration_info *configuration 176 = gUSBModule->get_nth_configuration(device, 0); 177 178 if (!configuration) 179 return B_ERROR; 180 181 status = serialDevice->AddDevice(configuration); 182 if (status < B_OK) { 183 delete serialDevice; 184 return status; 185 } 186 187 acquire_sem(gDriverLock); 188 for (int32 i = 0; i < DEVICES_COUNT; i++) { 189 if (gSerialDevices[i] != NULL) 190 continue; 191 192 status = serialDevice->Init(); 193 if (status < B_OK) { 194 delete serialDevice; 195 return status; 196 } 197 198 gSerialDevices[i] = serialDevice; 199 *cookie = serialDevice; 200 201 release_sem(gDriverLock); 202 TRACE_ALWAYS("%s (0x%04x/0x%04x) added\n", serialDevice->Description(), 203 descriptor->vendor_id, descriptor->product_id); 204 return B_OK; 205 } 206 207 release_sem(gDriverLock); 208 return B_ERROR; 209 } 210 211 212 status_t 213 pc_serial_device_removed(void *cookie) 214 { 215 TRACE_FUNCALLS("> pc_serial_device_removed(0x%08x)\n", cookie); 216 217 acquire_sem(gDriverLock); 218 219 SerialDevice *device = (SerialDevice *)cookie; 220 for (int32 i = 0; i < DEVICES_COUNT; i++) { 221 if (gSerialDevices[i] == device) { 222 if (device->IsOpen()) { 223 // the device will be deleted upon being freed 224 device->Removed(); 225 } else { 226 delete device; 227 gSerialDevices[i] = NULL; 228 } 229 break; 230 } 231 } 232 233 release_sem(gDriverLock); 234 TRACE_FUNCRET("< pc_serial_device_removed() returns\n"); 235 return B_OK; 236 } 237 #endif 238 239 //#pragma mark - 240 241 status_t 242 pc_serial_insert_device(SerialDevice *device) 243 { 244 status_t status = B_OK; 245 246 //XXX fix leaks! 247 acquire_sem(gDriverLock); 248 for (int32 i = 0; i < DEVICES_COUNT; i++) { 249 if (gSerialDevices[i] != NULL) 250 continue; 251 252 status = device->Init(); 253 if (status < B_OK) { 254 delete device; 255 //return status; 256 break; 257 } 258 259 gSerialDevices[i] = device; 260 261 release_sem(gDriverLock); 262 TRACE_ALWAYS("%s added\n", device->Description()); 263 return B_OK; 264 } 265 266 release_sem(gDriverLock); 267 return B_ERROR; 268 } 269 270 271 // probe devices with config_manager 272 static status_t 273 scan_bus(bus_type bus) 274 { 275 const char *bus_name = "Unknown"; 276 uint64 cookie = 0; 277 //status_t status; 278 struct { 279 device_info di; 280 pci_info pi; 281 } big_info; 282 struct device_info &dinfo = big_info.di; 283 284 switch (bus) { 285 case B_ISA_BUS: 286 bus_name = "ISA"; 287 break; 288 case B_PCI_BUS: 289 bus_name = "PCI"; 290 break; 291 case B_PCMCIA_BUS: 292 default: 293 return EINVAL; 294 } 295 TRACE_ALWAYS("scanning %s bus...\n", bus_name); 296 297 //XXX: clean up this mess 298 299 while ((gConfigManagerModule->get_next_device_info(bus, 300 &cookie, &big_info.di, sizeof(big_info)) == B_OK)) { 301 // skip disabled devices 302 if ((dinfo.flags & B_DEVICE_INFO_ENABLED) == 0) 303 continue; 304 // skip non configured devices 305 if ((dinfo.flags & B_DEVICE_INFO_CONFIGURED) == 0) 306 continue; 307 // and devices in error 308 if (dinfo.config_status < B_OK) 309 continue; 310 311 312 /* 313 TRACE_ALWAYS("device: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", 314 dinfo.id[0], dinfo.id[1], dinfo.id[2], dinfo.id[3]); 315 */ 316 317 /* 318 if (bus == B_PCI_BUS) { 319 pci_info *pcii = (pci_info *)(((char *)&dinfo) + 320 dinfo.bus_dependent_info_offset); 321 TRACE_ALWAYS("pci: %04x:%04x\n", 322 pcii->vendor_id, pcii->device_id); 323 if ((pcii->header_type & PCI_header_type_mask) == 324 PCI_header_type_generic) { 325 TRACE_ALWAYS("subsys: %04x:%04x\n", 326 pcii->u.h0.subsystem_vendor_id, pcii->u.h0.subsystem_id); 327 } 328 } 329 */ 330 331 const struct serial_support_descriptor *supported = NULL; 332 for (int i = 0; sSupportedDevices[i].name; i++) { 333 if (sSupportedDevices[i].bus != bus) 334 continue; 335 if (sSupportedDevices[i].match.class_base != PCI_undefined && 336 sSupportedDevices[i].match.class_base != dinfo.devtype.base) 337 continue; 338 if (sSupportedDevices[i].match.class_sub != PCI_undefined && 339 sSupportedDevices[i].match.class_sub != dinfo.devtype.subtype) 340 continue; 341 if (sSupportedDevices[i].match.class_api != PCI_undefined && 342 sSupportedDevices[i].match.class_api != dinfo.devtype.interface) 343 continue; 344 345 #if 0 346 // either this way 347 if (bus == B_PCI_BUS) { 348 pci_info *pcii = (pci_info *)(((char *)&dinfo) + 349 dinfo.bus_dependent_info_offset); 350 if (sSupportedDevices[i].match.vendor_id != PCI_INVAL && 351 sSupportedDevices[i].match.vendor_id != pcii->vendor_id) 352 continue; 353 if (sSupportedDevices[i].match.device_id != PCI_INVAL && 354 sSupportedDevices[i].match.device_id != pcii->device_id) 355 continue; 356 } 357 #endif 358 // or this one: 359 // .id[0] = vendor_id and .id[1] = device_id 360 // .id[3?] = subsys_vendor_id and .id[2?] = subsys_device_id 361 if (bus == B_PCI_BUS && 362 sSupportedDevices[i].match.vendor_id != PCI_INVAL && 363 sSupportedDevices[i].match.vendor_id != dinfo.id[0]) 364 continue; 365 366 if (bus == B_PCI_BUS && 367 sSupportedDevices[i].match.device_id != PCI_INVAL && 368 sSupportedDevices[i].match.device_id != dinfo.id[1]) 369 continue; 370 371 372 supported = &sSupportedDevices[i]; 373 break; 374 } 375 if (supported == NULL) 376 continue; 377 378 struct { 379 struct device_configuration c; 380 resource_descriptor res[16]; 381 } config; 382 if (gConfigManagerModule->get_size_of_current_configuration_for( 383 cookie) > (int)sizeof(config)) { 384 TRACE_ALWAYS("config size too big for device\n"); 385 continue; 386 } 387 388 if (gConfigManagerModule->get_current_configuration_for(cookie, 389 &config.c, sizeof(config)) < B_OK) { 390 TRACE_ALWAYS("can't get config for device\n"); 391 continue; 392 393 } 394 395 TRACE_ALWAYS("device %Ld resources: %d irq %d dma %d io %d mem\n", 396 cookie, 397 gConfigManagerModule->count_resource_descriptors_of_type( 398 &config.c, B_IRQ_RESOURCE), 399 gConfigManagerModule->count_resource_descriptors_of_type( 400 &config.c, B_DMA_RESOURCE), 401 gConfigManagerModule->count_resource_descriptors_of_type( 402 &config.c, B_IO_PORT_RESOURCE), 403 gConfigManagerModule->count_resource_descriptors_of_type( 404 &config.c, B_MEMORY_RESOURCE)); 405 406 407 // we first need the IRQ 408 resource_descriptor irqdesc; 409 if (gConfigManagerModule->get_nth_resource_descriptor_of_type( 410 &config.c, 0, B_IRQ_RESOURCE, &irqdesc, sizeof(irqdesc)) < B_OK) { 411 TRACE_ALWAYS("can't find IRQ for device\n"); 412 continue; 413 } 414 int irq; 415 // XXX: what about APIC lines ? 416 for (irq = 0; irq < 32; irq++) { 417 if (irqdesc.d.m.mask & (1 << irq)) 418 break; 419 } 420 //TRACE_ALWAYS("irq %d\n", irq); 421 //TRACE_ALWAYS("irq: %lx,%lx,%lx\n", irqdesc.d.m.mask, irqdesc.d.m.flags, irqdesc.d.m.cookie); 422 423 TRACE_ALWAYS("found %s device %Ld [%x|%x|%x] " 424 /*"ID: '%16.16s'"*/" irq: %d flags: %08lx status: %s\n", 425 bus_name, cookie, dinfo.devtype.base, dinfo.devtype.subtype, 426 dinfo.devtype.interface, /*dinfo.id,*/ irq, dinfo.flags, 427 strerror(dinfo.config_status)); 428 429 // force enable I/O ports on PCI devices 430 #if 0 431 if (bus == B_PCI_BUS) { 432 pci_info *pcii = (pci_info *)(((char *)&dinfo) + 433 dinfo.bus_dependent_info_offset); 434 435 uint32 cmd = gPCIModule->read_pci_config(pcii->bus, pcii->device, 436 pcii->function, PCI_command, 2); 437 TRACE_ALWAYS("PCI_command: 0x%04lx\n", cmd); 438 cmd |= PCI_command_io; 439 gPCIModule->write_pci_config(pcii->bus, pcii->device, 440 pcii->function, PCI_command, 2, cmd); 441 } 442 #endif 443 444 resource_descriptor iodesc; 445 SerialDevice *master = NULL; 446 447 //TODO: handle maxports 448 //TODO: handle subsystem_id_mask 449 450 // instanciate devices on IO ports 451 for (int i = 0; 452 gConfigManagerModule->get_nth_resource_descriptor_of_type( 453 &config.c, i, B_IO_PORT_RESOURCE, &iodesc, sizeof(iodesc)) == B_OK; 454 i++) { 455 TRACE_ALWAYS("io at 0x%04lx len 0x%04lx\n", iodesc.d.r.minbase, 456 iodesc.d.r.len); 457 458 if (iodesc.d.r.len < supported->constraints.minsize) 459 continue; 460 if (iodesc.d.r.len > supported->constraints.maxsize) 461 continue; 462 SerialDevice *device; 463 uint32 ioport = iodesc.d.r.minbase; 464 next_split: 465 // no more to split 466 if ((ioport - iodesc.d.r.minbase) >= iodesc.d.r.len) 467 continue; 468 469 TRACE_ALWAYS("inserting device at io 0x%04lx as %s\n", ioport, 470 supported->name); 471 472 473 #ifdef __HAIKU__ 474 device = new(std::nothrow) SerialDevice(supported, ioport, irq, master); 475 #else 476 device = new SerialDevice(supported, ioport, irq, master); 477 #endif 478 if (pc_serial_insert_device(device) < B_OK) { 479 TRACE_ALWAYS("can't insert device\n"); 480 continue; 481 } 482 if (master == NULL) 483 master = device; 484 485 ioport += supported->constraints.split; 486 goto next_split; 487 // try next part of the I/O range now 488 } 489 // we have at least one device 490 if (master) { 491 // hook up the irq 492 #if 0 493 status = install_io_interrupt_handler(irq, pc_serial_interrupt, 494 master, 0); 495 TRACE_ALWAYS("installing irq %d handler: %s\n", irq, strerror(status)); 496 #endif 497 } 498 } 499 return B_OK; 500 } 501 502 // this version doesn't use config_manager, but can't probe the IRQ yet 503 status_t 504 scan_pci_alt() 505 { 506 pci_info info; 507 int ix; 508 TRACE_ALWAYS("scanning PCI bus (alt)...\n"); 509 510 // probe PCI devices 511 for (ix = 0; (*gPCIModule->get_nth_pci_info)(ix, &info) == B_OK; ix++) { 512 // sanity check 513 if ((info.header_type & PCI_header_type_mask) != PCI_header_type_generic) 514 continue; 515 /* 516 TRACE_ALWAYS("probing PCI device %2d [%x|%x|%x] %04x:%04x\n", 517 ix, info.class_base, info.class_sub, info.class_api, 518 info.vendor_id, info.device_id); 519 */ 520 521 const struct serial_support_descriptor *supported = NULL; 522 for (int i = 0; sSupportedDevices[i].name; i++) { 523 if (sSupportedDevices[i].bus != B_PCI_BUS) 524 continue; 525 if (info.class_base != sSupportedDevices[i].match.class_base) 526 continue; 527 if (info.class_sub != sSupportedDevices[i].match.class_sub) 528 continue; 529 if (info.class_api != sSupportedDevices[i].match.class_api) 530 continue; 531 if (sSupportedDevices[i].match.vendor_id != PCI_INVAL 532 && info.vendor_id != sSupportedDevices[i].match.vendor_id) 533 continue; 534 if (sSupportedDevices[i].match.device_id != PCI_INVAL 535 && info.device_id != sSupportedDevices[i].match.device_id) 536 continue; 537 supported = &sSupportedDevices[i]; 538 break; 539 } 540 if (supported == NULL) 541 continue; 542 543 TRACE_ALWAYS("found PCI device %2d [%x|%x|%x] %04x:%04x as %s\n", 544 ix, info.class_base, info.class_sub, info.class_api, 545 info.vendor_id, info.device_id, supported->name); 546 547 // XXX: interrupt_line doesn't seem to 548 TRACE_ALWAYS("irq line %d, pin %d\n", 549 info.u.h0.interrupt_line, info.u.h0.interrupt_pin); 550 int irq = info.u.h0.interrupt_line; 551 552 SerialDevice *master = NULL; 553 554 uint8 portCount = 0; 555 uint32 maxPorts = DEVICES_COUNT; 556 557 if (supported->constraints.maxports) { 558 maxPorts = supported->constraints.maxports; 559 TRACE_ALWAYS("card supports up to %d ports\n", maxPorts); 560 } 561 if (supported->constraints.subsystem_id_mask) { 562 uint32 id = info.u.h0.subsystem_id; 563 uint32 mask = supported->constraints.subsystem_id_mask; 564 id &= mask; 565 //TRACE_ALWAYS("mask: %lx, masked: %lx\n", mask, id); 566 while (!(mask & 0x1)) { 567 mask >>= 1; 568 id >>= 1; 569 } 570 maxPorts = (uint8)id; 571 TRACE_ALWAYS("subsystem id tells card has %d ports\n", maxPorts); 572 } 573 574 // find I/O ports 575 for (int r = 0; r < 6; r++) { 576 uint32 regbase = info.u.h0.base_registers[r]; 577 uint32 reglen = info.u.h0.base_register_sizes[r]; 578 579 /**/ 580 TRACE("ranges[%d] at 0x%08lx len 0x%lx flags 0x%02x\n", r, 581 regbase, reglen, info.u.h0.base_register_flags[r]); 582 /**/ 583 584 // empty 585 if (reglen == 0) 586 continue; 587 588 // not I/O 589 if ((info.u.h0.base_register_flags[r] & PCI_address_space) == 0) 590 continue; 591 592 // the range for sure doesn't contain any UART 593 if (supported->constraints.ignoremask & (1 << r)) { 594 TRACE_ALWAYS("ignored regs at 0x%08lx len 0x%lx\n", 595 regbase, reglen); 596 continue; 597 } 598 599 TRACE_ALWAYS("regs at 0x%08lx len 0x%lx\n", 600 regbase, reglen); 601 //&PCI_address_io_mask 602 603 if (reglen < supported->constraints.minsize) 604 continue; 605 if (reglen > supported->constraints.maxsize) 606 continue; 607 608 SerialDevice *device; 609 uint32 ioport = regbase; 610 next_split_alt: 611 // no more to split 612 if ((ioport - regbase) >= reglen) 613 continue; 614 615 if (portCount >= maxPorts) 616 break; 617 618 TRACE_ALWAYS("inserting device at io 0x%04lx as %s\n", ioport, 619 supported->name); 620 621 622 /**/ 623 #ifdef __HAIKU__ 624 device = new(std::nothrow) SerialDevice(supported, ioport, irq, master); 625 #else 626 device = new SerialDevice(supported, ioport, irq, master); 627 #endif 628 if (pc_serial_insert_device(device) < B_OK) { 629 TRACE_ALWAYS("can't insert device\n"); 630 continue; 631 } 632 /**/ if (master == NULL) 633 master = device; 634 635 ioport += supported->constraints.split; 636 portCount++; 637 goto next_split_alt; 638 // try next part of the I/O range now 639 640 } 641 } 642 643 return B_OK; 644 } 645 646 647 //#pragma mark - 648 649 650 /* init_hardware - called once the first time the driver is loaded */ 651 status_t 652 init_hardware() 653 { 654 TRACE("init_hardware\n"); 655 return B_OK; 656 } 657 658 659 /* init_driver - called every time the driver is loaded. */ 660 status_t 661 init_driver() 662 { 663 status_t status; 664 load_settings(); 665 create_log_file(); 666 667 TRACE_FUNCALLS("> init_driver()\n"); 668 669 status = get_module(B_TTY_MODULE_NAME, (module_info **)&gTTYModule); 670 if (status < B_OK) 671 goto err_tty; 672 673 #ifndef __HAIKU__ 674 // due to BONE having a different function count and ordering, 675 // but the same version, to avoid crashing we detect it at runtime. 676 { 677 static tty_module_info_v1_bone sTTYModuleBONE; 678 static tty_module_info_v1_r5 *ttyModuleR5 = 679 (tty_module_info_v1_r5 *)gTTYModule; 680 image_info info; 681 int32 cookie = 0; 682 while (get_next_image_info(/*B_KERNEL_TEAM*/1, &cookie, &info) == B_OK) { 683 //dprintf(DRIVER_NAME ": checking image %32s\n", info.name); 684 if ((char *)(gTTYModule->ttyopen) >= (char *)info.text 685 && (char *)(gTTYModule->ttyopen) < ((char *)info.text + info.text_size)) { 686 void *symbol; 687 dprintf(DRIVER_NAME ": detected tty module %32s\n", info.name); 688 if (get_image_symbol(info.id, "ttydeselect", 689 B_SYMBOL_TYPE_ANY, &symbol) != B_OK) { 690 dprintf(DRIVER_NAME ": no ttydeselect() in tty module, assuming R5\n"); 691 // let's fake a BONE module with NULL select hooks 692 memcpy(&sTTYModuleBONE.mi, &ttyModuleR5->mi, sizeof(ttyModuleR5->mi)); 693 sTTYModuleBONE.ttyopen = ttyModuleR5->ttyopen; 694 sTTYModuleBONE.ttyclose = ttyModuleR5->ttyclose; 695 sTTYModuleBONE.ttyfree = ttyModuleR5->ttyfree; 696 sTTYModuleBONE.ttyread = ttyModuleR5->ttyread; 697 sTTYModuleBONE.ttywrite = ttyModuleR5->ttywrite; 698 sTTYModuleBONE.ttycontrol = ttyModuleR5->ttycontrol; 699 sTTYModuleBONE.ttyinit = ttyModuleR5->ttyinit; 700 sTTYModuleBONE.ttyilock = ttyModuleR5->ttyilock; 701 sTTYModuleBONE.ttyhwsignal = ttyModuleR5->ttyhwsignal; 702 sTTYModuleBONE.ttyin = ttyModuleR5->ttyin; 703 sTTYModuleBONE.ttyout = ttyModuleR5->ttyout; 704 sTTYModuleBONE.ddrstart = ttyModuleR5->ddrstart; 705 sTTYModuleBONE.ddrdone = ttyModuleR5->ddrdone; 706 sTTYModuleBONE.ddacquire = ttyModuleR5->ddacquire; 707 // no select hooks 708 sTTYModuleBONE.ttyselect = NULL; 709 sTTYModuleBONE.ttydeselect = NULL; 710 711 gTTYModule = &sTTYModuleBONE; 712 } 713 break; 714 } 715 } 716 } 717 #endif 718 719 status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCIModule); 720 if (status < B_OK) 721 goto err_pci; 722 723 status = get_module(B_ISA_MODULE_NAME, (module_info **)&gISAModule); 724 if (status < B_OK) 725 goto err_isa; 726 727 status = get_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME, 728 (module_info **)&gConfigManagerModule); 729 if (status < B_OK) 730 goto err_cm; 731 732 for (int32 i = 0; i < DEVICES_COUNT; i++) 733 gSerialDevices[i] = NULL; 734 735 gDeviceNames[0] = NULL; 736 737 gDriverLock = create_sem(1, DRIVER_NAME"_devices_table_lock"); 738 if (gDriverLock < B_OK) { 739 status = gDriverLock; 740 goto err_sem; 741 } 742 743 status = ENOENT; 744 745 #ifdef __BEOS__ 746 memset(&gSerialDomain, 0, sizeof(gSerialDomain)); 747 ddbackground(&gSerialDomain); 748 #endif 749 750 scan_bus(B_ISA_BUS); 751 //scan_bus(B_PCI_BUS); 752 scan_pci_alt(); 753 754 // XXX: ISA cards 755 // XXX: pcmcia 756 757 758 TRACE_FUNCRET("< init_driver() returns\n"); 759 return B_OK; 760 761 //err_none: 762 delete_sem(gDriverLock); 763 err_sem: 764 put_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME); 765 err_cm: 766 put_module(B_ISA_MODULE_NAME); 767 err_isa: 768 put_module(B_PCI_MODULE_NAME); 769 err_pci: 770 put_module(B_TTY_MODULE_NAME); 771 err_tty: 772 TRACE_FUNCRET("< init_driver() returns %s\n", strerror(status)); 773 return status; 774 } 775 776 777 /* uninit_driver - called every time the driver is unloaded */ 778 void 779 uninit_driver() 780 { 781 TRACE_FUNCALLS("> uninit_driver()\n"); 782 783 //gUSBModule->uninstall_notify(DRIVER_NAME); 784 acquire_sem(gDriverLock); 785 786 for (int32 i = 0; i < DEVICES_COUNT; i++) { 787 if (gSerialDevices[i]) { 788 /* 789 if (gSerialDevices[i]->Master() == gSerialDevices[i]) 790 remove_io_interrupt_handler(gSerialDevices[i]->IRQ(), 791 pc_serial_interrupt, gSerialDevices[i]); 792 */ 793 delete gSerialDevices[i]; 794 gSerialDevices[i] = NULL; 795 } 796 } 797 798 for (int32 i = 0; gDeviceNames[i]; i++) 799 free(gDeviceNames[i]); 800 801 delete_sem(gDriverLock); 802 put_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME); 803 put_module(B_ISA_MODULE_NAME); 804 put_module(B_PCI_MODULE_NAME); 805 put_module(B_TTY_MODULE_NAME); 806 807 TRACE_FUNCRET("< uninit_driver() returns\n"); 808 } 809 810 811 #ifdef __HAIKU__ 812 bool 813 pc_serial_service(struct tty *tty, uint32 op, void *buffer, size_t length) 814 { 815 TRACE_FUNCALLS("> pc_serial_service(%p, 0x%08lx, %p, %lu)\n", tty, 816 op, buffer, length); 817 818 819 for (int32 i = 0; i < DEVICES_COUNT; i++) { 820 if (gSerialDevices[i] 821 && gSerialDevices[i]->Service(tty, op, buffer, length)) { 822 TRACE_FUNCRET("< pc_serial_service() returns: true\n"); 823 return true; 824 } 825 } 826 827 TRACE_FUNCRET("< pc_serial_service() returns: false\n"); 828 return false; 829 } 830 #else /* __HAIKU__ */ 831 bool 832 pc_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags) 833 { 834 TRACE_FUNCALLS("> pc_serial_service(0x%08x, 0x%08x, 0x%08x)\n", ptty, ddr, flags); 835 836 for (int32 i = 0; i < DEVICES_COUNT; i++) { 837 if (gSerialDevices[i] && gSerialDevices[i]->Service(ptty, ddr, flags)) { 838 TRACE_FUNCRET("< pc_serial_service() returns: true\n"); 839 return true; 840 } 841 } 842 843 TRACE_FUNCRET("< pc_serial_service() returns: false\n"); 844 return false; 845 } 846 #endif /* __HAIKU__ */ 847 848 849 int32 850 pc_serial_interrupt(void *arg) 851 { 852 int32 ret; 853 SerialDevice *master = (SerialDevice *)arg; 854 TRACE_FUNCALLS("> pc_serial_interrupt(%p)\n", arg); 855 856 if (!master) 857 return B_UNHANDLED_INTERRUPT; 858 859 ret = master->InterruptHandler(); 860 return ret; 861 862 863 for (int32 i = 0; i < DEVICES_COUNT; i++) { 864 if (gSerialDevices[i] && gSerialDevices[i]->Master() == master) { 865 ret = gSerialDevices[i]->InterruptHandler(); 866 // XXX: handle more than 1 ? 867 if (ret != B_UNHANDLED_INTERRUPT) { 868 TRACE_FUNCRET("< pc_serial_interrupt() returns: true\n"); 869 return ret; 870 } 871 } 872 } 873 874 TRACE_FUNCRET("< pc_serial_interrupt() returns: unhandled\n"); 875 return B_UNHANDLED_INTERRUPT; 876 } 877 878 879 /* pc_serial_open - handle open() calls */ 880 status_t 881 pc_serial_open(const char *name, uint32 flags, void **cookie) 882 { 883 TRACE_FUNCALLS("> pc_serial_open(%s, 0x%08x, 0x%08x)\n", name, flags, cookie); 884 acquire_sem(gDriverLock); 885 status_t status = ENODEV; 886 887 *cookie = NULL; 888 int i = strtol(name + strlen(sDeviceBaseName), NULL, 10); 889 if (i >= 0 && i < DEVICES_COUNT && gSerialDevices[i]) { 890 status = gSerialDevices[i]->Open(flags); 891 *cookie = gSerialDevices[i]; 892 } 893 894 release_sem(gDriverLock); 895 TRACE_FUNCRET("< pc_serial_open() returns: 0x%08x\n", status); 896 return status; 897 } 898 899 900 /* pc_serial_read - handle read() calls */ 901 status_t 902 pc_serial_read(void *cookie, off_t position, void *buffer, size_t *numBytes) 903 { 904 TRACE_FUNCALLS("> pc_serial_read(0x%08x, %Ld, 0x%08x, %d)\n", cookie, 905 position, buffer, *numBytes); 906 SerialDevice *device = (SerialDevice *)cookie; 907 return device->Read((char *)buffer, numBytes); 908 } 909 910 911 /* pc_serial_write - handle write() calls */ 912 status_t 913 pc_serial_write(void *cookie, off_t position, const void *buffer, 914 size_t *numBytes) 915 { 916 TRACE_FUNCALLS("> pc_serial_write(0x%08x, %Ld, 0x%08x, %d)\n", cookie, 917 position, buffer, *numBytes); 918 SerialDevice *device = (SerialDevice *)cookie; 919 return device->Write((const char *)buffer, numBytes); 920 } 921 922 923 /* pc_serial_control - handle ioctl calls */ 924 status_t 925 pc_serial_control(void *cookie, uint32 op, void *arg, size_t length) 926 { 927 TRACE_FUNCALLS("> pc_serial_control(0x%08x, 0x%08x, 0x%08x, %d)\n", 928 cookie, op, arg, length); 929 SerialDevice *device = (SerialDevice *)cookie; 930 return device->Control(op, arg, length); 931 } 932 933 934 #if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__) 935 /* pc_serial_select - handle select start */ 936 status_t 937 pc_serial_select(void *cookie, uint8 event, uint32 ref, selectsync *sync) 938 { 939 TRACE_FUNCALLS("> pc_serial_select(0x%08x, 0x%08x, 0x%08x, %p)\n", 940 cookie, event, ref, sync); 941 SerialDevice *device = (SerialDevice *)cookie; 942 return device->Select(event, ref, sync); 943 } 944 945 946 /* pc_serial_deselect - handle select exit */ 947 status_t 948 pc_serial_deselect(void *cookie, uint8 event, selectsync *sync) 949 { 950 TRACE_FUNCALLS("> pc_serial_deselect(0x%08x, 0x%08x, %p)\n", 951 cookie, event, sync); 952 SerialDevice *device = (SerialDevice *)cookie; 953 return device->DeSelect(event, sync); 954 } 955 #endif // DANO, HAIKU 956 957 958 /* pc_serial_close - handle close() calls */ 959 status_t 960 pc_serial_close(void *cookie) 961 { 962 TRACE_FUNCALLS("> pc_serial_close(0x%08x)\n", cookie); 963 SerialDevice *device = (SerialDevice *)cookie; 964 return device->Close(); 965 } 966 967 968 /* pc_serial_free - called after last device is closed, and all i/o complete. */ 969 status_t 970 pc_serial_free(void *cookie) 971 { 972 TRACE_FUNCALLS("> pc_serial_free(0x%08x)\n", cookie); 973 SerialDevice *device = (SerialDevice *)cookie; 974 acquire_sem(gDriverLock); 975 status_t status = device->Free(); 976 if (device->IsRemoved()) { 977 for (int32 i = 0; i < DEVICES_COUNT; i++) { 978 if (gSerialDevices[i] == device) { 979 // the device is removed already but as it was open the 980 // removed hook has not deleted the object 981 delete device; 982 gSerialDevices[i] = NULL; 983 break; 984 } 985 } 986 } 987 988 release_sem(gDriverLock); 989 return status; 990 } 991 992 993 /* publish_devices - null-terminated array of devices supported by this driver. */ 994 const char ** 995 publish_devices() 996 { 997 TRACE_FUNCALLS("> publish_devices()\n"); 998 for (int32 i = 0; gDeviceNames[i]; i++) 999 free(gDeviceNames[i]); 1000 1001 int32 j = 0; 1002 acquire_sem(gDriverLock); 1003 for(int32 i = 0; i < DEVICES_COUNT; i++) { 1004 if (gSerialDevices[i]) { 1005 gDeviceNames[j] = (char *)malloc(strlen(sDeviceBaseName) + 4); 1006 if (gDeviceNames[j]) { 1007 sprintf(gDeviceNames[j], "%s%ld", sDeviceBaseName, i); 1008 j++; 1009 } else 1010 TRACE_ALWAYS("publish_devices - no memory to allocate device names\n"); 1011 } 1012 } 1013 1014 gDeviceNames[j] = NULL; 1015 release_sem(gDriverLock); 1016 return (const char **)&gDeviceNames[0]; 1017 } 1018 1019 1020 /* find_device - return poiter to device hooks structure for a given device */ 1021 device_hooks * 1022 find_device(const char *name) 1023 { 1024 static device_hooks deviceHooks = { 1025 pc_serial_open, /* -> open entry point */ 1026 pc_serial_close, /* -> close entry point */ 1027 pc_serial_free, /* -> free cookie */ 1028 pc_serial_control, /* -> control entry point */ 1029 pc_serial_read, /* -> read entry point */ 1030 pc_serial_write, /* -> write entry point */ 1031 #if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__) 1032 pc_serial_select, /* -> select entry point */ 1033 pc_serial_deselect /* -> deselect entry point */ 1034 #endif 1035 }; 1036 1037 TRACE_FUNCALLS("> find_device(%s)\n", name); 1038 return &deviceHooks; 1039 } 1040