m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2018-05-23 21:24:03 +0200
committerMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2018-05-24 21:34:12 +0200
commita2d05131f0515e5c53c12c26549f5be2ef7777e7 (patch)
tree99975f24a558e336fc627c66477754ec8f8adfe2
parente743a0a252f46dc2e19102b39d3058750a0b1bdb (diff)
Implement draw columns
-rw-r--r--char.c139
-rw-r--r--harddoomdev.c45
-rw-r--r--harddoomdev.h2
-rw-r--r--private_data.h13
-rw-r--r--surface.c43
5 files changed, 240 insertions, 2 deletions
diff --git a/char.c b/char.c
index a4ba095..54fd8a3 100644
--- a/char.c
+++ b/char.c
@@ -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
diff --git a/surface.c b/surface.c
index bb6766f..a54ca6f 100644
--- a/surface.c
+++ b/surface.c
@@ -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;