m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
path: root/char.c
diff options
context:
space:
mode:
Diffstat (limited to 'char.c')
-rw-r--r--char.c139
1 files changed, 138 insertions, 1 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)