m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2018-05-23 00:17:27 +0200
committerMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2018-05-23 00:19:16 +0200
commit962a5da1e9e7e3c3a0966720c0484308077918b7 (patch)
tree1f799e5ac67feb3c07508a05ccfcc9240ea6e0f5
parent42dc62e5db80994c51e0e62d6c264ce71c655c58 (diff)
Implement draw lines ioctl
-rw-r--r--surface.c97
1 files changed, 84 insertions, 13 deletions
diff --git a/surface.c b/surface.c
index fd5d37b..87304ab 100644
--- a/surface.c
+++ b/surface.c
@@ -9,10 +9,38 @@
#include "harddoom.h"
#include "surface.h"
#include "util.h"
+#include "harddoomdev.h"
+
+long draw_lines(struct file *filp, unsigned long arg)
+{
+ struct surface_data *surface_data;
+ struct doomdev_surf_ioctl_draw_lines *param;
+ struct doomdev_line *lines;
+ int i;
+
+ surface_data = filp->private_data;
+ param = (struct doomdev_surf_ioctl_draw_lines *) arg;
+ lines = (struct doomdev_line *) param->lines_ptr;
+
+ mutex_lock(&surface_data->doom_data->mutex);
+
+ for (i = 0; i < param->lines_num; i++) {
+ draw_line(surface_data, lines[i]);
+ }
+
+ mutex_unlock(&surface_data->doom_data->mutex);
+
+ return param->lines_num;
+}
long surface_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- return -1;
+ switch (cmd) {
+ case DOOMDEV_SURF_IOCTL_DRAW_LINES:
+ return draw_lines(filp, arg);
+ default:
+ return -1;
+ }
}
ssize_t surface_read(struct file *filp, char __user *buf, size_t count,
@@ -21,8 +49,8 @@ ssize_t surface_read(struct file *filp, char __user *buf, size_t count,
struct surface_data *surface_data;
unsigned long not_written;
- surface_data = filp->private_data;
- if (*offset >= surface_data->surface_size) {
+ surface_data = (struct surface_data *) filp->private_data;
+ if (*offset >= surface_data->surface_size || *offset < 0) {
return 0;
}
@@ -30,15 +58,49 @@ ssize_t surface_read(struct file *filp, char __user *buf, size_t count,
count = surface_data->surface_size - *offset;
}
- not_written = copy_to_user(buf, surface_data->surface_cpu + *offset,
+ mutex_lock(&surface_data->doom_data->mutex);
+ ping_sync(surface_data->doom_data->iomem);
+
+ down(&surface_data->doom_data->pong_sem);
+
+ not_written = copy_to_user(buf, surface_data->surface_cpu + (*offset),
count);
+ *offset += count - not_written;
+
+ mutex_unlock(&surface_data->doom_data->mutex);
+
return count - not_written;
}
loff_t surface_llseek(struct file *filp, loff_t offset, int origin)
{
- return -1;
+ struct surface_data *surface_data;
+ loff_t new_pos;
+
+ surface_data = filp->private_data;
+
+ switch (origin) {
+ case SEEK_SET:
+ new_pos = offset;
+ break;
+ case SEEK_CUR:
+ new_pos = filp->f_pos + offset;
+ break;
+ case SEEK_END:
+ new_pos = surface_data->surface_size + offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (new_pos < 0) {
+ return -EINVAL;
+ }
+
+ filp->f_pos = new_pos;
+
+ return new_pos;
}
void free_surface_buffer(struct surface_data *surface_data);
@@ -51,6 +113,8 @@ int surface_release (struct inode *inode, struct file *filp)
free_surface_buffer(surface_data);
+ kfree(surface_data);
+
return 0;
}
@@ -99,6 +163,8 @@ int alloc_surface_buffer(struct doomdev_ioctl_create_surface *params,
bytes_needed = params->width * params->height;
surface_data->surface_size = bytes_needed;
+ surface_data->width = params->width;
+ surface_data->height = params->height;
pages_needed = (bytes_needed / HARDDOOM_PAGE_SIZE);
if (bytes_needed % HARDDOOM_PAGE_SIZE != 0) {
pages_needed += 1;
@@ -109,16 +175,18 @@ int alloc_surface_buffer(struct doomdev_ioctl_create_surface *params,
}
surface_data->pages = pages_needed;
- bytes_needed += pages_needed * 4;
surface_data->surface_cpu =
dma_alloc_coherent(surface_data->doom_data->pci_device,
bytes_needed, &surface_data->surface_dev, GFP_KERNEL);
+
ORFAIL_NULL(surface_data->surface_cpu, -ENOMEM, error_pt);
- surface_data->page_table_cpu = (uint32_t *) (surface_data->surface_cpu +
- HARDDOOM_PAGE_SIZE * pages_needed);
- surface_data->page_table_dev = surface_data->surface_dev +
- HARDDOOM_PAGE_SIZE * pages_needed;
+
+ surface_data->page_table_cpu =
+ dma_alloc_coherent(surface_data->doom_data->pci_device,
+ pages_needed * 4, &surface_data->page_table_dev, GFP_KERNEL);
+
+ ORFAIL_NULL(surface_data->page_table_cpu, -ENOMEM, error_pt);
for (i = 0; i < pages_needed; i++) {
surface_data->page_table_cpu[i] =
@@ -136,8 +204,12 @@ error_pt:
void free_surface_buffer(struct surface_data *surface_data)
{
dma_free_coherent(surface_data->doom_data->device,
- surface_data->surface_size + 4 * surface_data->pages,
+ surface_data->surface_size,
surface_data->surface_cpu, surface_data->surface_dev);
+
+ dma_free_coherent(surface_data->doom_data->device,
+ surface_data->pages,
+ surface_data->page_table_cpu, surface_data->page_table_dev);
}
int new_surface(struct file *filp, struct doomdev_ioctl_create_surface *params)
@@ -160,14 +232,13 @@ int new_surface(struct file *filp, struct doomdev_ioctl_create_surface *params)
ORFAIL(alloc_surface_buffer(params, surface_data), error_buffer);
- fd = anon_inode_getfd("doom_surface", &surface_fops, NULL, 0);
+ fd = anon_inode_getfd("doom_surface", &surface_fops, surface_data, 0);
fd_s = fdget(fd);
if (fd_s.file->f_op != &surface_fops) {
err = -ENOENT;
goto error_fdget;
}
- fd_s.file->private_data = surface_data;
fd_s.file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
return fd;