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; |