123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- /*
- * video.c
- *
- * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <video.h>
- #include <exception.h>
- #include <pci.h>
- #include <heap.h>
- #include <memory.h>
- #include <process.h>
- #include <syscalls.h>
- static dword_t video_device_init(void);
- static dword_t video_device_cleanup(void);
- static dword_t video_device_read_write(device_t *device, void *buffer, size_t length, size_t *bytes_read);
- static dword_t video_device_ioctl(device_t *device, dword_t control_code, const void *in_buffer, size_t in_length, void *out_buffer, size_t out_length);
- static dword_t video_default_init(list_entry_t *video_devices);
- static dword_t video_default_cleanup(void);
- static char_dev_driver_t video_subsystem =
- {
- .init_proc = video_device_init,
- .cleanup_proc = video_device_cleanup,
- .read_proc = (char_dev_read_proc_t)video_device_read_write,
- .write_proc = (char_dev_write_proc_t)video_device_read_write,
- .ioctl_proc = video_device_ioctl,
- };
- static video_driver_t video_default_driver =
- {
- .init_proc = video_default_init,
- .cleanup_proc = video_default_cleanup,
- .control_proc = video_default_control,
- };
- static DECLARE_LIST(video_devices);
- static dword_t video_default_bitblt(video_device_t *device, video_bitblt_parameters_t *parameters)
- {
- dword_t i, j;
- dword_t *framebuffer;
- video_map_framebuffer_t map;
- if (device->current_mode.bpp > 32) return ERR_INVALID;
- dword_t top_x = MIN(parameters->source_x, parameters->dest_x);
- dword_t top_y = MIN(parameters->source_y, parameters->dest_y);
- dword_t bottom_x = MAX(parameters->source_x, parameters->dest_x);
- dword_t bottom_y = MAX(parameters->source_y, parameters->dest_y);
- map.address = NULL;
- map.offset = top_y * device->current_mode.scanline_size + ((top_x * device->current_mode.bpp) >> 3);
- map.size = (bottom_y * device->current_mode.scanline_size + ((bottom_x * device->current_mode.bpp + 7) >> 3)) - map.offset;
- processor_mode_t old_previous_mode = get_current_thread()->previous_mode;
- get_current_thread()->previous_mode = KERNEL_MODE;
- dword_t ret = device->driver->control_proc(device, IOCTL_VIDEO_MAP_FRAMEBUFFER, &map, sizeof(map), &framebuffer, sizeof(framebuffer));
- get_current_thread()->previous_mode = old_previous_mode;
- if (ret != ERR_SUCCESS) return ret;
- for (i = 0; i < parameters->height; i++)
- {
- dword_t sp_y = parameters->source_y >= parameters->dest_y ? i : parameters->height - i - 1;
- dword_t dp_y = sp_y + parameters->dest_y - parameters->source_y;
- for (j = 0; j < parameters->width; j++)
- {
- dword_t sp_x = parameters->source_x >= parameters->dest_x ? j : parameters->width - j - 1;
- dword_t dp_x = sp_x + parameters->dest_x - parameters->source_x;
- dword_t source_pixel = 0;
- dword_t dest_pixel = 0;
- uintptr_t source_offset = (sp_y * device->current_mode.scanline_size << 3) + sp_x * device->current_mode.bpp - (map.offset << 3);
- uintptr_t dest_offset = (dp_y * device->current_mode.scanline_size << 3) + dp_x * device->current_mode.bpp - (map.offset << 3);
- qword_t mask = ((qword_t)((1 << device->current_mode.bpp) - 1)) << (source_offset & 0x1F);
- dword_t low_mask = (dword_t)mask;
- dword_t high_mask = (dword_t)(mask >> 32);
- if (parameters->operation & BITBLT_SOURCE_ENABLED)
- {
- source_pixel = framebuffer[source_offset >> 5] >> (source_offset & 0x1F);
- if (high_mask) source_pixel |= framebuffer[(source_offset >> 5) + 1] << ((-dest_offset) & 0x1F);
- source_pixel &= (1 << device->current_mode.bpp) - 1;
- }
- if (parameters->operation & BITBLT_DEST_ENABLED)
- {
- dest_pixel = framebuffer[dest_offset >> 5] >> (dest_offset & 0x1F);
- if (high_mask) dest_pixel |= framebuffer[(dest_offset >> 5) + 1] << ((-dest_offset) & 0x1F);
- dest_pixel &= (1 << device->current_mode.bpp) - 1;
- }
- if (parameters->operation & BITBLT_SOURCE_INVERT) source_pixel = ~source_pixel;
- if (parameters->operation & BITBLT_DEST_INVERT) dest_pixel = ~dest_pixel;
- switch (parameters->operation & 3)
- {
- case BITBLT_OPERATION_NONE:
- dest_pixel = source_pixel;
- break;
- case BITBLT_OPERATION_AND:
- dest_pixel &= source_pixel;
- break;
- case BITBLT_OPERATION_OR:
- dest_pixel |= source_pixel;
- break;
- case BITBLT_OPERATION_XOR:
- dest_pixel ^= source_pixel;
- break;
- }
- if (parameters->operation & BITBLT_RESULT_INVERT) dest_pixel = ~dest_pixel;
- framebuffer[dest_offset >> 5] = (framebuffer[dest_offset >> 5] & ~low_mask) | (dest_pixel << (dest_offset & 0x1F));
- if (high_mask)
- {
- framebuffer[(dest_offset >> 5) + 1] = (framebuffer[(dest_offset >> 5) + 1] & ~high_mask) | (dest_pixel >> ((-dest_offset) & 0x1F));
- }
- }
- }
- unmap_memory(framebuffer);
- return ERR_SUCCESS;
- }
- static dword_t video_device_init(void)
- {
- list_entry_t *pci_device_list = get_pci_device_list_head();
- list_entry_t *ptr;
- int number = 0;
- for (ptr = pci_device_list->next; ptr != pci_device_list; ptr = ptr->next)
- {
- pci_device_t *device = CONTAINER_OF(ptr, pci_device_t, list);
- if (device->class == PCI_DISPLAY_DEVICE)
- {
- video_device_t *video = (video_device_t*)malloc(sizeof(video_device_t));
- ASSERT(video != NULL);
- video->header.driver = &video_subsystem;
- sprintf(video->header.name, "Video%d", number);
- video->header.resource = 0;
- video->pci_device = device;
- video->driver = &video_default_driver;
- memset(&video->current_mode, 0, sizeof(video->current_mode));
- video->current_mode.number = 3;
- video->current_mode.flags = VIDEO_MODE_ALPHANUMERIC | VIDEO_MODE_USES_PALETTE;
- video->current_mode.width = TEXT_WIDTH;
- video->current_mode.height = TEXT_HEIGHT;
- video->current_mode.bpp = 16;
- video->current_mode.scanline_size = TEXT_WIDTH * 2;
- video->current_mode.framebuffer_phys = TEXT_VIDEO_MEMORY;
- dword_t ret = register_char_device(&video->header);
- ASSERT(ret == ERR_SUCCESS);
- list_append(&video_devices, &video->list);
- number++;
- }
- }
- return ERR_SUCCESS;
- }
- static dword_t video_device_cleanup(void)
- {
- return ERR_SUCCESS;
- }
- static dword_t video_device_read_write(device_t *device, void *buffer, size_t length, size_t *bytes_read)
- {
- return ERR_INVALID;
- }
- static dword_t video_device_ioctl(device_t *device,
- dword_t control_code,
- const void *in_buffer,
- size_t in_length,
- void *out_buffer,
- size_t out_length)
- {
- video_device_t *video = CONTAINER_OF(device, video_device_t, header);
- return video->driver->control_proc(video, control_code, in_buffer, in_length, out_buffer, out_length);
- }
- static dword_t video_default_init(list_entry_t *video_devices)
- {
- UNUSED_PARAMETER(video_devices);
- return ERR_SUCCESS;
- }
- static dword_t video_default_cleanup(void)
- {
- return ERR_SUCCESS;
- }
- dword_t video_default_control(video_device_t *device,
- dword_t control_code,
- const void *in_buffer,
- size_t in_length,
- void *out_buffer,
- size_t out_length)
- {
- switch (control_code)
- {
- case IOCTL_VIDEO_GET_MODE:
- if (out_length >= sizeof(video_mode_t))
- {
- *(video_mode_t*)out_buffer = device->current_mode;
- return ERR_SUCCESS;
- }
- else
- {
- return ERR_SMALLBUF;
- }
- case IOCTL_VIDEO_SET_MODE:
- if (in_length >= sizeof(dword_t))
- {
- return (*(dword_t*)in_buffer == device->current_mode.number) ? ERR_SUCCESS : ERR_INVALID;
- }
- else
- {
- return ERR_SMALLBUF;
- }
- case IOCTL_VIDEO_LIST_MODES:
- if (out_length >= sizeof(dword_t))
- {
- dword_t *list = (dword_t*)out_buffer;
- list[0] = 1;
- if (out_length >= 2 * sizeof(dword_t))
- {
- list[1] = device->current_mode.number;
- return ERR_SUCCESS;
- }
- else
- {
- return ERR_SMALLBUF;
- }
- }
- else
- {
- return ERR_SMALLBUF;
- }
- case IOCTL_VIDEO_QUERY_MODE:
- if (in_length >= sizeof(dword_t) && out_length >= sizeof(video_mode_t))
- {
- if (*(dword_t*)in_buffer != device->current_mode.number) return ERR_INVALID;
- *(video_mode_t*)out_buffer = device->current_mode;
- return ERR_SUCCESS;
- }
- else
- {
- return ERR_SMALLBUF;
- }
- case IOCTL_VIDEO_MAP_FRAMEBUFFER:
- if (in_length >= sizeof(video_map_framebuffer_t) && out_length >= sizeof(void*))
- {
- video_map_framebuffer_t *params = (video_map_framebuffer_t*)in_buffer;
- void *address = params->address;
- dword_t size = device->current_mode.height * device->current_mode.scanline_size * (device->current_mode.bpp >> 3);
- if (params->offset >= size || params->size >= size || (params->offset + params->size) > size)
- {
- return ERR_INVALID;
- }
- if (get_previous_mode() == USER_MODE)
- {
- dword_t ret = map_memory_in_address_space(&get_current_process()->memory_space,
- (void*)(device->current_mode.framebuffer_phys + params->offset),
- &address,
- params->size,
- MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_WRITABLE | MEMORY_BLOCK_USERMODE);
- if (ret != ERR_SUCCESS) return ret;
- }
- else
- {
- dword_t ret = map_memory((void*)(device->current_mode.framebuffer_phys + params->offset),
- &address,
- params->size,
- MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_WRITABLE);
- if (ret != ERR_SUCCESS) return ret;
- }
- *(void**)out_buffer = address;
- return ERR_SUCCESS;
- }
- else
- {
- return ERR_SMALLBUF;
- }
- case IOCTL_VIDEO_BITBLT:
- if (in_length >= sizeof(video_bitblt_parameters_t))
- {
- return video_default_bitblt(device, (video_bitblt_parameters_t*)in_buffer);
- }
- else
- {
- return ERR_SMALLBUF;
- }
- case IOCTL_VIDEO_READ_PALETTE:
- case IOCTL_VIDEO_WRITE_PALETTE:
- case IOCTL_VIDEO_READ_FONT:
- case IOCTL_VIDEO_WRITE_FONT:
- return ERR_NOSYSCALL; // TODO
- case IOCTL_VIDEO_SET_TEXT_CURSOR:
- if (in_length >= sizeof(video_cursor_location_t))
- {
- video_cursor_location_t *location = (video_cursor_location_t*)in_buffer;
- word_t index = location->row * TEXT_WIDTH + location->column;
- outportb(VGA_CRTC_INDEX, 0x0F);
- outportb(VGA_CRTC_DATA, (byte_t) (index & 0xFF));
- outportb(VGA_CRTC_INDEX, 0x0E);
- outportb(VGA_CRTC_DATA, (byte_t) ((index >> 8) & 0xFF));
- }
- else
- {
- return ERR_SMALLBUF;
- }
- default:
- return ERR_INVALID;
- }
- }
- dword_t register_video_driver(video_driver_t *driver)
- {
- dword_t ret = driver->init_proc(&video_devices);
- return ret;
- }
- dword_t unregister_video_driver(video_driver_t *driver)
- {
- driver->cleanup_proc();
- return ERR_SUCCESS;
- }
- void video_init()
- {
- dword_t ret = register_char_dev_driver(&video_subsystem);
- ASSERT(ret == ERR_SUCCESS);
- video_map_framebuffer_t params = {
- .address = (void*)VIDEO_MEMORY,
- .offset = 0,
- .size = TEXT_WIDTH * TEXT_HEIGHT * 2
- };
- void *address;
- handle_t handle;
- ASSERT(get_previous_mode() == KERNEL_MODE);
- ret = syscall_open_file("CharDevices/Video0", &handle, 0, 0);
- ASSERT(ret == ERR_SUCCESS);
- ret = syscall_device_ioctl(handle, IOCTL_VIDEO_MAP_FRAMEBUFFER, ¶ms, sizeof(params), &address, sizeof(address));
- ASSERT(ret == ERR_SUCCESS);
- syscall_close_object(handle);
- }
|