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 + -
显示快捷键?