📄 vino.c
字号:
.type = V4L2_CTRL_TYPE_INTEGER, .name = "Blue Balance", .minimum = INDYCAM_BLUE_BALANCE_MIN, .maximum = INDYCAM_BLUE_BALANCE_MAX, .step = 1, .default_value = INDYCAM_BLUE_BALANCE_DEFAULT, .flags = 0, .reserved = { INDYCAM_CONTROL_BLUE_BALANCE, 0 }, },{ .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Shutter Control", .minimum = INDYCAM_SHUTTER_MIN, .maximum = INDYCAM_SHUTTER_MAX, .step = 1, .default_value = INDYCAM_SHUTTER_DEFAULT, .flags = 0, .reserved = { INDYCAM_CONTROL_SHUTTER, 0 }, },{ .id = V4L2_CID_GAMMA, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Gamma", .minimum = INDYCAM_GAMMA_MIN, .maximum = INDYCAM_GAMMA_MAX, .step = 1, .default_value = INDYCAM_GAMMA_DEFAULT, .flags = 0, .reserved = { INDYCAM_CONTROL_GAMMA, 0 }, }};#define VINO_SAA7191_V4L2_CONTROL_COUNT 9struct 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 = { SAA7191_CONTROL_HUE, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Luminance Bandpass", .minimum = SAA7191_BANDPASS_MIN, .maximum = SAA7191_BANDPASS_MAX, .step = 1, .default_value = SAA7191_BANDPASS_DEFAULT, .flags = 0, .reserved = { SAA7191_CONTROL_BANDPASS, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE + 1, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Luminance Bandpass Weight", .minimum = SAA7191_BANDPASS_WEIGHT_MIN, .maximum = SAA7191_BANDPASS_WEIGHT_MAX, .step = 1, .default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT, .flags = 0, .reserved = { SAA7191_CONTROL_BANDPASS_WEIGHT, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE + 2, .type = V4L2_CTRL_TYPE_INTEGER, .name = "HF Luminance Coring", .minimum = SAA7191_CORING_MIN, .maximum = SAA7191_CORING_MAX, .step = 1, .default_value = SAA7191_CORING_DEFAULT, .flags = 0, .reserved = { SAA7191_CONTROL_CORING, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE + 3, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Force Colour", .minimum = SAA7191_FORCE_COLOUR_MIN, .maximum = SAA7191_FORCE_COLOUR_MAX, .step = 1, .default_value = SAA7191_FORCE_COLOUR_DEFAULT, .flags = 0, .reserved = { SAA7191_CONTROL_FORCE_COLOUR, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE + 4, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Chrominance Gain Control", .minimum = SAA7191_CHROMA_GAIN_MIN, .maximum = SAA7191_CHROMA_GAIN_MAX, .step = 1, .default_value = SAA7191_CHROMA_GAIN_DEFAULT, .flags = 0, .reserved = { SAA7191_CONTROL_CHROMA_GAIN, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE + 5, .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 = { SAA7191_CONTROL_VTRC, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE + 6, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Luminance Delay Compensation", .minimum = SAA7191_LUMA_DELAY_MIN, .maximum = SAA7191_LUMA_DELAY_MAX, .step = 1, .default_value = SAA7191_LUMA_DELAY_DEFAULT, .flags = 0, .reserved = { SAA7191_CONTROL_LUMA_DELAY, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE + 7, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Vertical Noise Reduction", .minimum = SAA7191_VNR_MIN, .maximum = SAA7191_VNR_MAX, .step = 1, .default_value = SAA7191_VNR_DEFAULT, .flags = 0, .reserved = { SAA7191_CONTROL_VNR, 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){ unsigned long flags; int ret = 0; spin_lock_irqsave(&vino_drvdata->input_lock, flags); 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_irqrestore(&vino_drvdata->input_lock, flags); return ret;}static int i2c_vino_client_unreg(struct i2c_client *client){ unsigned long flags; int ret = 0; spin_lock_irqsave(&vino_drvdata->input_lock, flags); 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_irqrestore(&vino_drvdata->input_lock, flags); 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++) { ClearPageReserved(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; } SetPageReserved(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 /* keep */;/* 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; } SetPageReserved(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 inline 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_COUNT_MAX) length = VINO_FRAMEBUFFER_COUNT_MAX; f->length = length;}/* returns true/false */static inline 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;}#if 0 /* keep */;/* returns true/false */static inline int vino_fifo_full(struct vino_framebuffer_fifo *f){ return (f->used == f->length);}#endifstatic inline 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++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -