From bbc84914d4e340a18214a1a92b17deb03254169b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Fri, 27 Feb 2009 00:15:20 +0000 Subject: [PATCH] Working version of the driver. At least it does seem to work with my onboard com port, but not the OxfordSemi PCI card I have here. Still requires tty_manager, and config_manager too, so won't work in Haiku yet. Needs cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29328 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/ports/pc_serial/Driver.cpp | 520 +++++++++++++++++- .../kernel/drivers/ports/pc_serial/Driver.h | 96 +++- .../kernel/drivers/ports/pc_serial/NOTES.txt | 6 + .../drivers/ports/pc_serial/SerialDevice.cpp | 377 ++++++++++--- .../drivers/ports/pc_serial/SerialDevice.h | 62 ++- .../drivers/ports/pc_serial/Tracing.cpp | 1 - .../kernel/drivers/ports/pc_serial/Tracing.h | 6 +- .../kernel/drivers/ports/pc_serial/UART.h | 99 ++++ .../drivers/ports/pc_serial/pci_serial.txt | 36 ++ .../drivers/ports/pc_serial/poke_16C952.lst | 45 ++ 10 files changed, 1107 insertions(+), 141 deletions(-) create mode 100644 src/add-ons/kernel/drivers/ports/pc_serial/UART.h create mode 100644 src/add-ons/kernel/drivers/ports/pc_serial/pci_serial.txt create mode 100644 src/add-ons/kernel/drivers/ports/pc_serial/poke_16C952.lst diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp index 51304fa250..7625cd34d8 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp @@ -14,15 +14,113 @@ #include "Driver.h" #include "SerialDevice.h" -static const char *sDeviceBaseName = "ports/serial"; +int32 api_version = B_CUR_DRIVER_API_VERSION; +static const char *sDeviceBaseName = DEVFS_BASE; SerialDevice *gSerialDevices[DEVICES_COUNT]; char *gDeviceNames[DEVICES_COUNT + 1]; -usb_module_info *gUSBModule = NULL; +config_manager_for_driver_module_info *gConfigManagerModule = NULL; +isa_module_info *gISAModule = NULL; +pci_module_info *gPCIModule = NULL; tty_module_info *gTTYModule = NULL; struct ddomain gSerialDomain; sem_id gDriverLock = -1; +// 24 MHz clock +static const uint32 sDefaultRates[] = { + 0, //B0 + 2304, //B50 + 1536, //B75 + 1047, //B110 + 857, //B134 + 768, //B150 + 512, //B200 + 384, //B300 + 192, //B600 + 0, //B1200 + 0, //B1800 + 48, //B2400 + 24, //B4800 + 12, //B9600 + 6, //B19200 + 3, //B38400 + 2, //B57600 + 1, //B115200 + 0, //B230400 + 4, //460800 !? B31250! + 0, //921600 !? +}; +// 8MHz clock on serial3 and 4 on the BeBox +#if 0 +static const uint32 sBeBoxRates[] = { + 0, //B0 + //... +}; +#endif + +static const struct serial_support_descriptor sSupportedDevices[] = { + +#ifdef HANDLE_ISA_COM + // ISA devices + { B_ISA_BUS, "Generic 16550 Serial Port", sDefaultRates, NULL, { 8, 8, 8 }, + { PCI_simple_communications, PCI_serial, PCI_serial_16550 } }, +#endif + // PCI devices + + // vendor/device matches first + +/* + { B_PCI_BUS, "OxfordSemi 16950 Serial Port", sDefaultRates, NULL, { 32, 32, 8 }, + { PCI_simple_communications, PCI_serial, PCI_serial_16950, + 0x1415, 0x9501 } }, +*/ + // generic fallback matches + /* + { B_PCI_BUS, "Generic XT Serial Port", NULL }, + { PCI_INVAL, PCI_INVAL, PCI_simple_communications, + PCI_serial, PCI_serial_xt } }, + + { B_PCI_BUS, "Generic 16450 Serial Port", NULL }, + { PCI_INVAL, PCI_INVAL, PCI_simple_communications, + PCI_serial, PCI_serial_16450 } }, + + */ + { B_PCI_BUS, "Generic 16550 Serial Port", sDefaultRates, NULL, { 8, 8, 8 }, + { PCI_simple_communications, PCI_serial, PCI_serial_16550, + PCI_INVAL, PCI_INVAL } }, + +//XXX + + { B_PCI_BUS, "Generic 16950 Serial Port", sDefaultRates, NULL, { 8, 8, 8 }, + { PCI_simple_communications, PCI_serial, PCI_serial_16950, + PCI_INVAL, PCI_INVAL } }, + +//XXX DEBUG! HACK HACK HACK +//XXX for testing probing +#if 0 + { B_PCI_BUS, "My BadIDE controller", sDefaultRates, NULL, { 8, 32, 8 }, + { 1, 1, 0x8a, + 0x1002, 0x434a } }, + { B_PCI_BUS, "My GoodIDE controller", sDefaultRates, NULL, { 8, 32, 8 }, + { 1, 1, 0x8a, + 0x1002, 0x4349 } }, + { B_PCI_BUS, "My IDE controller", sDefaultRates, NULL, { 8, 32, 8 }, + { 1, 1, 0x8a, + PCI_INVAL, PCI_INVAL } }, +#endif + + // non PCI_serial devices + + // beos zz driver supported that one + { B_PCI_BUS, "Lucent Modem", sDefaultRates, NULL, { 8, 8, 8 }, + { PCI_simple_communications, PCI_simple_communications_other, 0x00, + 0x11C1, 0x0480 } }, + + { B_PCI_BUS, NULL, NULL, NULL, {0}, {0} } +}; + + +#if 0 status_t pc_serial_device_added(pc_device device, void **cookie) { @@ -101,6 +199,323 @@ pc_serial_device_removed(void *cookie) TRACE_FUNCRET("< pc_serial_device_removed() returns\n"); return B_OK; } +#endif + +//#pragma mark - + +status_t +pc_serial_insert_device(SerialDevice *device) +{ + status_t status = B_OK; + + //XXX fix leaks! + acquire_sem(gDriverLock); + for (int32 i = 0; i < DEVICES_COUNT; i++) { + if (gSerialDevices[i] != NULL) + continue; + + status = device->Init(); + if (status < B_OK) { + delete device; + //return status; + break; + } + + gSerialDevices[i] = device; + + release_sem(gDriverLock); + TRACE_ALWAYS("%s added\n", device->Description()); + return B_OK; + } + + release_sem(gDriverLock); + return B_ERROR; +} + + +// probe devices with config_manager +static status_t +scan_bus(bus_type bus) +{ + const char *bus_name = "Unknown"; + uint64 cookie = 0; + status_t status; + struct { + device_info di; + pci_info pi; + } big_info; + struct device_info &dinfo = big_info.di; + + switch (bus) { + case B_ISA_BUS: + bus_name = "ISA"; + break; + case B_PCI_BUS: + bus_name = "PCI"; + break; + case B_PCMCIA_BUS: + default: + return EINVAL; + } + TRACE_ALWAYS("scanning %s bus...\n", bus_name); + +//XXX: clean up this mess + + while ((gConfigManagerModule->get_next_device_info(bus, + &cookie, &big_info.di, sizeof(big_info)) == B_OK)) { + // skip disabled devices + if (dinfo.flags & B_DEVICE_INFO_ENABLED == 0) + continue; + // skip non configured devices + if (dinfo.flags & B_DEVICE_INFO_CONFIGURED == 0) + continue; + // and devices in error + if (dinfo.config_status < B_OK) + continue; + + + /* + TRACE_ALWAYS("device: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", + dinfo.id[0], dinfo.id[1], dinfo.id[2], dinfo.id[3]); + */ + + /* + if (bus == B_PCI_BUS) { + pci_info *pcii = (pci_info *)(((char *)&dinfo) + + dinfo.bus_dependent_info_offset); + TRACE_ALWAYS("pci: %04x:%04x\n", + pcii->vendor_id, pcii->device_id); + if ((pcii->header_type & PCI_header_type_mask) == + PCI_header_type_generic) { + TRACE_ALWAYS("subsys: %04x:%04x\n", + pcii->u.h0.subsystem_vendor_id, pcii->u.h0.subsystem_id); + } + } + */ + + const struct serial_support_descriptor *supported = NULL; + for (int i = 0; sSupportedDevices[i].name; i++) { + if (sSupportedDevices[i].bus != bus) + continue; + if (sSupportedDevices[i].match.class_base != PCI_undefined && + sSupportedDevices[i].match.class_base != dinfo.devtype.base) + continue; + if (sSupportedDevices[i].match.class_sub != PCI_undefined && + sSupportedDevices[i].match.class_sub != dinfo.devtype.subtype) + continue; + if (sSupportedDevices[i].match.class_api != PCI_undefined && + sSupportedDevices[i].match.class_api != dinfo.devtype.interface) + continue; + +#if 0 + // either this way + if (bus == B_PCI_BUS) { + pci_info *pcii = (pci_info *)(((char *)&dinfo) + + dinfo.bus_dependent_info_offset); + if (sSupportedDevices[i].match.vendor_id != PCI_INVAL && + sSupportedDevices[i].match.vendor_id != pcii->vendor_id) + continue; + if (sSupportedDevices[i].match.device_id != PCI_INVAL && + sSupportedDevices[i].match.device_id != pcii->device_id) + continue; + } +#endif + // or this one: + // .id[0] = vendor_id and .id[1] = device_id + // .id[3?] = subsys_vendor_id and .id[2?] = subsys_device_id + if (bus == B_PCI_BUS && + sSupportedDevices[i].match.vendor_id != PCI_INVAL && + sSupportedDevices[i].match.vendor_id != dinfo.id[0]) + continue; + + if (bus == B_PCI_BUS && + sSupportedDevices[i].match.device_id != PCI_INVAL && + sSupportedDevices[i].match.device_id != dinfo.id[1]) + continue; + + + supported = &sSupportedDevices[i]; + break; + } + if (supported == NULL) + continue; + + struct { + struct device_configuration c; + resource_descriptor res[16]; + } config; + if (gConfigManagerModule->get_size_of_current_configuration_for( + cookie) > sizeof(config)) { + TRACE_ALWAYS("config size too big for device\n"); + continue; + } + + if (gConfigManagerModule->get_current_configuration_for(cookie, + &config.c, sizeof(config)) < B_OK) { + TRACE_ALWAYS("can't get config for device\n"); + continue; + + } + + TRACE_ALWAYS("device %Ld resources: %d irq %d dma %d io %d mem\n", + cookie, + gConfigManagerModule->count_resource_descriptors_of_type( + &config.c, B_IRQ_RESOURCE), + gConfigManagerModule->count_resource_descriptors_of_type( + &config.c, B_DMA_RESOURCE), + gConfigManagerModule->count_resource_descriptors_of_type( + &config.c, B_IO_PORT_RESOURCE), + gConfigManagerModule->count_resource_descriptors_of_type( + &config.c, B_MEMORY_RESOURCE)); + + + // we first need the IRQ + resource_descriptor irqdesc; + if (gConfigManagerModule->get_nth_resource_descriptor_of_type( + &config.c, 0, B_IRQ_RESOURCE, &irqdesc, sizeof(irqdesc)) < B_OK) { + TRACE_ALWAYS("can't find IRQ for device\n"); + continue; + } + int irq; + // XXX: what about APIC lines ? + for (irq = 0; irq < 32; irq++) { + if (irqdesc.d.m.mask & (1 << irq)) + break; + } + TRACE_ALWAYS("irq %d\n", irq); + //TRACE_ALWAYS("irq: %lx,%lx,%lx\n", irqdesc.d.m.mask, irqdesc.d.m.flags, irqdesc.d.m.cookie); + + TRACE_ALWAYS("found %s device %Ld [%x|%x|%x] " + /*"ID: '%16.16s'"*/" flags: %08lx status: %s\n", + bus_name, cookie, dinfo.devtype.base, dinfo.devtype.subtype, + dinfo.devtype.interface, /*dinfo.id,*/ dinfo.flags, + strerror(dinfo.config_status)); + + // force enable I/O ports on PCI devices +#if 0 + if (bus == B_PCI_BUS) { + pci_info *pcii = (pci_info *)(((char *)&dinfo) + + dinfo.bus_dependent_info_offset); + + uint32 cmd = gPCIModule->read_pci_config(pcii->bus, pcii->device, + pcii->function, PCI_command, 2); + TRACE_ALWAYS("PCI_command: 0x%04lx\n", cmd); + cmd |= PCI_command_io; + gPCIModule->write_pci_config(pcii->bus, pcii->device, + pcii->function, PCI_command, 2, cmd); + } +#endif + + // instanciate devices on IO ports + resource_descriptor iodesc; + SerialDevice *master = NULL; + for (int i = 0; + gConfigManagerModule->get_nth_resource_descriptor_of_type( + &config.c, i, B_IO_PORT_RESOURCE, &iodesc, sizeof(iodesc)) == B_OK; + i++) { + TRACE_ALWAYS("io at 0x%04lx len 0x%04lx\n", iodesc.d.r.minbase, + iodesc.d.r.len); + + if (iodesc.d.r.len < supported->constraints.minsize) + continue; + if (iodesc.d.r.len > supported->constraints.maxsize) + continue; + SerialDevice *device; + uint32 ioport = iodesc.d.r.minbase; +next_split: + // no more to split + if ((ioport - iodesc.d.r.minbase) >= iodesc.d.r.len) + continue; + + TRACE_ALWAYS("inserting device at io 0x%04lx as %s\n", ioport, + supported->name); + + + device = new SerialDevice(supported, ioport, irq, master); + if (pc_serial_insert_device(device) < B_OK) { + TRACE_ALWAYS("can't insert device\n"); + continue; + } + if (master == NULL) + master = device; + + ioport += supported->constraints.split; + goto next_split; + // try next part of the I/O range now + } + // we have at least one device + if (master) { + // hook up the irq +#if 0 + status = install_io_interrupt_handler(irq, pc_serial_interrupt, + master, 0); + TRACE_ALWAYS("installing irq %d handler: %s\n", irq, strerror(status)); +#endif + } + } +} + +// this version doesn't use config_manager, but can't probe the IRQ yet +status_t +scan_pci_alt() +{ + pci_info info; + int ix; + // probe PCI devices + for (ix = 0; (*gPCIModule->get_nth_pci_info)(ix, &info) == B_OK; ix++) { + // sanity check + if (info.header_type & PCI_header_type_mask != PCI_header_type_generic) + continue; + TRACE_ALWAYS("probing PCI device %2d [%x|%x|%x] %04x:%04x\n", + ix, info.class_base, info.class_sub, info.class_api, + info.vendor_id, info.device_id); + + const struct serial_support_descriptor *supported = NULL; + for (int i = 0; sSupportedDevices[i].name; i++) { + if (sSupportedDevices[i].bus != B_PCI_BUS) + continue; + if (info.class_base != sSupportedDevices[i].match.class_base) + continue; + if (info.class_sub != sSupportedDevices[i].match.class_sub) + continue; + if (info.class_api != sSupportedDevices[i].match.class_api) + continue; + if (sSupportedDevices[i].match.vendor_id != PCI_INVAL + && info.vendor_id != sSupportedDevices[i].match.vendor_id) + continue; + if (sSupportedDevices[i].match.device_id != PCI_INVAL + && info.device_id != sSupportedDevices[i].match.device_id) + continue; + supported = &sSupportedDevices[i]; + } + if (supported == NULL) + continue; + + TRACE_ALWAYS("found PCI device %2d [%x|%x|%x] %04x:%04x as %s\n", + ix, info.class_base, info.class_sub, info.class_api, + info.vendor_id, info.device_id, supported->name); + + // find I/O ports + for (int r = 0; r < 6; r++) { + TRACE_ALWAYS("range at 0x%08lx len 0x%lx flags 0x%02x\n", + info.u.h0.base_registers[r], info.u.h0.base_register_sizes[r], + info.u.h0.base_register_flags[r]); + + // not I/O + if (info.u.h0.base_register_flags[r] & PCI_address_space == 0) + continue; + // + TRACE_ALWAYS("regs at 0x%08lx len 0x%lx\n", + info.u.h0.base_registers[r], info.u.h0.base_register_sizes[r]); + //&PCI_address_io_mask + } + // XXX: interrupt_line doesn't seem to + TRACE_ALWAYS("irq line %d, pin %d\n", + info.u.h0.interrupt_line, info.u.h0.interrupt_pin); + } + + return B_OK; +} //#pragma mark - @@ -119,20 +534,28 @@ init_hardware() status_t init_driver() { + status_t status; load_settings(); create_log_file(); TRACE_FUNCALLS("> init_driver()\n"); - status_t status = get_module(B_TTY_MODULE_NAME, (module_info **)&gTTYModule); + status = get_module(B_TTY_MODULE_NAME, (module_info **)&gTTYModule); if (status < B_OK) - return status; + goto err_tty; - status = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule); - if (status < B_OK) { - put_module(B_TTY_MODULE_NAME); - return status; - } + status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCIModule); + if (status < B_OK) + goto err_pci; + + status = get_module(B_ISA_MODULE_NAME, (module_info **)&gISAModule); + if (status < B_OK) + goto err_isa; + + status = get_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME, + (module_info **)&gConfigManagerModule); + if (status < B_OK) + goto err_cm; for (int32 i = 0; i < DEVICES_COUNT; i++) gSerialDevices[i] = NULL; @@ -141,20 +564,40 @@ init_driver() gDriverLock = create_sem(1, DRIVER_NAME"_devices_table_lock"); if (gDriverLock < B_OK) { - put_module(B_USB_MODULE_NAME); - put_module(B_TTY_MODULE_NAME); - return gDriverLock; + status = gDriverLock; + goto err_sem; } - static pc_notify_hooks notifyHooks = { - &pc_serial_device_added, - &pc_serial_device_removed - }; + status = ENOENT; - gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL); - gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); + memset(&gSerialDomain, 0, sizeof(gSerialDomain)); + ddbackground(&gSerialDomain); + + + scan_bus(B_ISA_BUS); + scan_bus(B_PCI_BUS); + + + // XXX: ISA cards + // XXX: pcmcia + + TRACE_FUNCRET("< init_driver() returns\n"); return B_OK; + +err_none: + delete_sem(gDriverLock); +err_sem: + put_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME); +err_cm: + put_module(B_ISA_MODULE_NAME); +err_isa: + put_module(B_PCI_MODULE_NAME); +err_pci: + put_module(B_TTY_MODULE_NAME); +err_tty: + TRACE_FUNCRET("< init_driver() returns %s\n", strerror(status)); + return status; } @@ -164,11 +607,16 @@ uninit_driver() { TRACE_FUNCALLS("> uninit_driver()\n"); - gUSBModule->uninstall_notify(DRIVER_NAME); + //gUSBModule->uninstall_notify(DRIVER_NAME); acquire_sem(gDriverLock); for (int32 i = 0; i < DEVICES_COUNT; i++) { if (gSerialDevices[i]) { + /* + if (gSerialDevices[i]->Master() == gSerialDevices[i]) + remove_io_interrupt_handler(gSerialDevices[i]->IRQ(), + pc_serial_interrupt, gSerialDevices[i]); + */ delete gSerialDevices[i]; gSerialDevices[i] = NULL; } @@ -178,7 +626,9 @@ uninit_driver() free(gDeviceNames[i]); delete_sem(gDriverLock); - put_module(B_USB_MODULE_NAME); + put_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME); + put_module(B_ISA_MODULE_NAME); + put_module(B_PCI_MODULE_NAME); put_module(B_TTY_MODULE_NAME); TRACE_FUNCRET("< uninit_driver() returns\n"); @@ -202,6 +652,36 @@ pc_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags) } +int32 +pc_serial_interrupt(void *arg) +{ + int32 ret; + SerialDevice *master = (SerialDevice *)arg; + TRACE_FUNCALLS("> pc_serial_interrupt(%p)\n", arg); + + if (!master) + return B_UNHANDLED_INTERRUPT; + + ret = master->InterruptHandler(); + return ret; + + + for (int32 i = 0; i < DEVICES_COUNT; i++) { + if (gSerialDevices[i] && gSerialDevices[i]->Master() == master) { + ret = gSerialDevices[i]->InterruptHandler(); + // XXX: handle more than 1 ? + if (ret != B_UNHANDLED_INTERRUPT) { + TRACE_FUNCRET("< pc_serial_interrupt() returns: true\n"); + return ret; + } + } + } + + TRACE_FUNCRET("< pc_serial_interrupt() returns: unhandled\n"); + return B_UNHANDLED_INTERRUPT; +} + + /* pc_serial_open - handle open() calls */ static status_t pc_serial_open(const char *name, uint32 flags, void **cookie) diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.h b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.h index 54ca07d199..e4395cf353 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.h +++ b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.h @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include #ifdef __HAIKU__ @@ -25,9 +28,71 @@ extern "C" { #include } + +// whether we should handle default COM ports +#define HANDLE_ISA_COM + #define DRIVER_NAME "pc_serial" // driver name for debug output #define DEVICES_COUNT 20 // max simultaneously open devices +#ifdef HANDLE_ISA_COM +#define DEVFS_BASE "ports/my_serial" +#else +// avoid clashing with BeOS zz driver +#define DEVFS_BASE "ports/pc_serial" +#endif + + +// no user serviceable part beyond this point + +// more PCI serial APIs +#ifndef PCI_serial_16650 +#define PCI_serial_16650 0x03 /* 16650-compatible serial controller */ +#define PCI_serial_16750 0x04 /* 16750-compatible serial controller */ +#define PCI_serial_16850 0x05 /* 16850-compatible serial controller */ +#define PCI_serial_16950 0x06 /* 16950-compatible serial controller */ +#endif + +class SerialDevice; + +struct port_constraints { + uint32 minsize; + uint32 maxsize; + uint32 split; // range to split I/O ports for each device +}; + +#define PCI_INVAL 0xffff +struct serial_support_descriptor { + bus_type bus; // B_*_BUS + const char *name; + const uint32 *bauds; + // not yet used + SerialDevice *(*instanciator)(struct serial_support_descriptor *desc); + // I/O port constrains (which ranges to use, how to split them) + struct port_constraints constraints; + // bus specific stuff here... + struct { + // for both ISA & PCI + uchar class_base; + uchar class_sub; + uchar class_api; // or PCI_undefined + // for PCI: if PCI_INVAL then match class + ushort vendor_id; + ushort device_id; + } match; +}; +typedef struct serial_support_descriptor serial_support_descriptor; + + +struct serial_config_descriptor { + bus_type bus; // B_*_BUS + struct serial_support_descriptor *descriptor; + union { + struct pci_info pci; + } d; +}; + + /* Some usefull helper defines ... */ #define SIZEOF(array) (sizeof(array) / sizeof(array[0])) /* size of array */ /* This one rounds the size to integral count of segs (segments) */ @@ -35,6 +100,9 @@ extern "C" { /* Default device buffer size */ #define DEF_BUFFER_SIZE 0x200 +// XXX: sort up the mess in termios.h on B* ! +#define BLAST B230400 + /* line coding defines ... Come from CDC USB specs? */ #define LC_STOP_BIT_1 0 #define LC_STOP_BIT_2 2 @@ -55,42 +123,18 @@ typedef struct pc_serial_line_coding_s { #define CLS_LINE_DTR 0x0001 #define CLS_LINE_RTS 0x0002 -/* attributes etc ...*/ -#ifndef USB_EP_ADDR_DIR_IN -#define USB_EP_ADDR_DIR_IN 0x80 -#define USB_EP_ADDR_DIR_OUT 0x00 -#endif - -#ifndef USB_EP_ATTR_CONTROL -#define USB_EP_ATTR_CONTROL 0x00 -#define USB_EP_ATTR_ISOCHRONOUS 0x01 -#define USB_EP_ATTR_BULK 0x02 -#define USB_EP_ATTR_INTERRUPT 0x03 -#endif - -/* USB class - communication devices */ -#define USB_DEV_CLASS_COMM 0x02 -#define USB_INT_CLASS_CDC 0x02 -#define USB_INT_SUBCLASS_ACM 0x02 -#define USB_INT_CLASS_CDC_DATA 0x0a -#define USB_INT_SUBCLASS_DATA 0x00 - -// communication device subtypes -#define FUNCTIONAL_SUBTYPE_UNION 0x06 - +extern config_manager_for_driver_module_info *gConfigManagerModule; extern isa_module_info *gISAModule; extern pci_module_info *gPCIModule; extern tty_module_info *gTTYModule; extern struct ddomain gSerialDomain; extern "C" { -status_t pc_serial_device_added(pc_device device, void **cookie); -status_t pc_serial_device_removed(void *cookie); - status_t init_hardware(); void uninit_driver(); bool pc_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags); +int32 pc_serial_interrupt(void *arg); status_t pc_serial_open(const char *name, uint32 flags, void **cookie); status_t pc_serial_read(void *cookie, off_t position, void *buffer, size_t *numBytes); diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/NOTES.txt b/src/add-ons/kernel/drivers/ports/pc_serial/NOTES.txt index 08cc2aa72e..0afeb9c4e1 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/NOTES.txt +++ b/src/add-ons/kernel/drivers/ports/pc_serial/NOTES.txt @@ -1,4 +1,10 @@ references: http://www.beyondlogic.org/serial/serial.htm +http://jamesthornton.com/freebsd/articles/serial-uart/ +http://dugeem.net/david/work/freebsd-serial.html +http://dugeem.net/david/work/etc/sio.c + +if you can understand it: +http://lxr.linux.no/linux+v2.6.28.7/drivers/serial/ diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp index ccd520a465..5a8f33c456 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp @@ -6,24 +6,23 @@ * Distributed under the terms of the MIT License. */ #include "SerialDevice.h" -#include "USB3.h" +#include "UART.h" -#include "ACM.h" -#include "FTDI.h" -#include "KLSI.h" -#include "Prolific.h" - -SerialDevice::SerialDevice(usb_device device, uint16 vendorID, - uint16 productID, const char *description) - : fDevice(device), - fVendorID(vendorID), - fProductID(productID), - fDescription(description), +SerialDevice::SerialDevice(const struct serial_support_descriptor *device, + uint32 ioBase, uint32 irq, const SerialDevice *master) + : /*fSupportDescriptor(device->descriptor), + fDevice(device), + fDescription(device->descriptor->name),*/ + fSupportDescriptor(device), + fDevice(NULL), + fDescription(device->name), + // fDeviceOpen(false), fDeviceRemoved(false), - fControlPipe(0), - fReadPipe(0), - fWritePipe(0), + fBus(device->bus), + fIOBase(ioBase), + fIRQ(irq), + fMaster(master), fBufferArea(-1), fReadBuffer(NULL), fReadBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)), @@ -40,6 +39,7 @@ SerialDevice::SerialDevice(usb_device device, uint16 vendorID, { memset(&fTTYFile, 0, sizeof(ttyfile)); memset(&fTTY, 0, sizeof(tty)); + memset(&fRover, 0, sizeof(ddrover)); } @@ -75,38 +75,79 @@ SerialDevice::Init() fWriteBuffer = fReadBuffer + fReadBufferSize; fInterruptBuffer = fWriteBuffer + fWriteBufferSize; + + // disable DLAB + WriteReg8(LCR, 0); + return B_OK; } -void -SerialDevice::SetControlPipe(usb_pipe handle) -{ - fControlPipe = handle; -} - - -void -SerialDevice::SetReadPipe(usb_pipe handle) -{ - fReadPipe = handle; -} - - -void -SerialDevice::SetWritePipe(usb_pipe handle) -{ - fWritePipe = handle; -} - - void SerialDevice::SetModes() { struct termios tios; memcpy(&tios, &fTTY.t, sizeof(struct termios)); + //TRACE_FUNCRES(trace_termios, &tios); + spin(10000); + uint32 baudIndex = tios.c_cflag & CBAUD; + if (baudIndex > BLAST) + baudIndex = BLAST; + + uint8 lcr = 0; + uint16 divisor = SupportDescriptor()->bauds[baudIndex]; + + switch (tios.c_cflag & CSIZE) { +#if CS5 != CS7 + // in case someday... + case CS5: + lcr |= LCR_5BIT; + break; + case CS6: + lcr |= LCR_6BIT; + break; +#endif + case CS7: + lcr |= LCR_7BIT; + break; + case CS8: + default: + lcr |= LCR_8BIT; + break; + } + + if (tios.c_cflag & CSTOPB) + lcr |= LCR_2STOP; + if (tios.c_cflag & PARENB) + lcr |= LCR_P_EN; + if (tios.c_cflag & PARODD == 0) + lcr |= LCR_P_EVEN; + + if (baudIndex == B0) { + // disable + MaskReg8(MCR, MCR_DTR); + } else { + // set FCR now, + // 16650 and later chips have another reg at 2 when DLAB=1 + uint8 fcr = FCR_ENABLE | FCR_RX_RST | FCR_TX_RST | FCR_F_8; + // enable fifo + //fcr = 0; + WriteReg8(FCR, fcr); + + // unmask the divisor latch regs + WriteReg8(LCR, LCR_DLAB); + // set divisor + WriteReg8(DLLB, divisor & 0x00ff); + WriteReg8(DLHB, divisor >> 8); + //WriteReg8(2,0); + + } + // set control lines, and disable divisor latch reg + WriteReg8(LCR, lcr); + + +#if 0 uint16 newControl = fControlOut; - TRACE_FUNCRES(trace_termios, &tios); static uint32 baudRates[] = { 0x00000000, //B0 @@ -132,11 +173,6 @@ SerialDevice::SetModes() 0x000E1000, //921600 }; - uint32 baudCount = sizeof(baudRates) / sizeof(baudRates[0]); - uint32 baudIndex = tios.c_cflag & CBAUD; - if (baudIndex > baudCount) - baudIndex = baudCount - 1; - usb_serial_line_coding lineCoding; lineCoding.speed = baudRates[baudIndex]; lineCoding.stopbits = (tios.c_cflag & CSTOPB) ? LC_STOP_BIT_2 : LC_STOP_BIT_1; @@ -172,64 +208,103 @@ SerialDevice::SetModes() fLineCoding.parity); SetLineCoding(&fLineCoding); } +#endif } bool SerialDevice::Service(struct tty *ptty, struct ddrover *ddr, uint flags) { + uint8 msr; + status_t err; + if (&fTTY != ptty) return false; + TRACE_ALWAYS("%s(,,0x%08lx)\n", __FUNCTION__, flags); + if (flags <= TTYGETSIGNALS) { switch (flags) { case TTYENABLE: TRACE("TTYENABLE\n"); - gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false); - gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true); - fControlOut = CLS_LINE_DTR | CLS_LINE_RTS; - SetControlLineState(fControlOut); + + SetModes(); + err = install_io_interrupt_handler(IRQ(), pc_serial_interrupt, this, 0); + TRACE_ALWAYS("installing irq handler for %d: %s\n", IRQ(), strerror(err)); + msr = ReadReg8(MSR); + gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, msr & MSR_DCD); + gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, msr & MSR_CTS); + // + WriteReg8(MCR, MCR_DTR | MCR_RTS | MCR_IRQ_EN /*| MCR_LOOP*//*XXXXXXX*/); + // enable irqs + WriteReg8(IER, IER_RLS | IER_MS | IER_RDA); + //WriteReg8(IER, IER_RDA); break; case TTYDISABLE: TRACE("TTYDISABLE\n"); - gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false); - fControlOut = 0x0; - SetControlLineState(fControlOut); + // remove the handler + remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this); + // disable IRQ + WriteReg8(IER, 0); + WriteReg8(MCR, 0); + msr = ReadReg8(MSR); + gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, msr & MSR_DCD); break; case TTYISTOP: TRACE("TTYISTOP\n"); - fInputStopped = true; - gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false); + MaskReg8(MCR, MCR_RTS); + //fInputStopped = true; + //gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false); break; case TTYIRESUME: TRACE("TTYIRESUME\n"); - gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true); - fInputStopped = false; + OrReg8(MCR, MCR_RTS); + //gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true); + //fInputStopped = false; break; case TTYGETSIGNALS: TRACE("TTYGETSIGNALS\n"); - gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, true); - gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true); - gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDSR, false); - gTTYModule->ttyhwsignal(ptty, ddr, TTYHWRI, false); + msr = ReadReg8(MSR); + gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, msr & MSR_DCD); + gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, msr & MSR_CTS); + gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDSR, msr & MSR_DSR); + gTTYModule->ttyhwsignal(ptty, ddr, TTYHWRI, msr & MSR_RI); break; case TTYSETMODES: TRACE("TTYSETMODES\n"); SetModes(); +//WriteReg8(IER, IER_RLS | IER_MS | IER_RDA); break; case TTYOSTART: + TRACE("TTYOSTART\n"); + // enable irqs + WriteReg8(IER, IER_RLS | IER_MS | IER_RDA | IER_THRE); + break; case TTYOSYNC: + TRACE("TTYOSYNC\n"); + return (ReadReg8(LSR) & (LSR_THRE | LSR_TSRE)) == (LSR_THRE | LSR_TSRE); + break; case TTYSETBREAK: + TRACE("TTYSETBREAK\n"); + OrReg8(LCR, LCR_BREAK); + break; case TTYCLRBREAK: + TRACE("TTYCLRBREAK\n"); + MaskReg8(LCR, LCR_BREAK); + break; case TTYSETDTR: + TRACE("TTYSETDTR\n"); + OrReg8(MCR, MCR_DTR); + break; case TTYCLRDTR: - TRACE("TTY other\n"); + TRACE("TTYCLRDTR\n"); + MaskReg8(MCR, MCR_DTR); break; } @@ -240,6 +315,86 @@ SerialDevice::Service(struct tty *ptty, struct ddrover *ddr, uint flags) } +int32 +SerialDevice::InterruptHandler() +{ + int32 ret = B_UNHANDLED_INTERRUPT; + gTTYModule->ddrstart(&fRover); + gTTYModule->ttyilock(&fTTY, &fRover, true); + + uint8 iir, lsr, msr; + int count; + + while (((iir = ReadReg8(IIR)) & IIR_PENDING) == 0) { // 0 means yes + int fifoavail = 1; + + //DEBUG +// for (count = 0; ReadReg8(LSR) & LSR_DR; count++) +// gTTYModule->ttyin(&fTTY, &fRover, ReadReg8(RBR)); + + switch (iir & (IIR_IMASK | IIR_TO)) { + case IIR_THRE: + dprintf("IIR_THRE\n"); + // check how much fifo we can use + //XXX: move to Init() ? + if (iir & IIR_FMASK == IIR_FMASK) + fifoavail = 16; + if (iir & IIR_F64EN) + fifoavail = 64; + for (int i = 0; i < fifoavail; i++) { + int chr = gTTYModule->ttyout(&fTTY, &fRover); + if (chr < 0) { + //WriteReg8(THB, (uint8)chr); + break; + } + WriteReg8(THB, (uint8)chr); + } + break; + case IIR_TO: + case IIR_TO | IIR_RDA: + // timeout: FALLTHROUGH + case IIR_RDA: + dprintf("IIR_TO/RDA\n"); + // while data is ready... get it + while (ReadReg8(LSR) & LSR_DR) + gTTYModule->ttyin(&fTTY, &fRover, ReadReg8(RBR)); + break; + case IIR_RLS: + dprintf("IIR_RLS\n"); + // ack + lsr = ReadReg8(LSR); + //XXX: handle this somehow + break; + case IIR_MS: + dprintf("IIR_MS\n"); + // modem signals changed + msr = ReadReg8(MSR); + if (msr & MSR_DDCD) + gTTYModule->ttyhwsignal(&fTTY, &fRover, TTYHWDCD, msr & MSR_DCD); + if (msr & MSR_DCTS) + gTTYModule->ttyhwsignal(&fTTY, &fRover, TTYHWCTS, msr & MSR_CTS); + if (msr & MSR_DDSR) + gTTYModule->ttyhwsignal(&fTTY, &fRover, TTYHWDSR, msr & MSR_DSR); + if (msr & MSR_TERI) + gTTYModule->ttyhwsignal(&fTTY, &fRover, TTYHWRI, msr & MSR_RI); + break; + default: + dprintf("IIR_?\n"); + // something happened + break; + } + ret = B_HANDLED_INTERRUPT; + dprintf("IRQ:h\n"); + } + + + gTTYModule->ttyilock(&fTTY, &fRover, false); + gTTYModule->ddrdone(&fRover); + dprintf("IRQ:r\n"); + return ret; +} + + status_t SerialDevice::Open(uint32 flags) { @@ -249,7 +404,7 @@ SerialDevice::Open(uint32 flags) if (fDeviceRemoved) return B_DEV_NOT_READY; - gTTYModule->ttyinit(&fTTY, true); + gTTYModule->ttyinit(&fTTY, false); fTTYFile.tty = &fTTY; fTTYFile.flags = flags; ResetDevice(); @@ -259,7 +414,7 @@ SerialDevice::Open(uint32 flags) return B_NO_MEMORY; gTTYModule->ddacquire(ddr, &gSerialDomain); - status_t status = gTTYModule->ttyopen(&fTTYFile, ddr, usb_serial_service); + status_t status = gTTYModule->ttyopen(&fTTYFile, ddr, pc_serial_service); gTTYModule->ddrdone(ddr); if (status < B_OK) { @@ -267,6 +422,7 @@ SerialDevice::Open(uint32 flags) return status; } +#if 0 fDeviceThread = spawn_kernel_thread(DeviceThread, "usb_serial device thread", B_NORMAL_PRIORITY, this); @@ -285,6 +441,7 @@ SerialDevice::Open(uint32 flags) if (status < B_OK) TRACE_ALWAYS("failed to queue initial interrupt\n"); +#endif fDeviceOpen = true; return B_OK; } @@ -298,24 +455,31 @@ SerialDevice::Read(char *buffer, size_t *numBytes) return B_DEV_NOT_READY; } + status_t status; +#if 0 status_t status = mutex_lock(&fReadLock); if (status != B_OK) { TRACE_ALWAYS("read: failed to get read lock\n"); *numBytes = 0; return status; } +#endif struct ddrover *ddr = gTTYModule->ddrstart(NULL); if (!ddr) { *numBytes = 0; +#if 0 mutex_unlock(&fReadLock); +#endif return B_NO_MEMORY; } status = gTTYModule->ttyread(&fTTYFile, ddr, buffer, numBytes); gTTYModule->ddrdone(ddr); +#if 0 mutex_unlock(&fReadLock); +#endif return status; } @@ -324,8 +488,19 @@ status_t SerialDevice::Write(const char *buffer, size_t *numBytes) { size_t bytesLeft = *numBytes; - *numBytes = 0; + //*numBytes = 0; + status_t status = EINVAL; + struct ddrover *ddr = gTTYModule->ddrstart(NULL); + if (!ddr) { + *numBytes = 0; + return B_ERROR; + } + + status = gTTYModule->ttywrite(&fTTYFile, ddr, buffer, numBytes); + gTTYModule->ddrdone(ddr); + +#if 0 status_t status = mutex_lock(&fWriteLock); if (status != B_OK) { TRACE_ALWAYS("write: failed to get write lock\n"); @@ -373,6 +548,7 @@ SerialDevice::Write(const char *buffer, size_t *numBytes) } mutex_unlock(&fWriteLock); +#endif return status; } @@ -431,9 +607,11 @@ SerialDevice::Close() OnClose(); if (!fDeviceRemoved) { +#if 0 gUSBModule->cancel_queued_transfers(fReadPipe); gUSBModule->cancel_queued_transfers(fWritePipe); gUSBModule->cancel_queued_transfers(fControlPipe); +#endif } struct ddrover *ddr = gTTYModule->ddrstart(NULL); @@ -473,12 +651,14 @@ SerialDevice::Removed() // we need to ensure that we do not use the device anymore fStopDeviceThread = true; fInputStopped = false; +#if 0 gUSBModule->cancel_queued_transfers(fReadPipe); gUSBModule->cancel_queued_transfers(fWritePipe); gUSBModule->cancel_queued_transfers(fControlPipe); +#endif int32 result = B_OK; - wait_for_thread(fDeviceThread, &result); + //wait_for_thread(fDeviceThread, &result); fDeviceThread = -1; mutex_lock(&fWriteLock); @@ -487,7 +667,7 @@ SerialDevice::Removed() status_t -SerialDevice::AddDevice(const usb_configuration_info *config) +SerialDevice::AddDevice(const serial_config_descriptor *config) { // default implementation - does nothing return B_ERROR; @@ -502,13 +682,14 @@ SerialDevice::ResetDevice() } +#if 0 status_t SerialDevice::SetLineCoding(usb_serial_line_coding *coding) { // default implementation - does nothing return B_OK; } - +#endif status_t SerialDevice::SetControlLineState(uint16 state) @@ -543,6 +724,7 @@ int32 SerialDevice::DeviceThread(void *data) { SerialDevice *device = (SerialDevice *)data; +#if 0 while (!device->fStopDeviceThread) { status_t status = gUSBModule->queue_bulk(device->fReadPipe, @@ -592,6 +774,7 @@ SerialDevice::DeviceThread(void *data) gTTYModule->ddrdone(ddr); } +#endif return B_OK; } @@ -638,14 +821,17 @@ SerialDevice::InterruptCallbackFunction(void *cookie, int32 status, // ToDo: maybe handle those somehow? if (status == B_OK && !device->fDeviceRemoved) { +#if 0 status = gUSBModule->queue_interrupt(device->fControlPipe, device->fInterruptBuffer, device->fInterruptBufferSize, device->InterruptCallbackFunction, device); +#endif } } +#if 0 SerialDevice * SerialDevice::MakeDevice(usb_device device, uint16 vendorID, uint16 productID) @@ -711,3 +897,66 @@ SerialDevice::MakeDevice(usb_device device, uint16 vendorID, return new ACMDevice(device, vendorID, productID, "CDC ACM compatible device"); } +#endif + + +uint8 +SerialDevice::ReadReg8(int reg) +{ + uint8 ret; + switch (fBus) { + case B_ISA_BUS: + ret = gISAModule->read_io_8(IOBase() + reg); + break; + case B_PCI_BUS: + ret = gPCIModule->read_io_8(IOBase() + reg); + break; + default: + TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__); + ret = 0; + //XXX:pcmcia ? + } + TRACE_ALWAYS("RR8(%d) = %d [%02x]\n", reg, ret, ret); + //spin(1000); + return ret; +} + +void +SerialDevice::WriteReg8(int reg, uint8 value) +{ +// TRACE_ALWAYS("WR8(0x%04x+%d, %d [0x%x])\n", IOBase(), reg, value, value); + TRACE_ALWAYS("WR8(%d, %d [0x%x])\n", reg, value, value); + switch (fBus) { + case B_ISA_BUS: + gISAModule->write_io_8(IOBase() + reg, value); + break; + case B_PCI_BUS: + gPCIModule->write_io_8(IOBase() + reg, value); + break; + default: + TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__); + //XXX:pcmcia ? + } + //spin(10000); +} + + +void +SerialDevice::OrReg8(int reg, uint8 value) +{ + WriteReg8(reg, ReadReg8(reg) | value); +} + + +void +SerialDevice::AndReg8(int reg, uint8 value) +{ + WriteReg8(reg, ReadReg8(reg) & value); +} + + +void +SerialDevice::MaskReg8(int reg, uint8 value) +{ + WriteReg8(reg, ReadReg8(reg) & ~value); +} diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h index 085102faf1..57cc422f17 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h @@ -12,29 +12,26 @@ class SerialDevice { public: - SerialDevice(usb_device device, - uint16 vendorID, uint16 productID, - const char *description); +/* SerialDevice(struct serial_config_descriptor + *device, uint32 ioBase, uint32 irq, SerialDevice *master=NULL);*/ + SerialDevice(const struct serial_support_descriptor + *device, uint32 ioBase, uint32 irq, const SerialDevice *master=NULL); virtual ~SerialDevice(); -static SerialDevice * MakeDevice(usb_device device, uint16 vendorID, - uint16 productID); +static SerialDevice * MakeDevice(struct serial_config_descriptor + *device); status_t Init(); - usb_device Device() { return fDevice; }; - uint16 ProductID() { return fProductID; }; - uint16 VendorID() { return fVendorID; }; - const char * Description() { return fDescription; }; + const struct serial_support_descriptor *SupportDescriptor() const + { return fSupportDescriptor; }; + struct serial_config_descriptor *ConfigDescriptor() const + { return fDevice; }; + //uint16 ProductID() const { return fProductID; }; + //uint16 VendorID() const { return fVendorID; }; + const char * Description() const { return fDescription; }; - void SetControlPipe(usb_pipe handle); - usb_pipe ControlPipe() { return fControlPipe; }; - - void SetReadPipe(usb_pipe handle); - usb_pipe ReadPipe() { return fReadPipe; }; - - void SetWritePipe(usb_pipe handle); - usb_pipe WritePipe() { return fWritePipe; } + const SerialDevice * Master() const { return fMaster ? fMaster : this; }; char * ReadBuffer() { return fReadBuffer; }; size_t ReadBufferSize() { return fReadBufferSize; }; @@ -46,6 +43,8 @@ static SerialDevice * MakeDevice(usb_device device, uint16 vendorID, bool Service(struct tty *ptty, struct ddrover *ddr, uint flags); + int32 InterruptHandler(); + status_t Open(uint32 flags); status_t Read(char *buffer, size_t *numBytes); status_t Write(const char *buffer, size_t *numBytes); @@ -60,11 +59,11 @@ static SerialDevice * MakeDevice(usb_device device, uint16 vendorID, bool IsRemoved() { return fDeviceRemoved; }; /* virtual interface to be overriden as necessary */ -virtual status_t AddDevice(const usb_configuration_info *config); +virtual status_t AddDevice(const struct serial_config_descriptor *device); virtual status_t ResetDevice(); -virtual status_t SetLineCoding(usb_serial_line_coding *coding); +//virtual status_t SetLineCoding(usb_serial_line_coding *coding); virtual status_t SetControlLineState(uint16 state); virtual void OnRead(char **buffer, size_t *numBytes); @@ -72,6 +71,9 @@ virtual void OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes); virtual void OnClose(); + uint32 IOBase() const { return fIOBase; }; + uint32 IRQ() const { return fIRQ; }; + protected: void SetReadBufferSize(size_t size) { fReadBufferSize = size; }; void SetWriteBufferSize(size_t size) { fWriteBufferSize = size; }; @@ -89,20 +91,25 @@ static void InterruptCallbackFunction(void *cookie, int32 status, void *data, uint32 actualLength); - usb_device fDevice; // USB device handle - uint16 fVendorID; - uint16 fProductID; + uint8 ReadReg8(int reg); + void WriteReg8(int reg, uint8 value); + void OrReg8(int reg, uint8 value); + void AndReg8(int reg, uint8 value); + void MaskReg8(int reg, uint8 value); + + const struct serial_support_descriptor *fSupportDescriptor; + struct serial_config_descriptor *fDevice; // USB device handle const char * fDescription; // informational description bool fDeviceOpen; bool fDeviceRemoved; - /* communication pipes */ - usb_pipe fControlPipe; - usb_pipe fReadPipe; - usb_pipe fWritePipe; + bus_type fBus; + uint32 fIOBase; + uint32 fIRQ; + const SerialDevice * fMaster; /* line coding */ - usb_serial_line_coding fLineCoding; + //usb_serial_line_coding fLineCoding; /* data buffers */ area_id fBufferArea; @@ -129,6 +136,7 @@ static void InterruptCallbackFunction(void *cookie, bool fInputStopped; struct ttyfile fTTYFile; struct tty fTTY; + struct ddrover fRover; /* device thread management */ thread_id fDeviceThread; diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.cpp index 993efb72e7..c2c47f7696 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.cpp @@ -7,7 +7,6 @@ */ #include "Tracing.h" #include "Driver.h" -#include "USB3.h" #include //sprintf #include //posix file i/o - create, write, close diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.h b/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.h index 65af5c5525..77bf7941aa 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.h +++ b/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.h @@ -5,8 +5,8 @@ * Copyright (c) 2003 by Siarzhuk Zharski * Distributed under the terms of the MIT License. */ -#ifndef _USB_SERIAL_TRACING_H_ -#define _USB_SERIAL_TRACING_H_ +#ifndef _PC_SERIAL_TRACING_H_ +#define _PC_SERIAL_TRACING_H_ void load_settings(); void create_log_file(); @@ -36,4 +36,4 @@ void trace_str(struct str *str); void trace_winsize(struct winsize *ws); void trace_tty(struct tty *tty); -#endif //_USB_SERIAL_TRACING_H_ +#endif //_PC_SERIAL_TRACING_H_ diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/UART.h b/src/add-ons/kernel/drivers/ports/pc_serial/UART.h new file mode 100644 index 0000000000..7d1ea8c8ea --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/pc_serial/UART.h @@ -0,0 +1,99 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * François Revol + */ +#ifndef _UART_H_ +#define _UART_H_ + +// References: +// http://www.beyondlogic.org/serial/serial.htm + + +// 8250 UART registers +#define THB 0 +#define RBR 0 +#define DLLB 0 +#define IER 1 +#define DLHB 1 +#define IIR 2 +#define FCR 2 +#define LCR 3 +#define MCR 4 +#define LSR 5 +#define MSR 6 +#define SR 7 + +// bits +#define IER_RDA (1 << 0) +#define IER_THRE (1 << 1) +#define IER_RLS (1 << 2) +#define IER_MS (1 << 3) +#define IER_SM (1 << 4) // 16750 +#define IER_LPM (1 << 5) // 16750 + +#define IIR_PENDING (1 << 0) +#define IIR_IMASK (0x03 << 1) +#define IIR_MS (0 << 1) +#define IIR_THRE (1 << 1) +#define IIR_RDA (2 << 1) +#define IIR_RLS (3 << 1) +#define IIR_TO (1 << 3) // 16550 +#define IIR_F64EN (1 << 5) // 16750 +#define IIR_FMASK (3 << 6) + +#define FCR_ENABLE (1 << 0) +#define FCR_RX_RST (1 << 1) +#define FCR_TX_RST (1 << 2) +#define FCR_DMA_EN (1 << 3) +#define FCR_F64EN (1 << 5) +#define FCR_FMASK (0x03 << 6) +#define FCR_F_1 (0 << 6) +#define FCR_F_4 (1 << 6) +#define FCR_F_8 (2 << 6) +#define FCR_F_14 (3 << 6) + +#define LCR_5BIT 0 +#define LCR_6BIT 1 +#define LCR_7BIT 2 +#define LCR_8BIT 3 +#define LCR_2STOP (1 << 2) +#define LCR_P_EN (1 << 3) +#define LCR_P_EVEN (1 << 4) +#define LCR_P_MARK (1 << 5) +#define LCR_BREAK (1 << 6) +#define LCR_DLAB (1 << 7) + +#define MCR_DTR (1 << 0) +#define MCR_RTS (1 << 1) +#define MCR_AUX1 (1 << 2) +#define MCR_AUX2 (1 << 3) +#define MCR_IRQ_EN (1 << 3) // ? +#define MCR_LOOP (1 << 4) +#define MCR_AUTOFLOW (1 << 5) // 16750 + +#define LSR_DR (1 << 0) +#define LSR_OVERRUN (1 << 1) +#define LSR_PARITY (1 << 2) +#define LSR_FRAMING (1 << 3) +#define LSR_BREAK (1 << 4) +#define LSR_THRE (1 << 5) +#define LSR_TSRE (1 << 6) +#define LSR_FIFO (1 << 7) + +#define MSR_DCTS (1 << 0) +#define MSR_DDSR (1 << 1) +#define MSR_TERI (1 << 2) +#define MSR_DDCD (1 << 3) +#define MSR_CTS (1 << 4) +#define MSR_DSR (1 << 5) +#define MSR_RI (1 << 6) +#define MSR_DCD (1 << 7) + +// speeds +//#define BPS_50 + + +#endif // _UART_H_ diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/pci_serial.txt b/src/add-ons/kernel/drivers/ports/pc_serial/pci_serial.txt new file mode 100644 index 0000000000..9ace2ca3f1 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/pc_serial/pci_serial.txt @@ -0,0 +1,36 @@ +PCI bus, device #4: Communication Device (Serial) [7|0|6] +Current configuration: irq [18] + io range: min b800 max b800 align 0 len 8 + io range: min bc00 max bc00 align 0 len 8 + io range: min c000 max c000 align 0 len 20 + mem range: min 0 max 0 align 0 len 80201000 + mem range: min 0 max 0 align 0 len 80201000 +1 configurations + +Possible configuration #0: irq [18] + io range: min b800 max b800 align 0 len 8 + io range: min bc00 max bc00 align 0 len 8 + io range: min c000 max c000 align 0 len 20 + mem range: min 0 max 0 align 0 len 80201000 + mem range: min 0 max 0 align 0 len 80201000 + +Bus-dependent information: +vendor id: 1415, device id: 1501 + +PCI bus, device #5: Communication Device (Parallel) [7|1|1] +Current configuration: irq [18] + io range: min c400 max c400 align 0 len 8 + io range: min c800 max c800 align 0 len 4 + io range: min cc00 max cc00 align 0 len 20 + mem range: min 0 max 0 align 0 len 80201000 +1 configurations + +Possible configuration #0: irq [18] + io range: min c400 max c400 align 0 len 8 + io range: min c800 max c800 align 0 len 4 + io range: min cc00 max cc00 align 0 len 20 + mem range: min 0 max 0 align 0 len 80201000 + +Bus-dependent information: +vendor id: 1415, device id: 1503 + diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/poke_16C952.lst b/src/add-ons/kernel/drivers/ports/pc_serial/poke_16C952.lst new file mode 100644 index 0000000000..3efc0d04d3 --- /dev/null +++ b/src/add-ons/kernel/drivers/ports/pc_serial/poke_16C952.lst @@ -0,0 +1,45 @@ +; poke script +; dump 16C952 ID regs + +outb b803 bf +outb b802 10 +outb b803 00 +; serial_icr_write(off,val) +; outb b807 off +; outb b805 val +; serial_icr_read(off) +; outb b807 00 +; outb b805 40 +; outb b807 off +; inb b805 +; outb b807 00 +; outb b805 00 + +outb b807 00 +outb b805 40 +; id1 +outb b807 08 +inb b805 +; id2 +outb b807 09 +inb b805 +; id3 +outb b807 0a +inb b805 +; rev +outb b807 0b +inb b805 + +; +outb b807 00 +inb b805 + + +outb b807 00 +outb b805 00 + + +; disable enhanced control bit +outb b803 bf +outb b802 00 +outb b803 00