diff options
-rw-r--r-- | char.c | 139 | ||||
-rw-r--r-- | harddoomdev.c | 45 | ||||
-rw-r--r-- | harddoomdev.h | 2 | ||||
-rw-r--r-- | private_data.h | 13 | ||||
-rw-r--r-- | surface.c | 43 |
5 files changed, 240 insertions, 2 deletions
@@ -1,10 +1,13 @@ #include "char.h" +#include <linux/anon_inodes.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/fs.h> +#include <asm/uaccess.h> #include "doomdev.h" +#include "harddoom.h" #include "util.h" #include "pci.h" #include "surface.h" @@ -24,9 +27,143 @@ long doom_create_surface(struct file *filp, unsigned long arg) return new_surface(filp, params); } +void free_texture(struct texture_data *texture_data); +int texture_release(struct inode *inode, struct file *filp) +{ + struct texture_data *texture_data; + + texture_data = filp->private_data; + + free_texture(texture_data); + + kfree(texture_data); + + return 0; +} + +struct file_operations texture_fops = { + .owner = THIS_MODULE, + .release = texture_release + +}; + +int verify_texture_params(struct doomdev_ioctl_create_texture *params) +{ + if (params->size > 4 * 1024 * 1024) { + return -EOVERFLOW; + } + + if (params->height > 1023) { + return -EOVERFLOW; + } + + return 0; +} + +int alloc_texture(struct doomdev_ioctl_create_texture *params, + struct texture_data *texture_data) +{ + int err; + int i; + int not_written; + int pages_needed; + + texture_data->size = params->size; + texture_data->height = params->height; + + pages_needed = (params->size / HARDDOOM_PAGE_SIZE); + if (params->size % HARDDOOM_PAGE_SIZE != 0) { + pages_needed += 1; + } + + texture_data->pages = pages_needed; + texture_data->texture_cpu = + dma_alloc_coherent(texture_data->doom_data->pci_device, + params->size, &texture_data->texture_dev, + GFP_KERNEL); + ORFAIL_NULL(texture_data->texture_cpu, -ENOMEM, error_texture); + + texture_data->page_table_cpu = + dma_alloc_coherent(texture_data->doom_data->pci_device, + pages_needed * 4, &texture_data->page_table_dev, + GFP_KERNEL); + ORFAIL_NULL(texture_data->page_table_cpu, -ENOMEM, error_pt); + + for (i = 0; i < pages_needed; i++) { + texture_data->page_table_cpu[i] = + (HARDDOOM_PTE_PHYS_MASK & + (texture_data->texture_dev + HARDDOOM_PAGE_SIZE * i)) | + HARDDOOM_PTE_VALID; + } + + not_written = copy_from_user(texture_data->texture_cpu, + (void __user *) params->data_ptr, + params->size); + + + if (not_written) { + err = -EFAULT; + goto error_copy; + } + + return 0; + +error_copy: + dma_free_coherent(texture_data->doom_data->pci_device, + texture_data->pages * 4, texture_data->page_table_cpu, + texture_data->page_table_dev); +error_pt: + dma_free_coherent(texture_data->doom_data->pci_device, + texture_data->size, texture_data->texture_cpu, + texture_data->texture_dev); +error_texture: + return err; +} + +void free_texture(struct texture_data *texture_data) +{ + dma_free_coherent(texture_data->doom_data->pci_device, + texture_data->pages * 4, texture_data->page_table_cpu, + texture_data->page_table_dev); + + dma_free_coherent(texture_data->doom_data->pci_device, + texture_data->size, texture_data->texture_cpu, + texture_data->texture_dev); +} + long doom_create_texture(struct file *filp, unsigned long arg) { - return -1; + int err; + struct doomdev_ioctl_create_texture *params; + struct texture_data *texture_data; + int fd; + struct doom_data *doom_data; + + params = (struct doomdev_ioctl_create_texture *) arg; + + err = verify_texture_params(params); + if (err < 0) { + return err; + } + + texture_data = kmalloc(sizeof(*texture_data), GFP_KERNEL); + ORFAIL_NULL(texture_data, -ENOMEM, error_data); + doom_data = container_of(filp->f_inode->i_cdev, struct doom_data, cdev); + texture_data->doom_data = doom_data; + + ORFAIL(alloc_texture(params, texture_data), error_texture); + + fd = anon_inode_getfd("doom_texture", &texture_fops, texture_data, 0); + ORFAIL(fd, error_inode); + + return fd; + +error_inode: + free_texture(texture_data); +error_texture: + kfree(texture_data); +error_data: + return err; } long doom_create_flat(struct file *filp, unsigned long arg) diff --git a/harddoomdev.c b/harddoomdev.c index 38c32dd..823e868 100644 --- a/harddoomdev.c +++ b/harddoomdev.c @@ -73,6 +73,31 @@ void set_fill_color(void __iomem *iomem, uint8_t color) send_command(iomem, HARDDOOM_CMD_FILL_COLOR(color)); } +void set_texture_pt(void __iomem *iomem, dma_addr_t page_table_dev) +{ + send_command(iomem, HARDDOOM_CMD_TEXTURE_PT(page_table_dev)); +} + +void set_texture_dims(void __iomem *iomem, uint32_t size, uint16_t height) +{ + send_command(iomem, HARDDOOM_CMD_TEXTURE_DIMS(size,height)); +} + +void set_ustart(void __iomem *iomem, uint32_t ustart) +{ + send_command(iomem, HARDDOOM_CMD_USTART(ustart)); +} + +void set_ustep(void __iomem *iomem, uint32_t ustep) +{ + send_command(iomem, HARDDOOM_CMD_USTEP(ustep)); +} + +void set_draw_params(void __iomem *iomem, uint8_t flags) +{ + send_command(iomem, HARDDOOM_CMD_DRAW_PARAMS(flags)); +} + void fill_rect(struct surface_data *surface_data, struct doomdev_fill_rect rect) { void __iomem *iomem; @@ -118,6 +143,26 @@ void copy_rect(struct surface_data *dst_data, struct surface_data *src_data, send_command(iomem, HARDDOOM_CMD_COPY_RECT(rect.width, rect.height)); } +void draw_column(struct surface_data *surface_data, + struct texture_data *texture_data, struct doomdev_column column) +{ + void __iomem *iomem; + + iomem = surface_data->doom_data->iomem; + + set_surf_dst_pt(iomem, surface_data->page_table_dev); + set_surf_dims(iomem, surface_data->width, surface_data->height); + set_texture_pt(iomem, texture_data->page_table_dev); + set_texture_dims(iomem, texture_data->size, texture_data->height); + set_xy_a(iomem, column.x, column.y1); + set_xy_b(iomem, column.x, column.y2); + set_ustart(iomem, column.ustart); + set_ustep(iomem, column.ustep); + set_draw_params(iomem, 0); + + send_command(iomem, HARDDOOM_CMD_DRAW_COLUMN(column.texture_offset)); +} + uint32_t doomdev_read_stat(void __iomem *iomem, size_t stat) { return doomdev_read(iomem, HARDDOOM_STATS(stat)); diff --git a/harddoomdev.h b/harddoomdev.h index 2c956f2..929d5f2 100644 --- a/harddoomdev.h +++ b/harddoomdev.h @@ -17,5 +17,7 @@ void draw_line(struct surface_data *surface_data, struct doomdev_line line); void fill_rect(struct surface_data *surface_data, struct doomdev_fill_rect rect); void copy_rect(struct surface_data *dst_data, struct surface_data *src_data, struct doomdev_copy_rect rect); +void draw_column(struct surface_data *surface_data, + struct texture_data *texture_data, struct doomdev_column column); #endif diff --git a/private_data.h b/private_data.h index 0325b93..ae1bf3e 100644 --- a/private_data.h +++ b/private_data.h @@ -29,4 +29,17 @@ struct surface_data { dma_addr_t page_table_dev; }; +struct texture_data { + struct doom_data *doom_data; + + uint32_t size; + uint16_t height; + int pages; + + uint8_t *texture_cpu; + uint32_t *page_table_cpu; + dma_addr_t texture_dev; + dma_addr_t page_table_dev; +}; + #endif @@ -89,6 +89,45 @@ long copy_rects(struct file *filp, unsigned long arg) return param->rects_num; } +long draw_columns(struct file *filp, unsigned long arg) +{ + struct doomdev_surf_ioctl_draw_columns *param; + struct surface_data *surface_data; + struct texture_data *texture_data; + struct doomdev_column *columns; + struct fd texture_fds; + int i; + + surface_data = filp->private_data; + + param = (struct doomdev_surf_ioctl_draw_columns *) arg; + + // temp + if (param->draw_flags & DOOMDEV_DRAW_FLAGS_FUZZ) { + return 0x400; + } + + texture_fds = fdget(param->texture_fd); + texture_data = texture_fds.file->private_data; + + if (surface_data->doom_data != texture_data->doom_data) { + p("texture from different device\n"); + return -EINVAL; + } + + columns = (struct doomdev_column *) param->columns_ptr; + + mutex_lock(&surface_data->doom_data->cmd_mutex); + + for (i = 0; i < param->columns_num; i++) { + draw_column(surface_data, texture_data, columns[i]); + } + + mutex_unlock(&surface_data->doom_data->cmd_mutex); + + return param->columns_num; +} + long surface_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch (cmd) { @@ -98,6 +137,8 @@ long surface_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return fill_rects(filp, arg); case DOOMDEV_SURF_IOCTL_COPY_RECTS: return copy_rects(filp, arg); + case DOOMDEV_SURF_IOCTL_DRAW_COLUMNS: + return draw_columns(filp, arg); default: return -1; } @@ -165,7 +206,7 @@ loff_t surface_llseek(struct file *filp, loff_t offset, int origin) void free_surface_buffer(struct surface_data *surface_data); -int surface_release (struct inode *inode, struct file *filp) +int surface_release(struct inode *inode, struct file *filp) { struct surface_data *surface_data; |