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