static status_t device_ioctl(void* dev, uint32 msg, void* buffer, size_t bufferLength) { DeviceInfo& di = *((DeviceInfo*)dev); // TRACE("device_ioctl(); ioctl: %lu, buffer: 0x%08lx, bufLen: %lu\n", msg, // (uint32)buffer, bufferLength); switch (msg) { case B_GET_ACCELERANT_SIGNATURE: strcpy((char*)buffer, ATI_ACCELERANT_NAME); return B_OK; case ATI_DEVICE_NAME: strncpy((char*)buffer, di.name, B_OS_NAME_LENGTH); ((char*)buffer)[B_OS_NAME_LENGTH -1] = '\0'; return B_OK; case ATI_GET_SHARED_DATA: if (bufferLength != sizeof(area_id)) return B_BAD_DATA; *((area_id*)buffer) = di.sharedArea; return B_OK; case ATI_GET_EDID: { if (bufferLength != sizeof(edid1_raw)) return B_BAD_DATA; edid1_raw rawEdid; status_t status = GetEdidFromBIOS(rawEdid); if (status == B_OK) user_memcpy((edid1_raw*)buffer, &rawEdid, sizeof(rawEdid)); return status; } case ATI_SET_VESA_DISPLAY_MODE: if (bufferLength != sizeof(uint16)) return B_BAD_DATA; return SetVesaDisplayMode(*((uint16*)buffer)); case ATI_RUN_INTERRUPTS: if (bufferLength != sizeof(bool)) return B_BAD_DATA; if (*((bool*)buffer)) EnableVBI(); else DisableVBI(); return B_OK; } return B_DEV_INVALID_IOCTL; }
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; } }
static status_t device_free(void* dev) { DeviceInfo& di = *((DeviceInfo*)dev); SharedInfo& si = *(di.sharedInfo); pci_info& pciInfo = di.pciInfo; TRACE("enter device_free()\n"); gLock.Acquire(); // lock driver // If opened multiple times, merely decrement the open count and exit. if (di.openCount <= 1) { DisableVBI(); // disable & clear any pending interrupts if (si.bInterruptAssigned) { remove_io_interrupt_handler(pciInfo.u.h0.interrupt_line, InterruptHandler, &di); } // Delete the semaphores, ignoring any errors because the owning team // may have died. if (si.vertBlankSem >= 0) delete_sem(si.vertBlankSem); si.vertBlankSem = -1; UnmapDevice(di); // free regs and frame buffer areas delete_area(di.sharedArea); di.sharedArea = -1; di.sharedInfo = NULL; } if (di.openCount > 0) di.openCount--; // mark device available gLock.Release(); // unlock driver TRACE("exit device_free() openCount: %ld\n", di.openCount); return B_OK; }
static status_t device_ioctl(void* dev, uint32 msg, void* buf, size_t len) { DeviceInfo& di = *((DeviceInfo*)dev); (void)len; // avoid compiler warning for unused arg // TRACE("device_ioctl(); ioctl: %lu, buf: 0x%08lx, len: %lu\n", msg, (uint32)buf, len); switch (msg) { case B_GET_ACCELERANT_SIGNATURE: strcpy((char*)buf, "s3.accelerant"); return B_OK; case S3_DEVICE_NAME: strncpy((char*)buf, di.name, B_OS_NAME_LENGTH); ((char*)buf)[B_OS_NAME_LENGTH -1] = '\0'; return B_OK; case S3_GET_PRIVATE_DATA: { S3GetPrivateData* gpd = (S3GetPrivateData*)buf; if (gpd->magic == S3_PRIVATE_DATA_MAGIC) { gpd->sharedInfoArea = di.sharedArea; return B_OK; } break; } case S3_GET_EDID: { #ifdef __HAIKU__ S3GetEDID* ged = (S3GetEDID*)buf; if (ged->magic == S3_PRIVATE_DATA_MAGIC) { edid1_raw rawEdid; status_t status = GetEdidFromBIOS(rawEdid); if (status == B_OK) user_memcpy(&ged->rawEdid, &rawEdid, sizeof(rawEdid)); return status; } #else return B_UNSUPPORTED; #endif break; } case S3_GET_PIO: { S3GetSetPIO* gsp = (S3GetSetPIO*)buf; if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { switch (gsp->size) { case 1: gsp->value = gPCI->read_io_8(gsp->offset); break; case 2: gsp->value = gPCI->read_io_16(gsp->offset); break; case 4: gsp->value = gPCI->read_io_32(gsp->offset); break; default: TRACE("device_ioctl() S3_GET_PIO invalid size: %ld\n", gsp->size); return B_ERROR; } return B_OK; } break; } case S3_SET_PIO: { S3GetSetPIO* gsp = (S3GetSetPIO*)buf; if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { switch (gsp->size) { case 1: gPCI->write_io_8(gsp->offset, gsp->value); break; case 2: gPCI->write_io_16(gsp->offset, gsp->value); break; case 4: gPCI->write_io_32(gsp->offset, gsp->value); break; default: TRACE("device_ioctl() S3_SET_PIO invalid size: %ld\n", gsp->size); return B_ERROR; } return B_OK; } break; } case S3_RUN_INTERRUPTS: { S3SetBoolState* ri = (S3SetBoolState*)buf; if (ri->magic == S3_PRIVATE_DATA_MAGIC) { if (ri->bEnable) EnableVBI(); else DisableVBI(); } return B_OK; } } return B_DEV_INVALID_IOCTL; }