Example #1
0
// until we support ISA device enumeration from PnP BIOS or ACPI,
// we have to probe the 4 default COM ports...
status_t
scan_isa_hardcoded()
{
#ifdef HANDLE_ISA_COM
	int i;
	bool serialDebug = get_safemode_boolean("serial_debug_output", true);

	for (i = 0; i < 4; i++) {
		// skip the port used for kernel debugging...
		if (serialDebug && sHardcodedPorts[i].ioBase == gKernelDebugPort) {
			TRACE_ALWAYS("Skipping port %d as it is used for kernel debug.\n", i);
			continue;
		}

		SerialDevice *device;
		device = new(std::nothrow) SerialDevice(&sSupportedDevices[0],
			sHardcodedPorts[i].ioBase, sHardcodedPorts[i].irq);
		if (device != NULL && device->Probe())
			pc_serial_insert_device(device);
		else
			delete device;
	}
#endif
	return B_OK;
}
Example #2
0
// until we support ISA device enumeration from PnP BIOS or ACPI,
// we have to probe the 4 default COM ports...
status_t
scan_isa_hardcoded()
{
#ifdef HANDLE_ISA_COM
	int i;

	for (i = 0; i < 4; i++) {
		// skip the port used for kernel debugging...
		if (sHardcodedPorts[i].ioBase == gKernelDebugPort)
			continue;

		SerialDevice *device;
		device = new(std::nothrow) SerialDevice(&sSupportedDevices[0],
			sHardcodedPorts[i].ioBase, sHardcodedPorts[i].irq);
		if (device != NULL && device->Probe())
			pc_serial_insert_device(device);
		else
			delete device;
	}
#endif
	return B_OK;
}
Example #3
0
// this version doesn't use config_manager, but can't probe the IRQ yet
status_t
scan_pci_alt()
{
	pci_info info;
	int ix;
	TRACE_ALWAYS("scanning PCI bus (alt)...\n");

	// 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];
			break;
		}
		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);

		// 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);
		int irq = info.u.h0.interrupt_line;

		SerialDevice *master = NULL;

		uint8 portCount = 0;
		uint32 maxPorts = DEVICES_COUNT;

		if (supported->constraints.maxports) {
			maxPorts = supported->constraints.maxports;
			TRACE_ALWAYS("card supports up to %d ports\n", maxPorts);
		}
		if (supported->constraints.subsystem_id_mask) {
			uint32 id = info.u.h0.subsystem_id;
			uint32 mask = supported->constraints.subsystem_id_mask;
			id &= mask;
			//TRACE_ALWAYS("mask: %lx, masked: %lx\n", mask, id);
			while (!(mask & 0x1)) {
				mask >>= 1;
				id >>= 1;
			}
			maxPorts = (uint8)id;
			TRACE_ALWAYS("subsystem id tells card has %d ports\n", maxPorts);
		}

		// find I/O ports
		for (int r = 0; r < 6; r++) {
			uint32 regbase = info.u.h0.base_registers[r];
			uint32 reglen = info.u.h0.base_register_sizes[r];

			/**/
			TRACE("ranges[%d] at 0x%08lx len 0x%lx flags 0x%02x\n", r,
				regbase, reglen, info.u.h0.base_register_flags[r]);
			/**/

			// empty
			if (reglen == 0)
				continue;

			// not I/O
			if ((info.u.h0.base_register_flags[r] & PCI_address_space) == 0)
				continue;

			// the range for sure doesn't contain any UART
			if (supported->constraints.ignoremask & (1 << r)) {
				TRACE_ALWAYS("ignored regs at 0x%08lx len 0x%lx\n",
					regbase, reglen);
				continue;
			}

			TRACE_ALWAYS("regs at 0x%08lx len 0x%lx\n",
				regbase, reglen);
			//&PCI_address_io_mask

			if (reglen < supported->constraints.minsize)
				continue;
			if (reglen > supported->constraints.maxsize)
				continue;

			SerialDevice *device;
			uint32 ioport = regbase;
next_split_alt:
			// no more to split
			if ((ioport - regbase) >= reglen)
				continue;

			if (portCount >= maxPorts)
				break;

			TRACE_ALWAYS("inserting device at io 0x%04lx as %s\n", ioport, 
				supported->name);

			
/**/
			device = new(std::nothrow) SerialDevice(supported, ioport, irq, master);
			if (device == NULL) {
				TRACE_ALWAYS("can't allocate device\n");
				continue;
			}

			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;
			portCount++;
			goto next_split_alt;
			// try next part of the I/O range now

		}
	}
Example #4
0
// 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) > (int)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'"*/" irq: %d flags: %08lx status: %s\n",
			bus_name, cookie, dinfo.devtype.base, dinfo.devtype.subtype,
			dinfo.devtype.interface, /*dinfo.id,*/ irq, 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

		resource_descriptor iodesc;
		SerialDevice *master = NULL;

		//TODO: handle maxports
		//TODO: handle subsystem_id_mask

		// instanciate devices on IO ports
		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(std::nothrow) SerialDevice(supported, ioport, irq, master);
			if (device == NULL) {
				TRACE_ALWAYS("can't allocate device\n");
				continue;
			}

			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
		}
	}
	return B_OK;
}