vino.c

来自「底层驱动开发」· C语言 代码 · 共 2,837 行 · 第 1/5 页

C
2,837
字号
		.maximum = INDYCAM_GAMMA_MAX,		.step = 1,		.default_value = INDYCAM_GAMMA_DEFAULT,		.flags = 0,		.reserved = { 0, 0 },	}};#define VINO_SAA7191_V4L2_CONTROL_COUNT		2struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {	{		.id = V4L2_CID_HUE,		.type = V4L2_CTRL_TYPE_INTEGER,		.name = "Hue",		.minimum = SAA7191_HUE_MIN,		.maximum = SAA7191_HUE_MAX,		.step = 1,		.default_value = SAA7191_HUE_DEFAULT,		.flags = 0,		.reserved = { 0, 0 },	},{		.id = V4L2_CID_PRIVATE_BASE,		.type = V4L2_CTRL_TYPE_BOOLEAN,		.name = "VTR Time Constant",		.minimum = SAA7191_VTRC_MIN,		.maximum = SAA7191_VTRC_MAX,		.step = 1,		.default_value = SAA7191_VTRC_DEFAULT,		.flags = 0,		.reserved = { 0, 0 },	}};/* VINO I2C bus functions */unsigned i2c_vino_getctrl(void *data){	return vino->i2c_control;}void i2c_vino_setctrl(void *data, unsigned val){	vino->i2c_control = val;}unsigned i2c_vino_rdata(void *data){	return vino->i2c_data;}void i2c_vino_wdata(void *data, unsigned val){	vino->i2c_data = val;}static struct i2c_algo_sgi_data i2c_sgi_vino_data ={	.getctrl = &i2c_vino_getctrl,	.setctrl = &i2c_vino_setctrl,	.rdata   = &i2c_vino_rdata,	.wdata   = &i2c_vino_wdata,	.xfer_timeout = 200,	.ack_timeout  = 1000,};/* * There are two possible clients on VINO I2C bus, so we limit usage only * to them. */static int i2c_vino_client_reg(struct i2c_client *client){	int ret = 0;	spin_lock(&vino_drvdata->input_lock);	switch (client->driver->id) {	case I2C_DRIVERID_SAA7191:		if (vino_drvdata->decoder.driver)			ret = -EBUSY;		else			vino_drvdata->decoder.driver = client;		break;	case I2C_DRIVERID_INDYCAM:		if (vino_drvdata->camera.driver)			ret = -EBUSY;		else			vino_drvdata->camera.driver = client;		break;	default:		ret = -ENODEV;	}	spin_unlock(&vino_drvdata->input_lock);	return ret;}static int i2c_vino_client_unreg(struct i2c_client *client){	int ret = 0;	spin_lock(&vino_drvdata->input_lock);	if (client == vino_drvdata->decoder.driver) {		if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL)			ret = -EBUSY;		else			vino_drvdata->decoder.driver = NULL;	} else if (client == vino_drvdata->camera.driver) {		if (vino_drvdata->camera.owner != VINO_NO_CHANNEL)			ret = -EBUSY;		else			vino_drvdata->camera.driver = NULL;	}	spin_unlock(&vino_drvdata->input_lock);	return ret;}static struct i2c_adapter vino_i2c_adapter ={	.name			= "VINO I2C bus",	.id			= I2C_HW_SGI_VINO,	.algo_data		= &i2c_sgi_vino_data,	.client_register	= &i2c_vino_client_reg,	.client_unregister	= &i2c_vino_client_unreg,};static int vino_i2c_add_bus(void){	return i2c_sgi_add_bus(&vino_i2c_adapter);}static int vino_i2c_del_bus(void){	return i2c_sgi_del_bus(&vino_i2c_adapter);}static int i2c_camera_command(unsigned int cmd, void *arg){	return vino_drvdata->camera.driver->		driver->command(vino_drvdata->camera.driver,				cmd, arg);}static int i2c_decoder_command(unsigned int cmd, void *arg){	return vino_drvdata->decoder.driver->		driver->command(vino_drvdata->decoder.driver,				cmd, arg);}/* VINO framebuffer/DMA descriptor management */static void vino_free_buffer_with_count(struct vino_framebuffer *fb,					       unsigned int count){	unsigned int i;	dprintk("vino_free_buffer_with_count(): count = %d\n", count);	for (i = 0; i < count; i++) {		mem_map_unreserve(virt_to_page(fb->desc_table.virtual[i]));		dma_unmap_single(NULL,				 fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],				 PAGE_SIZE, DMA_FROM_DEVICE);		free_page(fb->desc_table.virtual[i]);	}	dma_free_coherent(NULL,			  VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) *			  sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu,			  fb->desc_table.dma);	kfree(fb->desc_table.virtual);	memset(fb, 0, sizeof(struct vino_framebuffer));}static void vino_free_buffer(struct vino_framebuffer *fb){	vino_free_buffer_with_count(fb, fb->desc_table.page_count);}static int vino_allocate_buffer(struct vino_framebuffer *fb,				unsigned int size){	unsigned int count, i, j;	int ret = 0;	dprintk("vino_allocate_buffer():\n");	if (size < 1)		return -EINVAL;	memset(fb, 0, sizeof(struct vino_framebuffer));	count = ((size / PAGE_SIZE) + 4) & ~3;	dprintk("vino_allocate_buffer(): size = %d, count = %d\n",		size, count);	/* allocate memory for table with virtual (page) addresses */	fb->desc_table.virtual = (unsigned long *)		kmalloc(count * sizeof(unsigned long), GFP_KERNEL);	if (!fb->desc_table.virtual)		return -ENOMEM;	/* allocate memory for table with dma addresses	 * (has space for four extra descriptors) */	fb->desc_table.dma_cpu =		dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *				   sizeof(dma_addr_t), &fb->desc_table.dma,				   GFP_KERNEL | GFP_DMA);	if (!fb->desc_table.dma_cpu) {		ret = -ENOMEM;		goto out_free_virtual;	}	/* allocate pages for the buffer and acquire the according	 * dma addresses */	for (i = 0; i < count; i++) {		dma_addr_t dma_data_addr;		fb->desc_table.virtual[i] =			get_zeroed_page(GFP_KERNEL | GFP_DMA);		if (!fb->desc_table.virtual[i]) {			ret = -ENOBUFS;			break;		}		dma_data_addr =			dma_map_single(NULL,				       (void *)fb->desc_table.virtual[i],				       PAGE_SIZE, DMA_FROM_DEVICE);		for (j = 0; j < VINO_PAGE_RATIO; j++) {			fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =				dma_data_addr + VINO_PAGE_SIZE * j;		}		mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));	}	/* page_count needs to be set anyway, because the descriptor table has	 * been allocated according to this number */	fb->desc_table.page_count = count;	if (ret) {		/* the descriptor with index i doesn't contain		 * a valid address yet */		vino_free_buffer_with_count(fb, i);		return ret;	}	//fb->size = size;	fb->size = count * PAGE_SIZE;	fb->data_format = VINO_DATA_FMT_NONE;	/* set the dma stop-bit for the last (count+1)th descriptor */	fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;	return 0; out_free_virtual:	kfree(fb->desc_table.virtual);	return ret;}#if 0/* user buffers not fully implemented yet */static int vino_prepare_user_buffer(struct vino_framebuffer *fb,				     void *user,				     unsigned int size){	unsigned int count, i, j;	int ret = 0;	dprintk("vino_prepare_user_buffer():\n");	if (size < 1)		return -EINVAL;	memset(fb, 0, sizeof(struct vino_framebuffer));	count = ((size / PAGE_SIZE)) & ~3;	dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n",		size, count);	/* allocate memory for table with virtual (page) addresses */	fb->desc_table.virtual = (unsigned long *)		kmalloc(count * sizeof(unsigned long), GFP_KERNEL);	if (!fb->desc_table.virtual)		return -ENOMEM;	/* allocate memory for table with dma addresses	 * (has space for four extra descriptors) */	fb->desc_table.dma_cpu =		dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *				   sizeof(dma_addr_t), &fb->desc_table.dma,				   GFP_KERNEL | GFP_DMA);	if (!fb->desc_table.dma_cpu) {		ret = -ENOMEM;		goto out_free_virtual;	}	/* allocate pages for the buffer and acquire the according	 * dma addresses */	for (i = 0; i < count; i++) {		dma_addr_t dma_data_addr;		fb->desc_table.virtual[i] =			get_zeroed_page(GFP_KERNEL | GFP_DMA);		if (!fb->desc_table.virtual[i]) {			ret = -ENOBUFS;			break;		}		dma_data_addr =			dma_map_single(NULL,				       (void *)fb->desc_table.virtual[i],				       PAGE_SIZE, DMA_FROM_DEVICE);		for (j = 0; j < VINO_PAGE_RATIO; j++) {			fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =				dma_data_addr + VINO_PAGE_SIZE * j;		}		mem_map_reserve(virt_to_page(fb->desc_table.virtual[i]));	}	/* page_count needs to be set anyway, because the descriptor table has	 * been allocated according to this number */	fb->desc_table.page_count = count;	if (ret) {		/* the descriptor with index i doesn't contain		 * a valid address yet */		vino_free_buffer_with_count(fb, i);		return ret;	}	//fb->size = size;	fb->size = count * PAGE_SIZE;	/* set the dma stop-bit for the last (count+1)th descriptor */	fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;	return 0; out_free_virtual:	kfree(fb->desc_table.virtual);	return ret;}#endifstatic void vino_sync_buffer(struct vino_framebuffer *fb){	int i;	dprintk("vino_sync_buffer():\n");	for (i = 0; i < fb->desc_table.page_count; i++)		dma_sync_single(NULL,				fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],				PAGE_SIZE, DMA_FROM_DEVICE);}/* Framebuffer fifo functions (need to be locked externally) */static void vino_fifo_init(struct vino_framebuffer_fifo *f,			   unsigned int length){	f->length = 0;	f->used = 0;	f->head = 0;	f->tail = 0;	if (length > VINO_FRAMEBUFFER_MAX_COUNT)		length = VINO_FRAMEBUFFER_MAX_COUNT;	f->length = length;}/* returns true/false */static int vino_fifo_has_id(struct vino_framebuffer_fifo *f, unsigned int id){	unsigned int i;	for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) {		if (f->data[i] == id)			return 1;	}	return 0;}/* returns true/false */static int vino_fifo_full(struct vino_framebuffer_fifo *f){	return (f->used == f->length);}static unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f){	return f->used;}static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id){	if (id >= f->length) {		return VINO_QUEUE_ERROR;	}	if (vino_fifo_has_id(f, id)) {		return VINO_QUEUE_ERROR;	}	if (f->used < f->length) {		f->data[f->tail] = id;		f->tail = (f->tail + 1) % f->length;		f->used++;	} else {		return VINO_QUEUE_ERROR;	}	return 0;}static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id){	if (f->used > 0) {		*id = f->data[f->head];	} else {		return VINO_QUEUE_ERROR;	}	return 0;}static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id){	if (f->used > 0) {		*id = f->data[f->head];		f->head = (f->head + 1) % f->length;		f->used--;	} else {		return VINO_QUEUE_ERROR;	}	return 0;}/* Framebuffer queue functions *//* execute with queue_lock locked */static void vino_queue_free_with_count(struct vino_framebuffer_queue *q,				       unsigned int length){	unsigned int i;	q->length = 0;	memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo));	memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo));	for (i = 0; i < length; i++) {		dprintk("vino_queue_free_with_count(): freeing buffer %d\n",			i);		vino_free_buffer(q->buffer[i]);		kfree(q->buffer[i]);	}	q->type = VINO_MEMORY_NONE;	q->magic = 0;}static void vino_queue_free(struct vino_framebuffer_queue *q){	dprintk("vino_queue_free():\n");	if (q->magic != VINO_QUEUE_MAGIC)		return;	if (q->type != VINO_MEMORY_MMAP)		return;	down(&q->queue_sem);	vino_queue_free_with_count(q, q->length);	up(&q->queue_sem);}static int vino_queue_init(struct vino_framebuffer_queue *q,			   unsigned int *length){	unsigned int i;	int ret = 0;	dprintk("vino_queue_init(): length = %d\n", *length);	if (q->magic == VINO_QUEUE_MAGIC) {		dprintk("vino_queue_init(): queue already initialized!\n");		return -EINVAL;	}	if (q->type != VINO_MEMORY_NONE) {		dprintk("vino_queue_init(): queue already initialized!\n");		return -EINVAL;	}	if (*length < 1)		return -EINVAL;	down(&q->queue_sem);	if (*length > VINO_FRAMEBUFFER_MAX_COUNT)		*length = VINO_FRAMEBUFFER_MAX_COUNT;	q->length = 0;	for (i = 0; i < *length; i++) {		dprintk("vino_queue_init(): allocating buffer %d\n", i);		q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer),				       GFP_KERNEL);		if (!q->buffer[i]) {			dprintk("vino_queue_init(): kmalloc() failed\n");			ret = -ENOMEM;			break;		}		ret = vino_allocate_buffer(q->buffer[i],					   VINO_FRAMEBUFFER_SIZE);		if (ret) {			kfree(q->buffer[i]);			dprintk("vino_queue_init(): "				"vino_allocate_buffer() failed\n");			break;		}		q->buffer[i]->id = i;		if (i > 0) {			q->buffer[i]->offset = q->buffer[i - 1]->offset +				q->buffer[i - 1]->size;		} else {			q->buffer[i]->offset = 0;		}		spin_lock_init(&q->buffer[i]->state_lock);		dprintk("vino_queue_init(): buffer = %d, offset = %d, "			"size = %d\n", i, q->buffer[i]->offset,			q->buffer[i]->size);	}	if (ret) {		vino_queue_free_with_count(q, i);		*length = 0;	} else {		q->length = *length;		vino_fifo_init(&q->in, q->length);		vino_fifo_init(&q->out, q->length);		q->type = VINO_MEMORY_MMAP;		q->magic = VINO_QUEUE_MAGIC;	}	up(&q->queue_sem);	return ret;}static struct vino_framebuffer *vino_queue_add(struct					       vino_framebuffer_queue *q,					       unsigned int id){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?