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