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