status_t arch_smp_init(kernel_args *args) { TRACE(("%s: entry\n", __func__)); if (!apic_available()) { // if we don't have an apic we can't do smp TRACE(("%s: apic not available for smp\n", __func__)); return B_OK; } // setup some globals memcpy(sCPUAPICIds, args->arch_args.cpu_apic_id, sizeof(args->arch_args.cpu_apic_id)); memcpy(sAPICVersions, args->arch_args.cpu_apic_version, sizeof(args->arch_args.cpu_apic_version)); // set up the local apic on the boot cpu arch_smp_per_cpu_init(args, 0); if (args->num_cpus > 1) { // I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted reserve_io_interrupt_vectors(3, 0xfd - ARCH_INTERRUPT_BASE); install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &x86_ici_interrupt, NULL, B_NO_LOCK_VECTOR); install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &x86_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR); install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &x86_spurious_interrupt, NULL, B_NO_LOCK_VECTOR); } return B_OK; }
void arch_debug_install_interrupt_handlers(void) { install_io_interrupt_handler(INT_PS2_KEYBOARD, &debug_keyboard_interrupt, NULL, 0); sKeyboardHandlerInstalled = true; }
/** * Sets IRQ for VMMDev. * * @returns Haiku error code. * @param pvState Pointer to the state info structure. */ static int VBoxGuestHaikuAddIRQ(void *pvState) { status_t err; struct VBoxGuestDeviceState *pState = (struct VBoxGuestDeviceState *)pvState; AssertReturn(pState, VERR_INVALID_PARAMETER); err = install_io_interrupt_handler(pState->iIrqResId, VBoxGuestHaikuISR, pState, 0); if (err == B_OK) return VINF_SUCCESS; return VERR_DEV_IO_ERROR; }
int bus_setup_intr(device_t dev, struct resource *res, int p3, interrupt_handler int_func, void *cookie, void **tag) { int irq = (int)res; struct int_tag *int_tag = (struct int_tag *) malloc(sizeof(struct int_tag)); int_tag->int_func = int_func; int_tag->cookie = cookie; int_tag->irq = irq; *tag = int_tag; return install_io_interrupt_handler(irq, int_func, cookie, 0); }
static status_t hpet_init_timer(hpet_timer_cookie* cookie) { struct hpet_timer *timer = cookie->timer; uint32 interrupts = (uint32)HPET_GET_CAP_TIMER_ROUTE(timer); // TODO: Check if the interrupt is already used, and try another int32 interrupt = -1; for (int i = 0; i < 32; i++) { if (interrupts & (1 << i)) { interrupt = i; break; } } if (interrupt == -1) { dprintf("hpet_init_timer(): timer can't be routed to any interrupt!"); return B_ERROR; } // Non-periodic mode timer->config &= ~HPET_CONF_TIMER_TYPE; // level triggered timer->config |= HPET_CONF_TIMER_INT_TYPE; // Disable FSB/MSI timer->config &= ~HPET_CONF_TIMER_FSB_ENABLE; #if HPET64 //disable 32 bit mode timer->config &= ~HPET_CONF_TIMER_32MODE; #else //enable 32 bit mode timer->config |= HPET_CONF_TIMER_32MODE; #endif timer->config |= (interrupt << HPET_CONF_TIMER_INT_ROUTE_SHIFT) & HPET_CONF_TIMER_INT_ROUTE_MASK; cookie->irq = interrupt = HPET_GET_CONF_TIMER_INT_ROUTE(timer); status_t status = install_io_interrupt_handler(interrupt, &hpet_timer_interrupt, cookie, 0); if (status != B_OK) { dprintf("hpet_init_timer(): cannot install interrupt handler: %s\n", strerror(status)); return status; } #ifdef TRACE_HPET hpet_dump_timer(timer); #endif return B_OK; }
/** * Sets IRQ for VMMDev. * * @returns Haiku error code. * @param pvState Pointer to the state info structure. */ static int VBoxGuestHaikuAddIRQ(void *pvState) { status_t status; struct VBoxGuestDeviceState *pState = (struct VBoxGuestDeviceState *)pvState; status = install_io_interrupt_handler(pState->iIrqResId, VBoxGuestHaikuISR, pState, 0); if (status != B_OK) { return VERR_DEV_IO_ERROR; } return VINF_SUCCESS; }
static status_t b57_open(const char *name, uint32 flags, void **cookie) { struct be_b57_dev *pDevice = NULL; int i; *cookie = NULL; for (i = 0; i < cards_found; i++) { if (strcmp(dev_list[i],name) == 0) { *cookie = pDevice = &be_b57_dev_cards[i]; break; } } if (*cookie == NULL) return B_FILE_NOT_FOUND; if (atomic_or(&pDevice->opened, 1)) { *cookie = pDevice = NULL; return B_BUSY; } install_io_interrupt_handler(pDevice->pci_data.u.h0.interrupt_line, b57_interrupt, *cookie, 0); if (LM_InitializeAdapter(&pDevice->lm_dev) != LM_STATUS_SUCCESS) { atomic_and(&pDevice->opened,0); remove_io_interrupt_handler(pDevice->pci_data.u.h0.interrupt_line, b57_interrupt, *cookie); *cookie = NULL; return B_ERROR; } /*QQ_InitQueue(&pDevice->rx_out_of_buf_q.Container, MAX_RX_PACKET_DESC_COUNT);*/ //pDevice->lm_dev.PhyCrcCount = 0; LM_EnableInterrupt(&pDevice->lm_dev); dprintf("Broadcom 57xx adapter successfully inited at %s:\n", name); dprintf("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", pDevice->lm_dev.NodeAddress[0], pDevice->lm_dev.NodeAddress[1], pDevice->lm_dev.NodeAddress[2], pDevice->lm_dev.NodeAddress[3], pDevice->lm_dev.NodeAddress[4], pDevice->lm_dev.NodeAddress[5]); dprintf("PCI Data: 0x%08x\n", pDevice->pci_data.u.h0.base_registers[0]); dprintf("IRQ: %d\n", pDevice->pci_data.u.h0.interrupt_line); return B_OK; }
static void InitInterruptHandler(DeviceInfo& di) { SharedInfo& si = *(di.sharedInfo); TRACE("enter InitInterruptHandler()\n"); DisableVBI(); // disable & clear any pending interrupts si.bInterruptAssigned = false; // indicate interrupt not assigned yet // Create a semaphore for vertical blank management. si.vertBlankSem = create_sem(0, di.name); if (si.vertBlankSem < 0) return; // Change the owner of the semaphores to the calling team (usually the // app_server). This is required because apps can't aquire kernel // semaphores. thread_id threadID = find_thread(NULL); thread_info threadInfo; status_t status = get_thread_info(threadID, &threadInfo); if (status == B_OK) status = set_sem_owner(si.vertBlankSem, threadInfo.team); // If there is a valid interrupt assigned, set up interrupts. if (status == B_OK && di.pciInfo.u.h0.interrupt_pin != 0x00 && di.pciInfo.u.h0.interrupt_line != 0xff) { // We have a interrupt line to use. status = install_io_interrupt_handler(di.pciInfo.u.h0.interrupt_line, InterruptHandler, (void*)(&di), 0); if (status == B_OK) si.bInterruptAssigned = true; // we can use interrupt related functions } if (status != B_OK) { // Interrupt does not exist; thus delete semaphore as it won't be used. delete_sem(si.vertBlankSem); si.vertBlankSem = -1; } }
OMAP3Timer::OMAP3Timer(fdt_module_info *fdtModule, fdt_device_node node) : HardwareTimer(fdtModule, node), fSystemTime(0) { fRegArea = fFDT->map_reg_range(node, 0, (void**)&fRegBase); if (fRegArea < 0) panic("Cannot map OMAP3Timer registers!"); fInterrupt = fFDT->get_interrupt(node, 0); if (fInterrupt < 0) panic("Cannot get OMAP3Timer interrupt!"); uint32 rev = fRegBase[TIDR]; dprintf("OMAP: Found timer @ 0x%p, IRQ %d (rev %ld.%ld)\n", fRegBase, fInterrupt, (rev >> 4) & 0xf, rev & 0xf); // Let the timer run (so we can use it as clocksource) fRegBase[TCLR] |= 1; fRegBase[TIER] = 2; // Enable overflow interrupt install_io_interrupt_handler(fInterrupt, &OMAP3Timer::_InterruptWrapper, this, 0); }
status_t device_open(const char *name, uint32 flags, void **cookie) { struct sis_info *info; area_id area; int id; // verify device access (we only allow one user at a time) { char *thisName; int32 mask; // search for device name for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) { if (!strcmp(name, thisName)) break; } if (!thisName) return EINVAL; // check if device is already open mask = 1L << id; if (atomic_or(&gDeviceOpenMask, mask) & mask) return B_BUSY; } // allocate internal device structure if ((area = create_area(DEVICE_NAME " private data", cookie, B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(sizeof(struct sis_info)), B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA)) < B_OK) { gDeviceOpenMask &= ~(1L << id); return B_NO_MEMORY; } info = (struct sis_info *)*cookie; memset(info, 0, sizeof(struct sis_info)); info->cookieMagic = SiS_COOKIE_MAGIC; info->thisArea = area; info->id = id; info->pciInfo = pciInfo[id]; info->registers = (addr_t)pciInfo[id]->u.h0.base_registers[0]; if (sis900_getMACAddress(info)) dprintf(DEVICE_NAME ": MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", info->address.ebyte[0], info->address.ebyte[1], info->address.ebyte[2], info->address.ebyte[3], info->address.ebyte[4], info->address.ebyte[5]); else dprintf(DEVICE_NAME ": could not get MAC address\n"); readSettings(info); if (createSemaphores(info) == B_OK) { status_t status = sis900_initPHYs(info); if (status == B_OK) { TRACE((DEVICE_NAME ": MII status = %d\n", mdio_read(info, MII_STATUS))); //sis900_configFIFOs(info); sis900_reset(info); // install & enable interrupts install_io_interrupt_handler(info->pciInfo->u.h0.interrupt_line, sis900_interrupt, info, 0); sis900_enableInterrupts(info); sis900_setRxFilter(info); sis900_createRings(info); // enable receiver's state machine write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Rx_ENABLE); // check link mode & add timer (once every second) sis900_checkMode(info); add_timer(&info->timer, sis900_timer, 1000000LL, B_PERIODIC_TIMER); return B_OK; } dprintf(DEVICE_NAME ": could not initialize MII PHY: %s\n", strerror(status)); deleteSemaphores(info); } else dprintf(DEVICE_NAME ": could not create semaphores.\n"); gDeviceOpenMask &= ~(1L << id); delete_area(area); return B_ERROR; }
/* Initialize the BT-9X8 and confirm that it is operating as expected */ static long init_buslogic(BusLogic *bl) { uchar status; uchar id[16]; int i; char *str = bl->productname; d_printf("buslogic: init_buslogic()\n"); dprintf("buslogic: reset: "); outb(BL_CONTROL_REG, BL_CONTROL_RHARD); spin(10000); /* give the controller some time to settle down from reset */ for(i=0; i<1000; i++) { spin(100000); status = inb(BL_STATUS_REG); if(status & BL_STATUS_DACT) { dprintf("."); continue; } if(status & BL_STATUS_DFAIL) { dprintf(" FAILED\n"); return -1; } if(status & BL_STATUS_INREQ) { dprintf(" OKAY\n"); break; } if(status & BL_STATUS_HARDY) { dprintf(" READY\n"); break; } } if(i==100) { dprintf(" TIMEOUT\n"); return -1; } if(bl_execute(bl, 0x04, NULL, 0, id, 4)) { d_printf("buslogic: can't id?\n"); return B_ERROR; } d_printf("buslogic: Firmware Rev %c.%c\n",id[2],id[3]); id[0]=14; id[14]=id[2]; if(bl_execute(bl, 0x8d, id, 1, id, 14)) { d_printf("buslogic: cannot read extended config\n"); return B_ERROR; } d_printf("buslogic: rev = %c.%c%c%c mb = %d, sgmax = %d, flags = 0x%02x\n", id[14], id[10], id[11], id[12], id[4], id[2] | (id[3]<<8), id[13]); if(id[13] & 0x01) bl->wide = 1; else bl->wide = 0; if(id[14] == '5') { *str++ = 'B'; *str++ = 'T'; *str++ = '-'; *str++ = '9'; *str++ = bl->wide ? '5' : '4'; *str++ = '8'; if(id[13] & 0x02) *str++ = 'D'; *str++ = ' '; *str++ = 'v'; *str++ = id[14]; *str++ = '.'; *str++ = id[10]; *str++ = id[11]; *str++ = id[12]; *str++ = 0; } else { strcpy(str,"unknown"); } if(bl_execute(bl, 0x0B, NULL, 0, id, 3)) { d_printf("buslogic: cannot read config\n"); return B_ERROR; } bl->scsi_id = id[2]; d_printf("buslogic: Adapter SCSI ID = %d\n",bl->scsi_id); if(install_io_interrupt_handler(bl->irq, scsi_int_dispatch, bl, 0) == B_ERROR) d_printf("buslogic: can't install irq handler\n"); /* are we getting INTs? */ bl->done = 0; spin(10000); outb(BL_COMMAND_REG, 0x00); spin(1000000); if(bl->done) { d_printf("buslogic: interrupt test passed\n"); } else { d_printf("buslogic: interrupt test failed\n"); return B_ERROR; } /* strict round-robin on */ id[0] = 0; if(bl_execute(bl,0x8F, id, 1, NULL, 0)) { d_printf("buslogic: cannot enable strict round-robin mode\n"); return B_ERROR; } id[0] = bl->box_count; { int mbaddr = toLE(bl->phys_mailboxes); memcpy(id + 1, &(mbaddr),4); } if(bl_execute(bl, 0x81, id, 5, NULL, 0)) { d_printf("buslogic: cannot init mailboxes\n"); return B_ERROR; } d_printf("buslogic: %d mailboxes @ 0x%08xv/0x%08lxp\n", bl->box_count, (uint) bl->out_boxes, bl->phys_mailboxes); return B_NO_ERROR; }
static status_t ice1712_setup(ice1712 *ice) { int result, i; uint8 reg8 = 0; uint16 mute; ice->irq = ice->info.u.h0.interrupt_line; ice->Controller = ice->info.u.h0.base_registers[0]; ice->DDMA = ice->info.u.h0.base_registers[1]; ice->DMA_Path = ice->info.u.h0.base_registers[2]; ice->Multi_Track = ice->info.u.h0.base_registers[3]; // Soft Reset write_ccs_uint8(ice, CCS_CONTROL_STATUS, 0x81); snooze(200000); write_ccs_uint8(ice, CCS_CONTROL_STATUS, 0x01); snooze(200000); result = read_eeprom(ice, ice->eeprom_data); /* TRACE("EEprom -> "); for (i = 0; i < 32; i++) TRACE("%x, ", eeprom_data[i]); TRACE("<- EEprom\n");*/ write_ccs_uint8(ice, CCS_SERR_SHADOW, 0x01); //Write all configurations register from EEProm ice->info.device_id = ice->eeprom_data[E2PROM_MAP_SUBVENDOR_HIGH] << 8 | ice->eeprom_data[E2PROM_MAP_SUBVENDOR_LOW]; ice->info.vendor_id = ice->eeprom_data[E2PROM_MAP_SUBDEVICE_HIGH] << 8 | ice->eeprom_data[E2PROM_MAP_SUBDEVICE_LOW]; ice->product = ice->info.vendor_id << 16 | ice->info.device_id; TRACE("Product ID : 0x%x\n", ice->product); write_cci_uint8(ice, CCI_GPIO_WRITE_MASK, ice->eeprom_data[E2PROM_MAP_GPIOMASK]); write_cci_uint8(ice, CCI_GPIO_DATA, ice->eeprom_data[E2PROM_MAP_GPIOSTATE]); write_cci_uint8(ice, CCI_GPIO_DIRECTION_CONTROL, ice->eeprom_data[E2PROM_MAP_GPIODIR]); TRACE("CCI_GPIO_WRITE_MASK : 0x%x\n", ice->eeprom_data[E2PROM_MAP_GPIOMASK]); TRACE("CCI_GPIO_DATA : 0x%x\n", ice->eeprom_data[E2PROM_MAP_GPIOSTATE]); TRACE("CCI_GPIO_DIRECTION_CONTROL : 0x%x\n", ice->eeprom_data[E2PROM_MAP_GPIODIR]); //Write Configuration in the PCI configuration Register (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x60, 1, ice->eeprom_data[E2PROM_MAP_CONFIG]); (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x61, 1, ice->eeprom_data[E2PROM_MAP_ACL]); (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x62, 1, ice->eeprom_data[E2PROM_MAP_I2S]); (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x63, 1, ice->eeprom_data[E2PROM_MAP_SPDIF]); TRACE("E2PROM_MAP_CONFIG : 0x%x\n", ice->eeprom_data[E2PROM_MAP_CONFIG]); reg8 = ice->eeprom_data[E2PROM_MAP_CONFIG]; //Bits signification for E2PROM_MAP_CONFIG Byte // // 8 7 6 5 4 3 2 1 0 // |-D-|-C-|---B---|---A--- // // D : MPU401 number minus 1 // C : AC'97 // B : Stereo ADC number minus 1 (=> 1 to 4) // A : Stereo DAC number minus 1 (=> 1 to 4) ice->config.nb_DAC = ((reg8 & 0x03) + 1) * 2; reg8 >>= 2; ice->config.nb_ADC = ((reg8 & 0x03) + 1) * 2; reg8 >>= 2; if ((reg8 & 0x01) != 0) {//Consumer AC'97 Exist TRACE("Consumer AC'97 does exist\n"); //For now do nothing /* write_ccs_uint8(ice, CCS_CONS_AC97_COMMAND_STATUS, 0x40); snooze(10000); write_ccs_uint8(ice, CCS_CONS_AC97_COMMAND_STATUS, 0x00); snooze(20000); */ } else { TRACE("Consumer AC'97 does NOT exist\n"); } reg8 >>= 1; ice->config.nb_MPU401 = (reg8 & 0x1) + 1; if (ice->config.nb_MPU401 > 0) { sprintf(ice->midi_interf[0].name, "midi/ice1712/%ld/1", ice - cards + 1); (*mpu401->create_device)(ice->Controller + CCS_MIDI_1_DATA, &ice->midi_interf[0].mpu401device, 0x14121712, ice_1712_midi_interrupt_op, &ice->midi_interf[0]); names[num_names++] = ice->midi_interf[0].name; ice->midi_interf[0].card = ice; ice->midi_interf[0].int_mask = CCS_INTERRUPT_MIDI_1; } if (ice->config.nb_MPU401 > 1) { sprintf(ice->midi_interf[1].name, "midi/ice1712/%ld/2", ice - cards + 1); (*mpu401->create_device)(ice->Controller + CCS_MIDI_2_DATA, &ice->midi_interf[1].mpu401device, 0x14121712, ice_1712_midi_interrupt_op, &ice->midi_interf[1]); names[num_names++] = ice->midi_interf[1].name; ice->midi_interf[1].card = ice; ice->midi_interf[1].int_mask = CCS_INTERRUPT_MIDI_2; } TRACE("E2PROM_MAP_SPDIF : 0x%x\n", ice->eeprom_data[E2PROM_MAP_SPDIF]); ice->config.spdif = ice->eeprom_data[E2PROM_MAP_SPDIF]; switch (ice->product) { case ICE1712_SUBDEVICE_DELTA66 : case ICE1712_SUBDEVICE_DELTA44 : ice->CommLines.clock = DELTA66_CLK; ice->CommLines.data_in = 0; ice->CommLines.data_out = DELTA66_DOUT; ice->CommLines.cs_mask = DELTA66_CLK | DELTA66_DOUT | DELTA66_CODEC_CS_0 | DELTA66_CODEC_CS_1; break; case ICE1712_SUBDEVICE_DELTA410 : case ICE1712_SUBDEVICE_AUDIOPHILE_2496 : case ICE1712_SUBDEVICE_DELTADIO2496 : ice->CommLines.clock = AP2496_CLK; ice->CommLines.data_in = AP2496_DIN; ice->CommLines.data_out = AP2496_DOUT; ice->CommLines.cs_mask = AP2496_CLK | AP2496_DIN | AP2496_DOUT | AP2496_SPDIF_CS | AP2496_CODEC_CS; break; case ICE1712_SUBDEVICE_DELTA1010 : case ICE1712_SUBDEVICE_DELTA1010LT : ice->CommLines.clock = DELTA1010LT_CLK; ice->CommLines.data_in = DELTA1010LT_DIN; ice->CommLines.data_out = DELTA1010LT_DOUT; ice->CommLines.cs_mask = DELTA1010LT_CLK | DELTA1010LT_DIN | DELTA1010LT_DOUT | DELTA1010LT_CS_NONE; break; case ICE1712_SUBDEVICE_VX442 : ice->CommLines.clock = VX442_CLK; ice->CommLines.data_in = VX442_DIN; ice->CommLines.data_out = VX442_DOUT; ice->CommLines.cs_mask = VX442_SPDIF_CS | VX442_CODEC_CS_0 | VX442_CODEC_CS_1; break; } sprintf(ice->name, "%s/%ld", HMULTI_AUDIO_DEV_PATH, ice - cards + 1); names[num_names++] = ice->name; names[num_names] = NULL; ice->buffer_ready_sem = create_sem(0, "Buffer Exchange"); if (ice->buffer_ready_sem < B_OK) { return ice->buffer_ready_sem; } // TRACE("installing interrupt : %0x\n", ice->irq); install_io_interrupt_handler(ice->irq, ice_1712_int, ice, 0); ice->mem_id_pb = alloc_mem(&ice->phys_addr_pb, &ice->log_addr_pb, PLAYBACK_BUFFER_TOTAL_SIZE, "playback buffer"); if (ice->mem_id_pb < B_OK) { remove_io_interrupt_handler(ice->irq, ice_1712_int, ice); delete_sem(ice->buffer_ready_sem); return ice->mem_id_pb; } ice->mem_id_rec = alloc_mem(&ice->phys_addr_rec, &ice->log_addr_rec, RECORD_BUFFER_TOTAL_SIZE, "record buffer"); if (ice->mem_id_rec < B_OK) { remove_io_interrupt_handler(ice->irq, ice_1712_int, ice); delete_sem(ice->buffer_ready_sem); delete_area(ice->mem_id_pb); return(ice->mem_id_rec); } memset(ice->log_addr_pb, 0, PLAYBACK_BUFFER_TOTAL_SIZE); memset(ice->log_addr_rec, 0, RECORD_BUFFER_TOTAL_SIZE); ice->sampling_rate = 0x08; ice->buffer = 0; ice->frames_count = 0; ice->buffer_size = MAX_BUFFER_FRAMES; ice->total_output_channels = ice->config.nb_DAC; if (ice->config.spdif & SPDIF_OUT_PRESENT) ice->total_output_channels += 2; ice->total_input_channels = ice->config.nb_ADC + 2; if (ice->config.spdif & SPDIF_IN_PRESENT) ice->total_input_channels += 2; //Write bits in the GPIO write_cci_uint8(ice, CCI_GPIO_WRITE_MASK, ~(ice->CommLines.cs_mask)); //Deselect CS write_cci_uint8(ice, CCI_GPIO_DATA, ice->CommLines.cs_mask); //Set the rampe volume to a faster one write_mt_uint16(ice, MT_VOLUME_CONTROL_RATE, 0x01); //All Analog outputs from DMA write_mt_uint16(ice, MT_ROUTING_CONTROL_PSDOUT, 0x0000); //All Digital output from DMA write_mt_uint16(ice, MT_ROUTING_CONTROL_SPDOUT, 0x0000); //Just to route all input to all output // write_mt_uint16(ice, MT_ROUTING_CONTROL_PSDOUT, 0xAAAA); // write_mt_uint32(ice, MT_CAPTURED_DATA, 0x76543210); //Just to route SPDIF Input to DAC 0 // write_mt_uint16(ice, MT_ROUTING_CONTROL_PSDOUT, 0xAAAF); // write_mt_uint32(ice, MT_CAPTURED_DATA, 0x76543280); //Mute all input mute = (ICE1712_MUTE_VALUE << 0) | (ICE1712_MUTE_VALUE << 8); for (i = 0; i < 2 * ICE1712_HARDWARE_VOLUME; i++) { write_mt_uint8(ice, MT_VOLUME_CONTROL_CHANNEL_INDEX, i); write_mt_uint16(ice, MT_VOLUME_CONTROL_CHANNEL_INDEX, mute); } //Unmask Interrupt write_ccs_uint8(ice, CCS_CONTROL_STATUS, 0x41); reg8 = read_ccs_uint8(ice, CCS_INTERRUPT_MASK); TRACE("-----CCS----- = %x\n", reg8); write_ccs_uint8(ice, CCS_INTERRUPT_MASK, 0xEF); /* reg16 = read_ds_uint16(ice, DS_DMA_INT_MASK); TRACE("-----DS_DMA----- = %x\n", reg16); write_ds_uint16(ice, DS_DMA_INT_MASK, 0x0000); */ reg8 = read_mt_uint8(ice, MT_DMA_INT_MASK_STATUS); TRACE("-----MT_DMA----- = %x\n", reg8); write_mt_uint8(ice, MT_DMA_INT_MASK_STATUS, 0x00); return B_OK; };
OHCI::OHCI(pci_info *info, Stack *stack) : BusManager(stack), fPCIInfo(info), fStack(stack), fOperationalRegisters(NULL), fRegisterArea(-1), fHccaArea(-1), fHcca(NULL), fInterruptEndpoints(NULL), fDummyControl(NULL), fDummyBulk(NULL), fDummyIsochronous(NULL), fFirstTransfer(NULL), fLastTransfer(NULL), fFinishTransfersSem(-1), fFinishThread(-1), fStopFinishThread(false), fProcessingPipe(NULL), fRootHub(NULL), fRootHubAddress(0), fPortCount(0) { if (!fInitOK) { TRACE_ERROR("bus manager failed to init\n"); return; } TRACE("constructing new OHCI host controller driver\n"); fInitOK = false; mutex_init(&fEndpointLock, "ohci endpoint lock"); // enable busmaster and memory mapped access uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, PCI_command, 2); command &= ~PCI_command_io; command |= PCI_command_master | PCI_command_memory; sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, PCI_command, 2, command); // map the registers uint32 offset = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, PCI_base_registers, 4); offset &= PCI_address_memory_32_mask; TRACE_ALWAYS("iospace offset: 0x%lx\n", offset); fRegisterArea = map_physical_memory("OHCI memory mapped registers", (void *)offset, B_PAGE_SIZE, B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, (void **)&fOperationalRegisters); if (fRegisterArea < B_OK) { TRACE_ERROR("failed to map register memory\n"); return; } TRACE("mapped operational registers: %p\n", fOperationalRegisters); // Check the revision of the controller, which should be 10h uint32 revision = _ReadReg(OHCI_REVISION) & 0xff; TRACE("version %ld.%ld%s\n", OHCI_REVISION_HIGH(revision), OHCI_REVISION_LOW(revision), OHCI_REVISION_LEGACY(revision) ? ", legacy support" : ""); if (OHCI_REVISION_HIGH(revision) != 1 || OHCI_REVISION_LOW(revision) != 0) { TRACE_ERROR("unsupported OHCI revision\n"); return; } void *hccaPhysicalAddress; fHccaArea = fStack->AllocateArea((void **)&fHcca, &hccaPhysicalAddress, sizeof(ohci_hcca), "USB OHCI Host Controller Communication Area"); if (fHccaArea < B_OK) { TRACE_ERROR("unable to create the HCCA block area\n"); return; } memset(fHcca, 0, sizeof(ohci_hcca)); // Set Up Host controller // Dummy endpoints fDummyControl = _AllocateEndpoint(); if (!fDummyControl) return; fDummyBulk = _AllocateEndpoint(); if (!fDummyBulk) { _FreeEndpoint(fDummyControl); return; } fDummyIsochronous = _AllocateEndpoint(); if (!fDummyIsochronous) { _FreeEndpoint(fDummyControl); _FreeEndpoint(fDummyBulk); return; } // Static endpoints that get linked in the HCCA fInterruptEndpoints = new(std::nothrow) ohci_endpoint_descriptor *[OHCI_STATIC_ENDPOINT_COUNT]; if (!fInterruptEndpoints) { TRACE_ERROR("failed to allocate memory for interrupt endpoints\n"); _FreeEndpoint(fDummyControl); _FreeEndpoint(fDummyBulk); _FreeEndpoint(fDummyIsochronous); return; } for (int32 i = 0; i < OHCI_STATIC_ENDPOINT_COUNT; i++) { fInterruptEndpoints[i] = _AllocateEndpoint(); if (!fInterruptEndpoints[i]) { TRACE_ERROR("failed to allocate interrupt endpoint %ld", i); while (--i >= 0) _FreeEndpoint(fInterruptEndpoints[i]); _FreeEndpoint(fDummyBulk); _FreeEndpoint(fDummyControl); _FreeEndpoint(fDummyIsochronous); return; } } // build flat tree so that at each of the static interrupt endpoints // fInterruptEndpoints[i] == interrupt endpoint for interval 2^i uint32 interval = OHCI_BIGGEST_INTERVAL; uint32 intervalIndex = OHCI_STATIC_ENDPOINT_COUNT - 1; while (interval > 1) { uint32 insertIndex = interval / 2; while (insertIndex < OHCI_BIGGEST_INTERVAL) { fHcca->interrupt_table[insertIndex] = fInterruptEndpoints[intervalIndex]->physical_address; insertIndex += interval; } intervalIndex--; interval /= 2; } // setup the empty slot in the list and linking of all -> first fHcca->interrupt_table[0] = fInterruptEndpoints[0]->physical_address; for (int32 i = 1; i < OHCI_STATIC_ENDPOINT_COUNT; i++) { fInterruptEndpoints[i]->next_physical_endpoint = fInterruptEndpoints[0]->physical_address; fInterruptEndpoints[i]->next_logical_endpoint = fInterruptEndpoints[0]; } // Now link the first endpoint to the isochronous endpoint fInterruptEndpoints[0]->next_physical_endpoint = fDummyIsochronous->physical_address; // Determine in what context we are running (Kindly copied from FreeBSD) uint32 control = _ReadReg(OHCI_CONTROL); if (control & OHCI_INTERRUPT_ROUTING) { TRACE_ALWAYS("smm is in control of the host controller\n"); uint32 status = _ReadReg(OHCI_COMMAND_STATUS); _WriteReg(OHCI_COMMAND_STATUS, status | OHCI_OWNERSHIP_CHANGE_REQUEST); for (uint32 i = 0; i < 100 && (control & OHCI_INTERRUPT_ROUTING); i++) { snooze(1000); control = _ReadReg(OHCI_CONTROL); } if ((control & OHCI_INTERRUPT_ROUTING) != 0) { TRACE_ERROR("smm does not respond. resetting...\n"); _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); snooze(USB_DELAY_BUS_RESET); } else TRACE_ALWAYS("ownership change successful\n"); } else { TRACE("cold started\n"); snooze(USB_DELAY_BUS_RESET); } // This reset should not be necessary according to the OHCI spec, but // without it some controllers do not start. _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); snooze(USB_DELAY_BUS_RESET); // We now own the host controller and the bus has been reset uint32 frameInterval = _ReadReg(OHCI_FRAME_INTERVAL); uint32 intervalValue = OHCI_GET_INTERVAL_VALUE(frameInterval); // Disable interrupts right before we reset _WriteReg(OHCI_COMMAND_STATUS, OHCI_HOST_CONTROLLER_RESET); // Nominal time for a reset is 10 us uint32 reset = 0; for (uint32 i = 0; i < 10; i++) { spin(10); reset = _ReadReg(OHCI_COMMAND_STATUS) & OHCI_HOST_CONTROLLER_RESET; if (reset == 0) break; } if (reset) { TRACE_ERROR("error resetting the host controller (timeout)\n"); return; } // The controller is now in SUSPEND state, we have 2ms to go OPERATIONAL. // Interrupts are disabled. // Set up host controller register _WriteReg(OHCI_HCCA, (uint32)hccaPhysicalAddress); _WriteReg(OHCI_CONTROL_HEAD_ED, (uint32)fDummyControl->physical_address); _WriteReg(OHCI_BULK_HEAD_ED, (uint32)fDummyBulk->physical_address); // Disable all interrupts _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS); // Switch on desired functional features control = _ReadReg(OHCI_CONTROL); control &= ~(OHCI_CONTROL_BULK_SERVICE_RATIO_MASK | OHCI_ENABLE_LIST | OHCI_HC_FUNCTIONAL_STATE_MASK | OHCI_INTERRUPT_ROUTING); control |= OHCI_ENABLE_LIST | OHCI_CONTROL_BULK_RATIO_1_4 | OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL; // And finally start the controller _WriteReg(OHCI_CONTROL, control); // The controller is now OPERATIONAL. frameInterval = (_ReadReg(OHCI_FRAME_INTERVAL) & OHCI_FRAME_INTERVAL_TOGGLE) ^ OHCI_FRAME_INTERVAL_TOGGLE; frameInterval |= OHCI_FSMPS(intervalValue) | intervalValue; _WriteReg(OHCI_FRAME_INTERVAL, frameInterval); // 90% periodic uint32 periodic = OHCI_PERIODIC(intervalValue); _WriteReg(OHCI_PERIODIC_START, periodic); // Fiddle the No Over Current Protection bit to avoid chip bug uint32 desca = _ReadReg(OHCI_RH_DESCRIPTOR_A); _WriteReg(OHCI_RH_DESCRIPTOR_A, desca | OHCI_RH_NO_OVER_CURRENT_PROTECTION); _WriteReg(OHCI_RH_STATUS, OHCI_RH_LOCAL_POWER_STATUS_CHANGE); snooze(OHCI_ENABLE_POWER_DELAY); _WriteReg(OHCI_RH_DESCRIPTOR_A, desca); // The AMD756 requires a delay before re-reading the register, // otherwise it will occasionally report 0 ports. uint32 numberOfPorts = 0; for (uint32 i = 0; i < 10 && numberOfPorts == 0; i++) { snooze(OHCI_READ_DESC_DELAY); uint32 descriptor = _ReadReg(OHCI_RH_DESCRIPTOR_A); numberOfPorts = OHCI_RH_GET_PORT_COUNT(descriptor); } if (numberOfPorts > OHCI_MAX_PORT_COUNT) numberOfPorts = OHCI_MAX_PORT_COUNT; fPortCount = numberOfPorts; TRACE("port count is %d\n", fPortCount); // Create semaphore the finisher thread will wait for fFinishTransfersSem = create_sem(0, "OHCI Finish Transfers"); if (fFinishTransfersSem < B_OK) { TRACE_ERROR("failed to create semaphore\n"); return; } // Create the finisher service thread fFinishThread = spawn_kernel_thread(_FinishThread, "ohci finish thread", B_URGENT_DISPLAY_PRIORITY, (void *)this); resume_thread(fFinishThread); // Install the interrupt handler TRACE("installing interrupt handler\n"); install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, _InterruptHandler, (void *)this, 0); // Enable interesting interrupts now that the handler is in place _WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_NORMAL_INTERRUPTS | OHCI_MASTER_INTERRUPT_ENABLE); TRACE("OHCI host controller driver constructed\n"); fInitOK = true; }
// 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; }
static status_t open_hook(const char *name, uint32 flags, void** cookie) { dp83815_properties_t *data; uint8 temp8; // uint16 temp16; uint32 temp32; unsigned char cmd; TRACE(( kDevName " open_hook()\n" )); // verify device access { char *thisName; int32 mask; // search for device name for (temp8 = 0; (thisName = dp83815_names[temp8]) != NULL; temp8++) { if (!strcmp(name, thisName)) break; } if (!thisName) return EINVAL; // check if device is already open mask = 1L << temp8; if (atomic_or(&m_openmask, mask) & mask) return B_BUSY; } //Create a structure that contains the internals if (!(*cookie = data = (dp83815_properties_t *)malloc(sizeof(dp83815_properties_t)))) { TRACE(( kDevName " open_hook(): Out of memory\n" )); return B_NO_MEMORY; } //Set status to open: m_openmask &= ~( 1L << temp8 ); //Clear memory memset( data , 0 , sizeof( dp83815_properties_t ) ); //Set the ID data->device_id = temp8; // Create lock data->lock = create_sem( 1 , kDevName " data protect" ); set_sem_owner( data->lock , B_SYSTEM_TEAM ); data->Rx.Sem = create_sem( 0 , kDevName " read wait" ); set_sem_owner( data->Rx.Sem , B_SYSTEM_TEAM ); data->Tx.Sem = create_sem( 1 , kDevName " write wait" ); set_sem_owner( data->Tx.Sem , B_SYSTEM_TEAM ); //Set up the cookie data->pcii = m_devices[data->device_id]; //Enable the registers dp83815_init_registers( data ); /* enable pci address access */ cmd = m_pcimodule->read_pci_config(data->pcii->bus, data->pcii->device, data->pcii->function, PCI_command, 2); cmd = cmd | PCI_command_io | PCI_command_master | PCI_command_memory; m_pcimodule->write_pci_config(data->pcii->bus, data->pcii->device, data->pcii->function, PCI_command, 2, cmd ); if (allocate_resources(data) != B_OK) goto err1; /* We want interrupts! */ if ( install_io_interrupt_handler( data->pcii->u.h0.interrupt_line , dp83815_interrupt_hook , data , 0 ) != B_OK ) { TRACE(( kDevName " open_hook(): Error installing interrupt handler\n" )); return B_ERROR; } { temp32 = read32(REG_SRR); TRACE(( "SRR: %x\n", temp32)); } write32(REG_CR, CR_RXR|CR_TXR); /* Reset Tx & Rx */ if ( init_ring_buffers(data) != B_OK ) /* Init ring buffers */ goto err1; write32(REG_RFCR, RFCR_RFEN|RFCR_AAB|RFCR_AAM|RFCR_AAU); write32(REG_RXCFG, RXCFG_ATP|RXCFG_DRTH(31)); /* Set the drth */ write32(REG_TXCFG, TXCFG_CSI| TXCFG_HBI| TXCFG_ATP| TXCFG_MXDMA_256| TXCFG_FLTH(16)| TXCFG_DRTH(16) ); write32(REG_IMR, ISR_RXIDLE | ISR_TXOK | ISR_RXOK ); write32(REG_CR, CR_RXE); /* Enable Rx */ write32(REG_IER, 1); /* Enable interrupts */ return B_OK; err1: free_resources(data); free(data); return B_ERROR; }
static status_t open_hook(const char* name, uint32 flags, void** cookie) { int32 index = 0; device_info *di; shared_info *si; thread_id thid; thread_info thinfo; status_t result = B_OK; char shared_name[B_OS_NAME_LENGTH]; physical_entry map[1]; size_t net_buf_size; void *unaligned_dma_buffer; /* find the device name in the list of devices */ /* we're never passed a name we didn't publish */ while (pd->device_names[index] && (strcmp(name, pd->device_names[index]) != 0)) index++; /* for convienience */ di = &(pd->di[index]); /* make sure no one else has write access to the common data */ AQUIRE_BEN(pd->kernel); /* if it's already open for writing */ if (di->is_open) { /* mark it open another time */ goto mark_as_open; } /* create the shared_info area */ sprintf(shared_name, DEVICE_FORMAT " shared", di->pcii.vendor_id, di->pcii.device_id, di->pcii.bus, di->pcii.device, di->pcii.function); /* create this area with NO user-space read or write permissions, to prevent accidental damage */ di->shared_area = create_area(shared_name, (void **)&(di->si), B_ANY_KERNEL_ADDRESS, ((sizeof(shared_info) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), B_FULL_LOCK, B_USER_CLONEABLE_AREA); if (di->shared_area < 0) { /* return the error */ result = di->shared_area; goto done; } /* save a few dereferences */ si = di->si; /* create the DMA command buffer area */ //fixme? for R4.5 a workaround for cloning would be needed! /* we want to setup a 1Mb buffer (size must be multiple of B_PAGE_SIZE) */ net_buf_size = ((1 * 1024 * 1024) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1); /* create the area that will hold the DMA command buffer */ si->unaligned_dma_area = create_area("NV DMA cmd buffer", (void **)&unaligned_dma_buffer, B_ANY_KERNEL_ADDRESS, 2 * net_buf_size, /* take twice the net size so we can have MTRR-WC even on old systems */ B_32_BIT_CONTIGUOUS, /* GPU always needs access */ B_USER_CLONEABLE_AREA | B_READ_AREA | B_WRITE_AREA); // TODO: Physical aligning can be done without waste using the // private create_area_etc(). /* on error, abort */ if (si->unaligned_dma_area < 0) { /* free the already created shared_info area, and return the error */ result = si->unaligned_dma_area; goto free_shared; } /* we (also) need the physical adress our DMA buffer is at, as this needs to be * fed into the GPU's engine later on. Get an aligned adress so we can use MTRR-WC * even on older CPU's. */ get_memory_map(unaligned_dma_buffer, B_PAGE_SIZE, map, 1); si->dma_buffer_pci = (void*) ((map[0].address + net_buf_size - 1) & ~(net_buf_size - 1)); /* map the net DMA command buffer into vmem, using Write Combining */ si->dma_area = map_physical_memory( "NV aligned DMA cmd buffer", (addr_t)si->dma_buffer_pci, net_buf_size, B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, B_READ_AREA | B_WRITE_AREA, &(si->dma_buffer)); /* if failed with write combining try again without */ if (si->dma_area < 0) { si->dma_area = map_physical_memory( "NV aligned DMA cmd buffer", (addr_t)si->dma_buffer_pci, net_buf_size, B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA, &(si->dma_buffer)); } /* if there was an error, delete our other areas and pass on error*/ if (si->dma_area < 0) { /* free the already created areas, and return the error */ result = si->dma_area; goto free_shared_and_uadma; } /* save the vendor and device IDs */ si->vendor_id = di->pcii.vendor_id; si->device_id = di->pcii.device_id; si->revision = di->pcii.revision; si->bus = di->pcii.bus; si->device = di->pcii.device; si->function = di->pcii.function; /* ensure that the accelerant's INIT_ACCELERANT function can be executed */ si->accelerant_in_use = false; /* preset singlehead card to prevent early INT routine calls (once installed) to * wrongly identify the INT request coming from us! */ si->ps.secondary_head = false; /* note the amount of system RAM the system BIOS assigned to the card if applicable: * unified memory architecture (UMA) */ switch ((((uint32)(si->device_id)) << 16) | si->vendor_id) { case 0x01a010de: /* Nvidia GeForce2 Integrated GPU */ /* device at bus #0, device #0, function #1 holds value at byte-index 0x7C */ si->ps.memory_size = 1024 * 1024 * (((((*pci_bus->read_pci_config)(0, 0, 1, 0x7c, 4)) & 0x000007c0) >> 6) + 1); /* last 64kB RAM is used for the BIOS (or something else?) */ si->ps.memory_size -= (64 * 1024); break; case 0x01f010de: /* Nvidia GeForce4 MX Integrated GPU */ /* device at bus #0, device #0, function #1 holds value at byte-index 0x84 */ si->ps.memory_size = 1024 * 1024 * (((((*pci_bus->read_pci_config)(0, 0, 1, 0x84, 4)) & 0x000007f0) >> 4) + 1); /* last 64kB RAM is used for the BIOS (or something else?) */ si->ps.memory_size -= (64 * 1024); break; default: /* all other cards have own RAM: the amount of which is determined in the * accelerant. */ break; } /* map the device */ result = map_device(di); if (result < 0) goto free_shared_and_alldma; /* we will be returning OK status for sure now */ result = B_OK; /* disable and clear any pending interrupts */ //fixme: //distinquish between crtc1/crtc2 once all heads get seperate driver instances! disable_vbi_all(di->regs); /* preset we can't use INT related functions */ si->ps.int_assigned = false; /* create a semaphore for vertical blank management */ si->vblank = create_sem(0, di->name); if (si->vblank < 0) goto mark_as_open; /* change the owner of the semaphores to the opener's team */ /* this is required because apps can't aquire kernel semaphores */ thid = find_thread(NULL); get_thread_info(thid, &thinfo); set_sem_owner(si->vblank, thinfo.team); /* If there is a valid interrupt line assigned then set up interrupts */ if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff) || /* no IRQ assigned */ (di->pcii.u.h0.interrupt_line <= 0x02)) /* system IRQ assigned */ { /* delete the semaphore as it won't be used */ delete_sem(si->vblank); si->vblank = -1; } else { /* otherwise install our interrupt handler */ result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, nv_interrupt, (void *)di, 0); /* bail if we couldn't install the handler */ if (result != B_OK) { /* delete the semaphore as it won't be used */ delete_sem(si->vblank); si->vblank = -1; } else { /* inform accelerant(s) we can use INT related functions */ si->ps.int_assigned = true; } } mark_as_open: /* mark the device open */ di->is_open++; /* send the cookie to the opener */ *cookie = di; goto done; free_shared_and_alldma: /* clean up our aligned DMA area */ delete_area(si->dma_area); si->dma_area = -1; si->dma_buffer = NULL; free_shared_and_uadma: /* clean up our unaligned DMA area */ delete_area(si->unaligned_dma_area); si->unaligned_dma_area = -1; si->dma_buffer_pci = NULL; free_shared: /* clean up our shared area */ delete_area(di->shared_area); di->shared_area = -1; di->si = NULL; done: /* end of critical section */ RELEASE_BEN(pd->kernel); /* all done, return the status */ return result; }
static void init_interrupt_handler(intel_info &info) { info.shared_info->vblank_sem = create_sem(0, "intel extreme vblank"); if (info.shared_info->vblank_sem < B_OK) return; status_t status = B_OK; // We need to change the owner of the sem to the calling team (usually the // app_server), because userland apps cannot acquire kernel semaphores thread_id thread = find_thread(NULL); thread_info threadInfo; if (get_thread_info(thread, &threadInfo) != B_OK || set_sem_owner(info.shared_info->vblank_sem, threadInfo.team) != B_OK) { status = B_ERROR; } // Find the right interrupt vector, using MSIs if available. info.irq = 0xff; info.use_msi = false; if (info.pci->u.h0.interrupt_pin != 0x00) info.irq = info.pci->u.h0.interrupt_line; if (gPCIx86Module != NULL && gPCIx86Module->get_msi_count(info.pci->bus, info.pci->device, info.pci->function) >= 1) { uint8 msiVector = 0; if (gPCIx86Module->configure_msi(info.pci->bus, info.pci->device, info.pci->function, 1, &msiVector) == B_OK && gPCIx86Module->enable_msi(info.pci->bus, info.pci->device, info.pci->function) == B_OK) { ERROR("using message signaled interrupts\n"); info.irq = msiVector; info.use_msi = true; } } if (status == B_OK && info.irq != 0xff) { // we've gotten an interrupt line for us to use info.fake_interrupts = false; status = install_io_interrupt_handler(info.irq, &intel_interrupt_handler, (void*)&info, 0); if (status == B_OK) { write32(info, INTEL_DISPLAY_A_PIPE_STATUS, DISPLAY_PIPE_VBLANK_STATUS | DISPLAY_PIPE_VBLANK_ENABLED); write32(info, INTEL_DISPLAY_B_PIPE_STATUS, DISPLAY_PIPE_VBLANK_STATUS | DISPLAY_PIPE_VBLANK_ENABLED); write16(info, find_reg(info, INTEL_INTERRUPT_IDENTITY), ~0); // enable interrupts - we only want VBLANK interrupts bool hasPCH = info.device_type.HasPlatformControlHub(); uint16 enable = hasPCH ? (PCH_INTERRUPT_VBLANK_PIPEA | PCH_INTERRUPT_VBLANK_PIPEB) : (INTERRUPT_VBLANK_PIPEA | INTERRUPT_VBLANK_PIPEB); write16(info, find_reg(info, INTEL_INTERRUPT_ENABLED), enable); write16(info, find_reg(info, INTEL_INTERRUPT_MASK), ~enable); } } if (status < B_OK) { // There is no interrupt reserved for us, or we couldn't install our // interrupt handler, let's fake the vblank interrupt for our clients // using a timer interrupt info.fake_interrupts = true; // TODO: fake interrupts! TRACE("Fake interrupt mode (no PCI interrupt line assigned\n"); status = B_ERROR; } if (status < B_OK) { delete_sem(info.shared_info->vblank_sem); info.shared_info->vblank_sem = B_ERROR; } }
static status_t wb840_open(const char *name, uint32 flags, void** cookie) { char *deviceName = NULL; int32 i; int32 mask; struct wb_device *data; status_t status; LOG((DEVICE_NAME ": open()\n")); for (i = 0; (deviceName = gDevNameList[i]) != NULL; i++) { if (!strcmp(name, deviceName)) break; } if (deviceName == NULL) { LOG(("invalid device name")); return EINVAL; } // There can be only one access at time mask = 1L << i; if (atomic_or(&sOpenMask, mask) & mask) return B_BUSY; // Allocate a wb_device structure if (!(data = (wb_device *)malloc(sizeof(wb_device)))) { sOpenMask &= ~(1L << i); return B_NO_MEMORY; } memset(data, 0, sizeof(wb_device)); *cookie = data; #ifdef DEBUG load_driver_symbols("wb840"); #endif data->devId = i; data->pciInfo = gDevList[i]; data->deviceName = gDevNameList[i]; data->blockFlag = 0; data->reg_base = data->pciInfo->u.h0.base_registers[0]; data->wb_cachesize = gPci->read_pci_config(data->pciInfo->bus, data->pciInfo->device, data->pciInfo->function, PCI_line_size, sizeof (PCI_line_size)) & 0xff; wb_read_eeprom(data, &data->MAC_Address, 0, 3, false); status = wb_create_semaphores(data); if (status < B_OK) { LOG((DEVICE_NAME ": Couldn't create semaphores\n")); goto err; } status = wb_stop(data); if (status < B_OK) { LOG((DEVICE_NAME": Can't stop device\n")); goto err1; } status = wb_initPHYs(data); if (status < B_OK) { LOG((DEVICE_NAME": Can't init PHYs\n")); goto err1; } wb_init(data); /* Setup interrupts */ data->irq = data->pciInfo->u.h0.interrupt_line; status = install_io_interrupt_handler(data->irq, wb_interrupt, data, 0); if (status < B_OK) { LOG((DEVICE_NAME " can't install interrupt handler: %s\n", strerror(status))); goto err1; } LOG(("Interrupts installed at irq line %x\n", data->irq)); status = wb_create_rings(data); if (status < B_OK) { LOG((DEVICE_NAME": can't create ring buffers\n")); goto err2; } wb_enable_interrupts(data); WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_RX_ON); write32(data->reg_base + WB_RXSTART, 0xFFFFFFFF); WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_TX_ON); add_timer(&data->timer, wb_tick, 1000000LL, B_PERIODIC_TIMER); return B_OK; // Everything after this line is an error err2: remove_io_interrupt_handler(data->irq, wb_interrupt, data); err1: wb_delete_semaphores(data); err: sOpenMask &= ~(1L << i); free(data); LOG(("wb840: Open Failed\n")); return status; }
static status_t open_hook (const char* name, uint32 flags, void** cookie) { int32 index = 0; device_info *di; shared_info *si; thread_id thid; thread_info thinfo; status_t result = B_OK; vuint32 *regs; char shared_name[B_OS_NAME_LENGTH]; /* find the device name in the list of devices */ /* we're never passed a name we didn't publish */ while (pd->device_names[index] && (strcmp(name, pd->device_names[index]) != 0)) index++; /* for convienience */ di = &(pd->di[index]); /* make sure no one else has write access to the common data */ AQUIRE_BEN(pd->kernel); /* if it's already open for writing */ if (di->is_open) { /* mark it open another time */ goto mark_as_open; } /* create the shared area */ sprintf(shared_name, DEVICE_FORMAT " shared", di->pcii.vendor_id, di->pcii.device_id, di->pcii.bus, di->pcii.device, di->pcii.function); /* create this area with NO user-space read or write permissions, to prevent accidental dammage */ di->shared_area = create_area(shared_name, (void **)&(di->si), B_ANY_KERNEL_ADDRESS, ((sizeof(shared_info) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), B_FULL_LOCK, 0); if (di->shared_area < 0) { /* return the error */ result = di->shared_area; goto done; } /* save a few dereferences */ si = di->si; /* save the vendor and device IDs */ si->vendor_id = di->pcii.vendor_id; si->device_id = di->pcii.device_id; si->revision = di->pcii.revision; si->bus = di->pcii.bus; si->device = di->pcii.device; si->function = di->pcii.function; /* device at bus #0, device #0, function #0 holds byte value at byte-index 0xf6 */ si->ps.chip_rev = ((*pci_bus->read_pci_config)(0, 0, 0, 0xf6, 1)); /* map the device */ result = map_device(di); if (result < 0) goto free_shared; result = B_OK; /* create a semaphore for vertical blank management */ si->vblank = create_sem(0, di->name); if (si->vblank < 0) { result = si->vblank; goto unmap; } /* change the owner of the semaphores to the opener's team */ /* this is required because apps can't aquire kernel semaphores */ thid = find_thread(NULL); get_thread_info(thid, &thinfo); set_sem_owner(si->vblank, thinfo.team); /* assign local regs pointer for SAMPLExx() macros */ regs = di->regs; /* disable and clear any pending interrupts */ disable_vbi(regs); /* If there is a valid interrupt line assigned then set up interrupts */ if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff) || /* no IRQ assigned */ (di->pcii.u.h0.interrupt_line <= 0x02)) /* system IRQ assigned */ { /* we are aborting! */ /* Note: the R4 graphics driver kit lacks this statement!! */ result = B_ERROR; /* interrupt does not exist so exit without installing our handler */ goto delete_the_sem; } else { /* otherwise install our interrupt handler */ result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, eng_interrupt, (void *)di, 0); /* bail if we couldn't install the handler */ if (result != B_OK) goto delete_the_sem; } mark_as_open: /* mark the device open */ di->is_open++; /* send the cookie to the opener */ *cookie = di; goto done; delete_the_sem: delete_sem(si->vblank); unmap: unmap_device(di); free_shared: /* clean up our shared area */ delete_area(di->shared_area); di->shared_area = -1; di->si = NULL; done: /* end of critical section */ RELEASE_BEN(pd->kernel); /* all done, return the status */ return result; }
/* init the adapter... if restarting, no bus reset or whathaveyou */ static long init_symbios(Symbios *s, int restarting) { d_printf("symbios%ld: init_symbios()\n",s->num); if(restarting){ s->reset = 1; } else { s->reset = 0; } if(!restarting){ /* reset the SCSI bus */ dprintf("symbios%ld: scsi bus reset\n",s->num); outb(sym_scntl1, sym_scntl1_rst); spin(25); outb(sym_scntl1, 0); spin(250000); /* clear ints */ inb(sym_istat); inb(sym_sist0); inb(sym_sist1); inb(sym_dstat); install_io_interrupt_handler(s->irq, scsi_int_dispatch, s, 0); d_printf("symbios%ld: registered interrupt handler for irq %ld\n",s->num,s->irq); } /* enable irqs, prefetch, no 53c700 compat */ outb(sym_dcntl, sym_dcntl_com); /* enable all DMA ints */ outb(sym_dien, sym_dien_sir | sym_dien_mdpe | sym_dien_bf | sym_dien_abrt | sym_dien_iid); /* enable all fatal SCSI ints */ outb(sym_sien0, sym_sien0_ma | sym_sien0_sge | sym_sien0_udc | sym_sien0_rst | sym_sien0_par); outb(sym_sien1, sym_sien1_sto | sym_sien1_sbmc); // XXX /* sel / hth timeouts */ outb(sym_stime0, 0xbb); /* clear ints */ inb(sym_istat); inb(sym_sist0); inb(sym_sist1); inb(sym_dstat); /* clear ints */ inb(sym_sist0); inb(sym_sist1); inb(sym_dstat); if(restarting){ s->reset = 0; } else { int i; s->status = TEST; dprintf("symbios%ld: selftest ",s->num); out32(sym_dsp, LE(s->sram_phys + Ent_test)); for(i=0;(s->status == TEST) && i<10;i++) { dprintf("."); spin(10000); } if(s->status == TEST){ dprintf("FAIL\n"); return B_ERROR; //XXX teardown } else { dprintf("PASS\n"); } } s->status = IDLE; out32(sym_dsp, LE(s->sram_phys + Ent_idle)); d_printf("symbios%ld: started script\n",s->num); return B_NO_ERROR; }
static status_t et6000OpenHook(const char* name, uint32 flags, void** cookie) { int32 index = 0; ET6000DeviceInfo *di; ET6000SharedInfo *si; status_t result = B_OK; char shared_name[B_OS_NAME_LENGTH]; ddprintf(("SKD et6000OpenHook(%s, %ld, 0x%08lx)\n", name, flags, (uint32)cookie)); /* find the device name in the list of devices */ /* we're never passed a name we didn't publish */ while(pd->deviceNames[index] && (strcmp(name, pd->deviceNames[index]) != 0)) { index++; } /* for convienience */ di = &(pd->di[index]); /* make sure no one else has write access to the common data */ AQUIRE_BEN(pd->kernel); /* if it's already open for writing */ if (di->isOpen) { /* mark it open another time */ goto mark_as_open; } /* create the shared area */ sprintf(shared_name, "%04X_%04X_%02X%02X%02X shared", di->pcii.vendor_id, di->pcii.device_id, di->pcii.bus, di->pcii.device, di->pcii.function); /* create this area with NO user-space read or write permissions, to prevent accidental dammage */ di->sharedArea = create_area(shared_name, (void **)&(di->si), B_ANY_KERNEL_ADDRESS, ((sizeof(ET6000SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), B_FULL_LOCK, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA); if (di->sharedArea < 0) { /* return the error */ result = di->sharedArea; goto done; } /* save a few dereferences */ si = di->si; /* save the vendor and device IDs */ si->vendor_id = di->pcii.vendor_id; si->device_id = di->pcii.device_id; si->revision = di->pcii.revision; si->pixelClockMax16 = 135000; si->pixelClockMax24 = 135000; if (si->vendor_id == 0x100C) { /* Tseng Labs, Inc. */ switch (si->device_id) { case 0x3208:/* ET6000/ET6100 */ if (si->revision < 0x70) { /* ET6000 */ si->pixelClockMax16 = 135000; si->pixelClockMax24 = 135000; } else { /* ET6100 */ si->pixelClockMax16 = 175000; si->pixelClockMax24 = 175000; } break; case 0x4702: /* ET6300 */ si->pixelClockMax16 = 220000; si->pixelClockMax24 = 220000; break; } } /* map the device */ result = et6000MapDevice(di); if (result < 0) goto free_shared; result = B_OK; /* * Clear any pending interrupts and disable interrupts. Driver * currently does not use interrupts and unlikely will in future. */ et6000aclReadInterruptClear(si->mmRegs); et6000aclWriteInterruptClear(si->mmRegs); et6000aclMasterInterruptDisable(si->mmRegs); /* Install the interrupt handler */ result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, et6000Interrupt, (void *)di, 0); /* bail if we couldn't install the handler */ if (result != B_OK) goto unmap; mark_as_open: /* mark the device open */ di->isOpen++; /* send the cookie to the opener */ *cookie = di; goto done; unmap: et6000UnmapDevice(di); free_shared: /* clean up our shared area */ delete_area(di->sharedArea); di->sharedArea = -1; di->si = NULL; done: /* end of critical section */ RELEASE_BEN(pd->kernel); /* all done, return the status */ ddprintf(("et6000OpenHook returning 0x%08lx\n", result)); return result; }