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
This commit is contained in:
@@ -14,15 +14,113 @@
|
|||||||
#include "Driver.h"
|
#include "Driver.h"
|
||||||
#include "SerialDevice.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];
|
SerialDevice *gSerialDevices[DEVICES_COUNT];
|
||||||
char *gDeviceNames[DEVICES_COUNT + 1];
|
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;
|
tty_module_info *gTTYModule = NULL;
|
||||||
struct ddomain gSerialDomain;
|
struct ddomain gSerialDomain;
|
||||||
sem_id gDriverLock = -1;
|
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
|
status_t
|
||||||
pc_serial_device_added(pc_device device, void **cookie)
|
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");
|
TRACE_FUNCRET("< pc_serial_device_removed() returns\n");
|
||||||
return B_OK;
|
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 -
|
//#pragma mark -
|
||||||
@@ -119,20 +534,28 @@ init_hardware()
|
|||||||
status_t
|
status_t
|
||||||
init_driver()
|
init_driver()
|
||||||
{
|
{
|
||||||
|
status_t status;
|
||||||
load_settings();
|
load_settings();
|
||||||
create_log_file();
|
create_log_file();
|
||||||
|
|
||||||
TRACE_FUNCALLS("> init_driver()\n");
|
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)
|
if (status < B_OK)
|
||||||
return status;
|
goto err_tty;
|
||||||
|
|
||||||
status = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule);
|
status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCIModule);
|
||||||
if (status < B_OK) {
|
if (status < B_OK)
|
||||||
put_module(B_TTY_MODULE_NAME);
|
goto err_pci;
|
||||||
return status;
|
|
||||||
}
|
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++)
|
for (int32 i = 0; i < DEVICES_COUNT; i++)
|
||||||
gSerialDevices[i] = NULL;
|
gSerialDevices[i] = NULL;
|
||||||
@@ -141,20 +564,40 @@ init_driver()
|
|||||||
|
|
||||||
gDriverLock = create_sem(1, DRIVER_NAME"_devices_table_lock");
|
gDriverLock = create_sem(1, DRIVER_NAME"_devices_table_lock");
|
||||||
if (gDriverLock < B_OK) {
|
if (gDriverLock < B_OK) {
|
||||||
put_module(B_USB_MODULE_NAME);
|
status = gDriverLock;
|
||||||
put_module(B_TTY_MODULE_NAME);
|
goto err_sem;
|
||||||
return gDriverLock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static pc_notify_hooks notifyHooks = {
|
status = ENOENT;
|
||||||
&pc_serial_device_added,
|
|
||||||
&pc_serial_device_removed
|
|
||||||
};
|
|
||||||
|
|
||||||
gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL);
|
memset(&gSerialDomain, 0, sizeof(gSerialDomain));
|
||||||
gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks);
|
ddbackground(&gSerialDomain);
|
||||||
|
|
||||||
|
|
||||||
|
scan_bus(B_ISA_BUS);
|
||||||
|
scan_bus(B_PCI_BUS);
|
||||||
|
|
||||||
|
|
||||||
|
// XXX: ISA cards
|
||||||
|
// XXX: pcmcia
|
||||||
|
|
||||||
|
|
||||||
TRACE_FUNCRET("< init_driver() returns\n");
|
TRACE_FUNCRET("< init_driver() returns\n");
|
||||||
return B_OK;
|
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");
|
TRACE_FUNCALLS("> uninit_driver()\n");
|
||||||
|
|
||||||
gUSBModule->uninstall_notify(DRIVER_NAME);
|
//gUSBModule->uninstall_notify(DRIVER_NAME);
|
||||||
acquire_sem(gDriverLock);
|
acquire_sem(gDriverLock);
|
||||||
|
|
||||||
for (int32 i = 0; i < DEVICES_COUNT; i++) {
|
for (int32 i = 0; i < DEVICES_COUNT; i++) {
|
||||||
if (gSerialDevices[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];
|
delete gSerialDevices[i];
|
||||||
gSerialDevices[i] = NULL;
|
gSerialDevices[i] = NULL;
|
||||||
}
|
}
|
||||||
@@ -178,7 +626,9 @@ uninit_driver()
|
|||||||
free(gDeviceNames[i]);
|
free(gDeviceNames[i]);
|
||||||
|
|
||||||
delete_sem(gDriverLock);
|
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);
|
put_module(B_TTY_MODULE_NAME);
|
||||||
|
|
||||||
TRACE_FUNCRET("< uninit_driver() returns\n");
|
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 */
|
/* pc_serial_open - handle open() calls */
|
||||||
static status_t
|
static status_t
|
||||||
pc_serial_open(const char *name, uint32 flags, void **cookie)
|
pc_serial_open(const char *name, uint32 flags, void **cookie)
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <Drivers.h>
|
#include <Drivers.h>
|
||||||
|
#include <ISA.h>
|
||||||
|
#include <PCI.h>
|
||||||
|
#include <config_manager.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef __HAIKU__
|
#ifdef __HAIKU__
|
||||||
@@ -25,9 +28,71 @@ extern "C" {
|
|||||||
#include <ttylayer.h>
|
#include <ttylayer.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// whether we should handle default COM ports
|
||||||
|
#define HANDLE_ISA_COM
|
||||||
|
|
||||||
#define DRIVER_NAME "pc_serial" // driver name for debug output
|
#define DRIVER_NAME "pc_serial" // driver name for debug output
|
||||||
#define DEVICES_COUNT 20 // max simultaneously open devices
|
#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 ... */
|
/* Some usefull helper defines ... */
|
||||||
#define SIZEOF(array) (sizeof(array) / sizeof(array[0])) /* size of array */
|
#define SIZEOF(array) (sizeof(array) / sizeof(array[0])) /* size of array */
|
||||||
/* This one rounds the size to integral count of segs (segments) */
|
/* This one rounds the size to integral count of segs (segments) */
|
||||||
@@ -35,6 +100,9 @@ extern "C" {
|
|||||||
/* Default device buffer size */
|
/* Default device buffer size */
|
||||||
#define DEF_BUFFER_SIZE 0x200
|
#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? */
|
/* line coding defines ... Come from CDC USB specs? */
|
||||||
#define LC_STOP_BIT_1 0
|
#define LC_STOP_BIT_1 0
|
||||||
#define LC_STOP_BIT_2 2
|
#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_DTR 0x0001
|
||||||
#define CLS_LINE_RTS 0x0002
|
#define CLS_LINE_RTS 0x0002
|
||||||
|
|
||||||
/* attributes etc ...*/
|
extern config_manager_for_driver_module_info *gConfigManagerModule;
|
||||||
#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 isa_module_info *gISAModule;
|
extern isa_module_info *gISAModule;
|
||||||
extern pci_module_info *gPCIModule;
|
extern pci_module_info *gPCIModule;
|
||||||
extern tty_module_info *gTTYModule;
|
extern tty_module_info *gTTYModule;
|
||||||
extern struct ddomain gSerialDomain;
|
extern struct ddomain gSerialDomain;
|
||||||
|
|
||||||
extern "C" {
|
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();
|
status_t init_hardware();
|
||||||
void uninit_driver();
|
void uninit_driver();
|
||||||
|
|
||||||
bool pc_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags);
|
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_open(const char *name, uint32 flags, void **cookie);
|
||||||
status_t pc_serial_read(void *cookie, off_t position, void *buffer, size_t *numBytes);
|
status_t pc_serial_read(void *cookie, off_t position, void *buffer, size_t *numBytes);
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
|
|
||||||
references:
|
references:
|
||||||
http://www.beyondlogic.org/serial/serial.htm
|
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/
|
||||||
|
|
||||||
|
|||||||
@@ -6,24 +6,23 @@
|
|||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#include "SerialDevice.h"
|
#include "SerialDevice.h"
|
||||||
#include "USB3.h"
|
#include "UART.h"
|
||||||
|
|
||||||
#include "ACM.h"
|
SerialDevice::SerialDevice(const struct serial_support_descriptor *device,
|
||||||
#include "FTDI.h"
|
uint32 ioBase, uint32 irq, const SerialDevice *master)
|
||||||
#include "KLSI.h"
|
: /*fSupportDescriptor(device->descriptor),
|
||||||
#include "Prolific.h"
|
fDevice(device),
|
||||||
|
fDescription(device->descriptor->name),*/
|
||||||
SerialDevice::SerialDevice(usb_device device, uint16 vendorID,
|
fSupportDescriptor(device),
|
||||||
uint16 productID, const char *description)
|
fDevice(NULL),
|
||||||
: fDevice(device),
|
fDescription(device->name),
|
||||||
fVendorID(vendorID),
|
//
|
||||||
fProductID(productID),
|
|
||||||
fDescription(description),
|
|
||||||
fDeviceOpen(false),
|
fDeviceOpen(false),
|
||||||
fDeviceRemoved(false),
|
fDeviceRemoved(false),
|
||||||
fControlPipe(0),
|
fBus(device->bus),
|
||||||
fReadPipe(0),
|
fIOBase(ioBase),
|
||||||
fWritePipe(0),
|
fIRQ(irq),
|
||||||
|
fMaster(master),
|
||||||
fBufferArea(-1),
|
fBufferArea(-1),
|
||||||
fReadBuffer(NULL),
|
fReadBuffer(NULL),
|
||||||
fReadBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)),
|
fReadBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)),
|
||||||
@@ -40,6 +39,7 @@ SerialDevice::SerialDevice(usb_device device, uint16 vendorID,
|
|||||||
{
|
{
|
||||||
memset(&fTTYFile, 0, sizeof(ttyfile));
|
memset(&fTTYFile, 0, sizeof(ttyfile));
|
||||||
memset(&fTTY, 0, sizeof(tty));
|
memset(&fTTY, 0, sizeof(tty));
|
||||||
|
memset(&fRover, 0, sizeof(ddrover));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -75,38 +75,79 @@ SerialDevice::Init()
|
|||||||
|
|
||||||
fWriteBuffer = fReadBuffer + fReadBufferSize;
|
fWriteBuffer = fReadBuffer + fReadBufferSize;
|
||||||
fInterruptBuffer = fWriteBuffer + fWriteBufferSize;
|
fInterruptBuffer = fWriteBuffer + fWriteBufferSize;
|
||||||
|
|
||||||
|
// disable DLAB
|
||||||
|
WriteReg8(LCR, 0);
|
||||||
|
|
||||||
return B_OK;
|
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
|
void
|
||||||
SerialDevice::SetModes()
|
SerialDevice::SetModes()
|
||||||
{
|
{
|
||||||
struct termios tios;
|
struct termios tios;
|
||||||
memcpy(&tios, &fTTY.t, sizeof(struct termios));
|
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;
|
uint16 newControl = fControlOut;
|
||||||
TRACE_FUNCRES(trace_termios, &tios);
|
|
||||||
|
|
||||||
static uint32 baudRates[] = {
|
static uint32 baudRates[] = {
|
||||||
0x00000000, //B0
|
0x00000000, //B0
|
||||||
@@ -132,11 +173,6 @@ SerialDevice::SetModes()
|
|||||||
0x000E1000, //921600
|
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;
|
usb_serial_line_coding lineCoding;
|
||||||
lineCoding.speed = baudRates[baudIndex];
|
lineCoding.speed = baudRates[baudIndex];
|
||||||
lineCoding.stopbits = (tios.c_cflag & CSTOPB) ? LC_STOP_BIT_2 : LC_STOP_BIT_1;
|
lineCoding.stopbits = (tios.c_cflag & CSTOPB) ? LC_STOP_BIT_2 : LC_STOP_BIT_1;
|
||||||
@@ -172,64 +208,103 @@ SerialDevice::SetModes()
|
|||||||
fLineCoding.parity);
|
fLineCoding.parity);
|
||||||
SetLineCoding(&fLineCoding);
|
SetLineCoding(&fLineCoding);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SerialDevice::Service(struct tty *ptty, struct ddrover *ddr, uint flags)
|
SerialDevice::Service(struct tty *ptty, struct ddrover *ddr, uint flags)
|
||||||
{
|
{
|
||||||
|
uint8 msr;
|
||||||
|
status_t err;
|
||||||
|
|
||||||
if (&fTTY != ptty)
|
if (&fTTY != ptty)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
TRACE_ALWAYS("%s(,,0x%08lx)\n", __FUNCTION__, flags);
|
||||||
|
|
||||||
if (flags <= TTYGETSIGNALS) {
|
if (flags <= TTYGETSIGNALS) {
|
||||||
switch (flags) {
|
switch (flags) {
|
||||||
case TTYENABLE:
|
case TTYENABLE:
|
||||||
TRACE("TTYENABLE\n");
|
TRACE("TTYENABLE\n");
|
||||||
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false);
|
|
||||||
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
|
SetModes();
|
||||||
fControlOut = CLS_LINE_DTR | CLS_LINE_RTS;
|
err = install_io_interrupt_handler(IRQ(), pc_serial_interrupt, this, 0);
|
||||||
SetControlLineState(fControlOut);
|
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;
|
break;
|
||||||
|
|
||||||
case TTYDISABLE:
|
case TTYDISABLE:
|
||||||
TRACE("TTYDISABLE\n");
|
TRACE("TTYDISABLE\n");
|
||||||
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false);
|
// remove the handler
|
||||||
fControlOut = 0x0;
|
remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this);
|
||||||
SetControlLineState(fControlOut);
|
// disable IRQ
|
||||||
|
WriteReg8(IER, 0);
|
||||||
|
WriteReg8(MCR, 0);
|
||||||
|
msr = ReadReg8(MSR);
|
||||||
|
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, msr & MSR_DCD);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TTYISTOP:
|
case TTYISTOP:
|
||||||
TRACE("TTYISTOP\n");
|
TRACE("TTYISTOP\n");
|
||||||
fInputStopped = true;
|
MaskReg8(MCR, MCR_RTS);
|
||||||
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false);
|
//fInputStopped = true;
|
||||||
|
//gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TTYIRESUME:
|
case TTYIRESUME:
|
||||||
TRACE("TTYIRESUME\n");
|
TRACE("TTYIRESUME\n");
|
||||||
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
|
OrReg8(MCR, MCR_RTS);
|
||||||
fInputStopped = false;
|
//gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
|
||||||
|
//fInputStopped = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TTYGETSIGNALS:
|
case TTYGETSIGNALS:
|
||||||
TRACE("TTYGETSIGNALS\n");
|
TRACE("TTYGETSIGNALS\n");
|
||||||
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, true);
|
msr = ReadReg8(MSR);
|
||||||
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
|
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, msr & MSR_DCD);
|
||||||
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDSR, false);
|
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, msr & MSR_CTS);
|
||||||
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWRI, false);
|
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDSR, msr & MSR_DSR);
|
||||||
|
gTTYModule->ttyhwsignal(ptty, ddr, TTYHWRI, msr & MSR_RI);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TTYSETMODES:
|
case TTYSETMODES:
|
||||||
TRACE("TTYSETMODES\n");
|
TRACE("TTYSETMODES\n");
|
||||||
SetModes();
|
SetModes();
|
||||||
|
//WriteReg8(IER, IER_RLS | IER_MS | IER_RDA);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TTYOSTART:
|
case TTYOSTART:
|
||||||
|
TRACE("TTYOSTART\n");
|
||||||
|
// enable irqs
|
||||||
|
WriteReg8(IER, IER_RLS | IER_MS | IER_RDA | IER_THRE);
|
||||||
|
break;
|
||||||
case TTYOSYNC:
|
case TTYOSYNC:
|
||||||
|
TRACE("TTYOSYNC\n");
|
||||||
|
return (ReadReg8(LSR) & (LSR_THRE | LSR_TSRE)) == (LSR_THRE | LSR_TSRE);
|
||||||
|
break;
|
||||||
case TTYSETBREAK:
|
case TTYSETBREAK:
|
||||||
|
TRACE("TTYSETBREAK\n");
|
||||||
|
OrReg8(LCR, LCR_BREAK);
|
||||||
|
break;
|
||||||
case TTYCLRBREAK:
|
case TTYCLRBREAK:
|
||||||
|
TRACE("TTYCLRBREAK\n");
|
||||||
|
MaskReg8(LCR, LCR_BREAK);
|
||||||
|
break;
|
||||||
case TTYSETDTR:
|
case TTYSETDTR:
|
||||||
|
TRACE("TTYSETDTR\n");
|
||||||
|
OrReg8(MCR, MCR_DTR);
|
||||||
|
break;
|
||||||
case TTYCLRDTR:
|
case TTYCLRDTR:
|
||||||
TRACE("TTY other\n");
|
TRACE("TTYCLRDTR\n");
|
||||||
|
MaskReg8(MCR, MCR_DTR);
|
||||||
break;
|
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
|
status_t
|
||||||
SerialDevice::Open(uint32 flags)
|
SerialDevice::Open(uint32 flags)
|
||||||
{
|
{
|
||||||
@@ -249,7 +404,7 @@ SerialDevice::Open(uint32 flags)
|
|||||||
if (fDeviceRemoved)
|
if (fDeviceRemoved)
|
||||||
return B_DEV_NOT_READY;
|
return B_DEV_NOT_READY;
|
||||||
|
|
||||||
gTTYModule->ttyinit(&fTTY, true);
|
gTTYModule->ttyinit(&fTTY, false);
|
||||||
fTTYFile.tty = &fTTY;
|
fTTYFile.tty = &fTTY;
|
||||||
fTTYFile.flags = flags;
|
fTTYFile.flags = flags;
|
||||||
ResetDevice();
|
ResetDevice();
|
||||||
@@ -259,7 +414,7 @@ SerialDevice::Open(uint32 flags)
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
gTTYModule->ddacquire(ddr, &gSerialDomain);
|
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);
|
gTTYModule->ddrdone(ddr);
|
||||||
|
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
@@ -267,6 +422,7 @@ SerialDevice::Open(uint32 flags)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
fDeviceThread = spawn_kernel_thread(DeviceThread, "usb_serial device thread",
|
fDeviceThread = spawn_kernel_thread(DeviceThread, "usb_serial device thread",
|
||||||
B_NORMAL_PRIORITY, this);
|
B_NORMAL_PRIORITY, this);
|
||||||
|
|
||||||
@@ -285,6 +441,7 @@ SerialDevice::Open(uint32 flags)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
TRACE_ALWAYS("failed to queue initial interrupt\n");
|
TRACE_ALWAYS("failed to queue initial interrupt\n");
|
||||||
|
|
||||||
|
#endif
|
||||||
fDeviceOpen = true;
|
fDeviceOpen = true;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -298,24 +455,31 @@ SerialDevice::Read(char *buffer, size_t *numBytes)
|
|||||||
return B_DEV_NOT_READY;
|
return B_DEV_NOT_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t status;
|
||||||
|
#if 0
|
||||||
status_t status = mutex_lock(&fReadLock);
|
status_t status = mutex_lock(&fReadLock);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
TRACE_ALWAYS("read: failed to get read lock\n");
|
TRACE_ALWAYS("read: failed to get read lock\n");
|
||||||
*numBytes = 0;
|
*numBytes = 0;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
|
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
|
||||||
if (!ddr) {
|
if (!ddr) {
|
||||||
*numBytes = 0;
|
*numBytes = 0;
|
||||||
|
#if 0
|
||||||
mutex_unlock(&fReadLock);
|
mutex_unlock(&fReadLock);
|
||||||
|
#endif
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = gTTYModule->ttyread(&fTTYFile, ddr, buffer, numBytes);
|
status = gTTYModule->ttyread(&fTTYFile, ddr, buffer, numBytes);
|
||||||
gTTYModule->ddrdone(ddr);
|
gTTYModule->ddrdone(ddr);
|
||||||
|
|
||||||
|
#if 0
|
||||||
mutex_unlock(&fReadLock);
|
mutex_unlock(&fReadLock);
|
||||||
|
#endif
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,8 +488,19 @@ status_t
|
|||||||
SerialDevice::Write(const char *buffer, size_t *numBytes)
|
SerialDevice::Write(const char *buffer, size_t *numBytes)
|
||||||
{
|
{
|
||||||
size_t bytesLeft = *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);
|
status_t status = mutex_lock(&fWriteLock);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
TRACE_ALWAYS("write: failed to get write lock\n");
|
TRACE_ALWAYS("write: failed to get write lock\n");
|
||||||
@@ -373,6 +548,7 @@ SerialDevice::Write(const char *buffer, size_t *numBytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&fWriteLock);
|
mutex_unlock(&fWriteLock);
|
||||||
|
#endif
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,9 +607,11 @@ SerialDevice::Close()
|
|||||||
OnClose();
|
OnClose();
|
||||||
|
|
||||||
if (!fDeviceRemoved) {
|
if (!fDeviceRemoved) {
|
||||||
|
#if 0
|
||||||
gUSBModule->cancel_queued_transfers(fReadPipe);
|
gUSBModule->cancel_queued_transfers(fReadPipe);
|
||||||
gUSBModule->cancel_queued_transfers(fWritePipe);
|
gUSBModule->cancel_queued_transfers(fWritePipe);
|
||||||
gUSBModule->cancel_queued_transfers(fControlPipe);
|
gUSBModule->cancel_queued_transfers(fControlPipe);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
|
struct ddrover *ddr = gTTYModule->ddrstart(NULL);
|
||||||
@@ -473,12 +651,14 @@ SerialDevice::Removed()
|
|||||||
// we need to ensure that we do not use the device anymore
|
// we need to ensure that we do not use the device anymore
|
||||||
fStopDeviceThread = true;
|
fStopDeviceThread = true;
|
||||||
fInputStopped = false;
|
fInputStopped = false;
|
||||||
|
#if 0
|
||||||
gUSBModule->cancel_queued_transfers(fReadPipe);
|
gUSBModule->cancel_queued_transfers(fReadPipe);
|
||||||
gUSBModule->cancel_queued_transfers(fWritePipe);
|
gUSBModule->cancel_queued_transfers(fWritePipe);
|
||||||
gUSBModule->cancel_queued_transfers(fControlPipe);
|
gUSBModule->cancel_queued_transfers(fControlPipe);
|
||||||
|
#endif
|
||||||
|
|
||||||
int32 result = B_OK;
|
int32 result = B_OK;
|
||||||
wait_for_thread(fDeviceThread, &result);
|
//wait_for_thread(fDeviceThread, &result);
|
||||||
fDeviceThread = -1;
|
fDeviceThread = -1;
|
||||||
|
|
||||||
mutex_lock(&fWriteLock);
|
mutex_lock(&fWriteLock);
|
||||||
@@ -487,7 +667,7 @@ SerialDevice::Removed()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
SerialDevice::AddDevice(const usb_configuration_info *config)
|
SerialDevice::AddDevice(const serial_config_descriptor *config)
|
||||||
{
|
{
|
||||||
// default implementation - does nothing
|
// default implementation - does nothing
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -502,13 +682,14 @@ SerialDevice::ResetDevice()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
status_t
|
status_t
|
||||||
SerialDevice::SetLineCoding(usb_serial_line_coding *coding)
|
SerialDevice::SetLineCoding(usb_serial_line_coding *coding)
|
||||||
{
|
{
|
||||||
// default implementation - does nothing
|
// default implementation - does nothing
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
SerialDevice::SetControlLineState(uint16 state)
|
SerialDevice::SetControlLineState(uint16 state)
|
||||||
@@ -543,6 +724,7 @@ int32
|
|||||||
SerialDevice::DeviceThread(void *data)
|
SerialDevice::DeviceThread(void *data)
|
||||||
{
|
{
|
||||||
SerialDevice *device = (SerialDevice *)data;
|
SerialDevice *device = (SerialDevice *)data;
|
||||||
|
#if 0
|
||||||
|
|
||||||
while (!device->fStopDeviceThread) {
|
while (!device->fStopDeviceThread) {
|
||||||
status_t status = gUSBModule->queue_bulk(device->fReadPipe,
|
status_t status = gUSBModule->queue_bulk(device->fReadPipe,
|
||||||
@@ -592,6 +774,7 @@ SerialDevice::DeviceThread(void *data)
|
|||||||
gTTYModule->ddrdone(ddr);
|
gTTYModule->ddrdone(ddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,14 +821,17 @@ SerialDevice::InterruptCallbackFunction(void *cookie, int32 status,
|
|||||||
// ToDo: maybe handle those somehow?
|
// ToDo: maybe handle those somehow?
|
||||||
|
|
||||||
if (status == B_OK && !device->fDeviceRemoved) {
|
if (status == B_OK && !device->fDeviceRemoved) {
|
||||||
|
#if 0
|
||||||
status = gUSBModule->queue_interrupt(device->fControlPipe,
|
status = gUSBModule->queue_interrupt(device->fControlPipe,
|
||||||
device->fInterruptBuffer, device->fInterruptBufferSize,
|
device->fInterruptBuffer, device->fInterruptBufferSize,
|
||||||
device->InterruptCallbackFunction, device);
|
device->InterruptCallbackFunction, device);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
SerialDevice *
|
SerialDevice *
|
||||||
SerialDevice::MakeDevice(usb_device device, uint16 vendorID,
|
SerialDevice::MakeDevice(usb_device device, uint16 vendorID,
|
||||||
uint16 productID)
|
uint16 productID)
|
||||||
@@ -711,3 +897,66 @@ SerialDevice::MakeDevice(usb_device device, uint16 vendorID,
|
|||||||
|
|
||||||
return new ACMDevice(device, vendorID, productID, "CDC ACM compatible device");
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,29 +12,26 @@
|
|||||||
|
|
||||||
class SerialDevice {
|
class SerialDevice {
|
||||||
public:
|
public:
|
||||||
SerialDevice(usb_device device,
|
/* SerialDevice(struct serial_config_descriptor
|
||||||
uint16 vendorID, uint16 productID,
|
*device, uint32 ioBase, uint32 irq, SerialDevice *master=NULL);*/
|
||||||
const char *description);
|
SerialDevice(const struct serial_support_descriptor
|
||||||
|
*device, uint32 ioBase, uint32 irq, const SerialDevice *master=NULL);
|
||||||
virtual ~SerialDevice();
|
virtual ~SerialDevice();
|
||||||
|
|
||||||
static SerialDevice * MakeDevice(usb_device device, uint16 vendorID,
|
static SerialDevice * MakeDevice(struct serial_config_descriptor
|
||||||
uint16 productID);
|
*device);
|
||||||
|
|
||||||
status_t Init();
|
status_t Init();
|
||||||
|
|
||||||
usb_device Device() { return fDevice; };
|
const struct serial_support_descriptor *SupportDescriptor() const
|
||||||
uint16 ProductID() { return fProductID; };
|
{ return fSupportDescriptor; };
|
||||||
uint16 VendorID() { return fVendorID; };
|
struct serial_config_descriptor *ConfigDescriptor() const
|
||||||
const char * Description() { return fDescription; };
|
{ return fDevice; };
|
||||||
|
//uint16 ProductID() const { return fProductID; };
|
||||||
|
//uint16 VendorID() const { return fVendorID; };
|
||||||
|
const char * Description() const { return fDescription; };
|
||||||
|
|
||||||
void SetControlPipe(usb_pipe handle);
|
const SerialDevice * Master() const { return fMaster ? fMaster : this; };
|
||||||
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; }
|
|
||||||
|
|
||||||
char * ReadBuffer() { return fReadBuffer; };
|
char * ReadBuffer() { return fReadBuffer; };
|
||||||
size_t ReadBufferSize() { return fReadBufferSize; };
|
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,
|
bool Service(struct tty *ptty, struct ddrover *ddr,
|
||||||
uint flags);
|
uint flags);
|
||||||
|
|
||||||
|
int32 InterruptHandler();
|
||||||
|
|
||||||
status_t Open(uint32 flags);
|
status_t Open(uint32 flags);
|
||||||
status_t Read(char *buffer, size_t *numBytes);
|
status_t Read(char *buffer, size_t *numBytes);
|
||||||
status_t Write(const 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; };
|
bool IsRemoved() { return fDeviceRemoved; };
|
||||||
|
|
||||||
/* virtual interface to be overriden as necessary */
|
/* 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 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 status_t SetControlLineState(uint16 state);
|
||||||
|
|
||||||
virtual void OnRead(char **buffer, size_t *numBytes);
|
virtual void OnRead(char **buffer, size_t *numBytes);
|
||||||
@@ -72,6 +71,9 @@ virtual void OnWrite(const char *buffer, size_t *numBytes,
|
|||||||
size_t *packetBytes);
|
size_t *packetBytes);
|
||||||
virtual void OnClose();
|
virtual void OnClose();
|
||||||
|
|
||||||
|
uint32 IOBase() const { return fIOBase; };
|
||||||
|
uint32 IRQ() const { return fIRQ; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetReadBufferSize(size_t size) { fReadBufferSize = size; };
|
void SetReadBufferSize(size_t size) { fReadBufferSize = size; };
|
||||||
void SetWriteBufferSize(size_t size) { fWriteBufferSize = size; };
|
void SetWriteBufferSize(size_t size) { fWriteBufferSize = size; };
|
||||||
@@ -89,20 +91,25 @@ static void InterruptCallbackFunction(void *cookie,
|
|||||||
int32 status, void *data,
|
int32 status, void *data,
|
||||||
uint32 actualLength);
|
uint32 actualLength);
|
||||||
|
|
||||||
usb_device fDevice; // USB device handle
|
uint8 ReadReg8(int reg);
|
||||||
uint16 fVendorID;
|
void WriteReg8(int reg, uint8 value);
|
||||||
uint16 fProductID;
|
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
|
const char * fDescription; // informational description
|
||||||
bool fDeviceOpen;
|
bool fDeviceOpen;
|
||||||
bool fDeviceRemoved;
|
bool fDeviceRemoved;
|
||||||
|
|
||||||
/* communication pipes */
|
bus_type fBus;
|
||||||
usb_pipe fControlPipe;
|
uint32 fIOBase;
|
||||||
usb_pipe fReadPipe;
|
uint32 fIRQ;
|
||||||
usb_pipe fWritePipe;
|
const SerialDevice * fMaster;
|
||||||
|
|
||||||
/* line coding */
|
/* line coding */
|
||||||
usb_serial_line_coding fLineCoding;
|
//usb_serial_line_coding fLineCoding;
|
||||||
|
|
||||||
/* data buffers */
|
/* data buffers */
|
||||||
area_id fBufferArea;
|
area_id fBufferArea;
|
||||||
@@ -129,6 +136,7 @@ static void InterruptCallbackFunction(void *cookie,
|
|||||||
bool fInputStopped;
|
bool fInputStopped;
|
||||||
struct ttyfile fTTYFile;
|
struct ttyfile fTTYFile;
|
||||||
struct tty fTTY;
|
struct tty fTTY;
|
||||||
|
struct ddrover fRover;
|
||||||
|
|
||||||
/* device thread management */
|
/* device thread management */
|
||||||
thread_id fDeviceThread;
|
thread_id fDeviceThread;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "Tracing.h"
|
#include "Tracing.h"
|
||||||
#include "Driver.h"
|
#include "Driver.h"
|
||||||
#include "USB3.h"
|
|
||||||
|
|
||||||
#include <stdio.h> //sprintf
|
#include <stdio.h> //sprintf
|
||||||
#include <unistd.h> //posix file i/o - create, write, close
|
#include <unistd.h> //posix file i/o - create, write, close
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
* Copyright (c) 2003 by Siarzhuk Zharski <[email protected]>
|
* Copyright (c) 2003 by Siarzhuk Zharski <[email protected]>
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef _USB_SERIAL_TRACING_H_
|
#ifndef _PC_SERIAL_TRACING_H_
|
||||||
#define _USB_SERIAL_TRACING_H_
|
#define _PC_SERIAL_TRACING_H_
|
||||||
|
|
||||||
void load_settings();
|
void load_settings();
|
||||||
void create_log_file();
|
void create_log_file();
|
||||||
@@ -36,4 +36,4 @@ void trace_str(struct str *str);
|
|||||||
void trace_winsize(struct winsize *ws);
|
void trace_winsize(struct winsize *ws);
|
||||||
void trace_tty(struct tty *tty);
|
void trace_tty(struct tty *tty);
|
||||||
|
|
||||||
#endif //_USB_SERIAL_TRACING_H_
|
#endif //_PC_SERIAL_TRACING_H_
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Haiku, Inc.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* François Revol <[email protected]>
|
||||||
|
*/
|
||||||
|
#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_
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user