diff options
-rw-r--r-- | surface.c | 97 |
1 files changed, 84 insertions, 13 deletions
@@ -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; |