omap24xxvout.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 2,498 行 · 第 1/5 页
C
2,498 行
},};static struct platform_device omap24xxv2out_dev = { .name = V2OUT_NAME, .id = 12, //.devid = OMAP24xx_V2OUT_DEVID, //.busid = OMAP_BUS_L3, .dev = { .release = omap35x_platform_release, },};static struct platform_driver omap24xxv1out_driver = { .driver = { .name = V1OUT_NAME, }, //.devid = OMAP24xx_V1OUT_DEVID, // .id = 11, //.busid = OMAP_BUS_L3, // .clocks = 0, .probe = omap24xxvout_probe, .suspend = omap24xxvout_suspend, .resume = omap24xxvout_resume,};static struct platform_driver omap24xxv2out_driver = { .driver = { .name = V2OUT_NAME, }, //.id = 12, //.devid = OMAP24xx_V2OUT_DEVID, //.busid = OMAP_BUS_L3, //.clocks = 0, .probe = omap24xxvout_probe, .suspend = omap24xxvout_suspend, .resume = omap24xxvout_resume,};void omap24xxvout_isr(void *arg, struct pt_regs *regs, unsigned int irqstatus){ struct timeval timevalue; unsigned int out_dev; struct omap24xxvout_device *vout=(struct omap24xxvout_device *)arg; u32 addr, fid; if(!vout->streaming) return; spin_lock(&vout->vbq_lock); do_gettimeofday(&timevalue); out_dev = omap2_disp_get_output_dev(vout->vid); if(out_dev == OMAP2_OUTPUT_LCD) { if(list_empty(&vout->dma_queue)) { spin_unlock(&vout->vbq_lock); return; } if(!vout->first_int){ vout->curFrm->ts = timevalue; vout->curFrm->state = VIDEOBUF_DONE; if(&(vout->curFrm->done)) { wake_up(&vout->curFrm->done); } vout->curFrm = vout->nextFrm; } vout->first_int = 0; vout->nextFrm = list_entry(vout->dma_queue.next, struct videobuf_buffer, queue); list_del(&vout->nextFrm->queue); vout->nextFrm->state = VIDEOBUF_ACTIVE; addr = (unsigned long) vout->queued_buf_addr[vout->nextFrm->i] + vout->cropped_offset; omap2_disp_set_addr(vout->vid, addr, addr, addr + vout->tv_field1_offset); } else { if(vout->first_int) { vout->first_int = 0; spin_unlock(&vout->vbq_lock); return ; } vout->field_id ^= 1; fid = (irqstatus & DISPC_IRQSTATUS_EVSYNC_ODD)?0:1; if(fid != vout->field_id) { if(0 == fid) vout->field_id = fid; spin_unlock(&vout->vbq_lock); return; } if(0 == fid) { if(vout->curFrm == vout->nextFrm) { spin_unlock(&vout->vbq_lock); return; } vout->curFrm->ts = timevalue; vout->curFrm->state = VIDEOBUF_DONE; wake_up_interruptible(&vout->curFrm->done); vout->curFrm = vout->nextFrm; } else if(1 == fid){ if(list_empty(&vout->dma_queue) || (vout->curFrm != vout->nextFrm)) { spin_unlock(&vout->vbq_lock); return ; } vout->nextFrm = list_entry(vout->dma_queue.next, struct videobuf_buffer, queue); list_del(&vout->nextFrm->queue); vout->nextFrm->state = VIDEOBUF_ACTIVE; addr = (unsigned long) vout->queued_buf_addr[vout->nextFrm->i] + vout->cropped_offset; omap2_disp_set_addr(vout->vid, addr, addr, addr + vout->tv_field1_offset); } } spin_unlock(&vout->vbq_lock);}static void cleanup_vout_device (int vid){ struct video_device *vfd; struct omap24xxvout_device *vout; int i, j, numbuffers; vout = (vid == OMAP2_VIDEO1) ? saved_v1out : saved_v2out; if (!vout) return; vfd = vout->vfd; if (vfd) { if (vfd->minor == -1) { /* * The device was never registered, so release the * video_device struct directly. */ video_device_release (vfd); } else { /* * The unregister function will release the video_device * struct as well as unregistering it. */ video_unregister_device (vfd); } } for(i = 0 ; i < 4 ; i ++) { for( j = 0 ; j < 4 ; j ++) { release_mem_region (vout->sms_rot_phy[i][j], VRF_SIZE); } } /* Allocate memory for the buffes */ numbuffers = (vid == OMAP2_VIDEO1) ? video1_numbuffers : video2_numbuffers; vout->buffer_size = (vid == OMAP2_VIDEO1) ? video1_bufsize : video2_bufsize; for(i = 0 ; i < numbuffers ; i ++) { omap35xvout_free_buffer(vout->buf_virt_addr[i], vout->buf_phy_addr[i], vout->buffer_size); vout->buf_phy_addr[i]=0; vout->buf_virt_addr[i]=0; } if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED){ vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; omap_free_dma (vout->vrfb_dma_tx.dma_ch); printk("Freed DMA channel\n"); } platform_device_unregister ((vid == OMAP2_VIDEO1) ? &omap24xxv1out_dev : &omap24xxv2out_dev); platform_driver_unregister ((vid == OMAP2_VIDEO1) ? &omap24xxv1out_driver : &omap24xxv2out_driver); kfree (vout); if (vid == OMAP2_VIDEO1) saved_v1out = NULL; else saved_v2out = NULL; omap2_disp_unregister_isr(omap24xxvout_isr);}static struct omap24xxvout_device * init_vout_device (int vid){ int r, i, j, mask; struct omap24xxvout_device *vout; struct video_device *vfd; struct v4l2_pix_format *pix; struct platform_driver *this_driver; struct platform_device *this_dev; u32 sms_start_addr, numbuffers; int index_i, index_j, image_width, image_height; vout = kmalloc (sizeof (struct omap24xxvout_device), GFP_KERNEL); if (!vout){ printk (KERN_ERR VOUT_NAME ": could not allocate memory\n"); return NULL; } memset (vout, 0, sizeof (struct omap24xxvout_device)); vout->vid = vid; vout->rotation = rotation_support; /* set the default pix */ pix = &vout->pix; pix->width = QQVGA_WIDTH; pix->height = QQVGA_HEIGHT; pix->pixelformat = V4L2_PIX_FMT_RGB565; pix->field = V4L2_FIELD_ANY; pix->bytesperline = pix->width * 2; pix->sizeimage = pix->bytesperline * pix->height; pix->priv = 0; pix->colorspace = V4L2_COLORSPACE_JPEG; vout->bpp = RGB565_BPP; vout->vrfb_bpp = 1; /* get the screen parameters */ omap2_disp_get_panel_size (omap2_disp_get_output_dev (vout->vid), &(vout->fbuf.fmt.width),&(vout->fbuf.fmt.height)); /* set default crop and win */ omap24xxvout_new_format (pix, &vout->fbuf, &vout->crop, &vout->win); /* initialize the video_device struct */ vfd = vout->vfd = video_device_alloc (); if (!vfd){ printk (KERN_ERR VOUT_NAME": could not allocate video \ device struct\n"); kfree (vout); return NULL; } vfd->release = video_device_release; strncpy (vfd->name, VOUT_NAME, sizeof (vfd->name)); vfd->type = VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY; /* need to register for a VID_HARDWARE_* ID in videodev.h */ vfd->fops = &omap24xxvout_fops; video_set_drvdata (vfd, vout); vfd->minor = -1; sms_start_addr = (vid == OMAP2_VIDEO1)?OMAP35XVOUT_VIDEO1_SMS_START : OMAP35XVOUT_VIDEO2_SMS_START; for(i = 0 ; i < 4 ; i ++) { for(j = 0 ; j < 4 ; j ++) { vout->sms_rot_phy[i][j] = sms_start_addr; if (!request_mem_region (vout->sms_rot_phy[i][j], VRF_SIZE, vfd->name)) { printk("Cannot reserve smsm IO %x\n", vout->sms_rot_phy[i][j]); index_i = i; index_j = j; goto rotation_free; } sms_start_addr += 0x1000000; } } index_i = 4; index_j = 4; /* Allocate memory for the buffes */ numbuffers = (vid == OMAP2_VIDEO1) ? video1_numbuffers : video2_numbuffers; vout->buffer_size = (vid == OMAP2_VIDEO1) ? video1_bufsize : video2_bufsize; for(i = 0 ; i < numbuffers ; i ++) { vout->buf_virt_addr[i] = omap35xvout_alloc_buffer( vout->buffer_size, (u32*)&vout->buf_phy_addr[i]); if(!vout->buf_virt_addr[i]) { numbuffers = i - 1; goto free_buffer_memory; } } vout->suspended = 0; init_waitqueue_head (&vout->suspend_wq); if (video_register_device (vfd, VFL_TYPE_GRABBER, vid) < 0){ printk (KERN_ERR VOUT_NAME": could not register Video for \ Linux device\n"); vfd->minor = -1; goto free_buffer_memory; } this_driver = (vid == OMAP2_VIDEO1) ? &omap24xxv1out_driver : &omap24xxv2out_driver; this_dev = (vid == OMAP2_VIDEO1) ? &omap24xxv1out_dev : &omap24xxv2out_dev; if (platform_driver_register (this_driver) != 0) { printk (KERN_ERR VOUT_NAME ": could not register \ Video driver\n"); cleanup_vout_device (vid); return NULL; } if (platform_device_register (this_dev) != 0) { printk (KERN_ERR VOUT_NAME ": could not register \ Video device\n"); cleanup_vout_device (vid); return NULL; } /* set driver specific data to use in power mgmt functions */ // omap_set_drvdata (this_dev, vout); platform_set_drvdata (this_dev, vout); if(vid == OMAP2_VIDEO1) { vout->vrfb_context[0] = 4; vout->vrfb_context[1] = 5; vout->vrfb_context[2] = 6; vout->vrfb_context[3] = 7; } else { vout->vrfb_context[0] = 8; vout->vrfb_context[1] = 9; vout->vrfb_context[2] = 10; vout->vrfb_context[3] = 11; } vout->cropped_offset = 0; /* Calculate VRFB memory size */ /* allocate for worst case size */ image_width = VID_MAX_WIDTH / TILE_SIZE; if (VID_MAX_WIDTH % TILE_SIZE) image_width++; image_width = image_width * TILE_SIZE; image_height = VID_MAX_HEIGHT / TILE_SIZE; if (VID_MAX_HEIGHT % TILE_SIZE) image_height++; image_height = image_height * TILE_SIZE; vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2); /* * Request and Initialize DMA, for DMA based VRFB transfer */ vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE; vout->vrfb_dma_tx.dma_ch = -1; vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED; r = omap_request_dma (vout->vrfb_dma_tx.dev_id, "VRFB DMA TX", vrfb_dma_tx_callback, (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch); if (r < 0) vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; init_waitqueue_head (&vout->vrfb_dma_tx.wait); /* Register ISR handler */ mask = (DISPC_IRQSTATUS_EVSYNC_ODD | DISPC_IRQSTATUS_EVSYNC_EVEN | DISPC_IRQSTATUS_VSYNC); r = omap2_disp_register_isr(omap24xxvout_isr, vout, mask); if(r < 0) { cleanup_vout_device (vid); return NULL; } /*if rotation support */ printk (KERN_INFO VOUT_NAME ": registered device video%d [v4l2]\n", vfd->minor); return vout;free_buffer_memory: for(i = 0 ; i < numbuffers ; i ++){ omap35xvout_free_buffer(vout->buf_virt_addr[i], vout->buf_phy_addr[i], vout->buffer_size); vout->buf_virt_addr[i] = 0; vout->buf_phy_addr[i] = 0; }rotation_free: for(j = 0 ; j < index_j ; j ++){ release_mem_region (vout->sms_rot_phy[index_i][j], VRF_SIZE); } for(i = 0 ; i < (index_i - 1) ; i ++){ for( j = 0 ;j < 4 ; j ++) { release_mem_region (vout->sms_rot_phy[i][j], VRF_SIZE); } } video_device_release (vfd); kfree (vout); return NULL;}static int __init omap24xxvout_init (void){ omap2_disp_get_dss(); saved_v1out = init_vout_device (OMAP2_VIDEO1); if (saved_v1out == NULL) { omap2_disp_put_dss(); return -ENODEV; } omap2_disp_save_initstate(OMAP_DSS_DISPC_GENERIC); omap2_disp_save_initstate(OMAP2_VIDEO1); saved_v2out = init_vout_device (OMAP2_VIDEO2); if (saved_v2out == NULL){ cleanup_vout_device (OMAP2_VIDEO1); omap2_disp_put_dss(); return -ENODEV; } omap2_disp_save_initstate(OMAP_DSS_DISPC_GENERIC); omap2_disp_save_initstate(OMAP2_VIDEO2); omap2_disp_put_dss(); vout_linked = -1; spin_lock_init (&vout_link_lock); return 0;}static void omap24xxvout_cleanup (void){ omap2_disp_get_dss(); cleanup_vout_device (OMAP2_VIDEO1); cleanup_vout_device (OMAP2_VIDEO2); omap2_disp_put_dss();}/* * omap24xxvout_setup - process command line options * @options: string of options * * NOTE: This function is a __setup and __init function. * * Returns zero. */int __init omap24xxvout_setup (char *options){ char *this_opt; int i; if (!options || !*options)return 0; DPRINTK ("Options \"%s\"\n", options); i = strlen (VOUT_NAME); if (!strncmp (options, VOUT_NAME, i) && options[i] == ':'){ this_opt = options + i + 1; if (!this_opt || !*this_opt) return 0; if (!strncmp (this_opt, "rotation=", 9)){ int deg = simple_strtoul (this_opt + 9, NULL, 0); switch (deg){ case 0: case 90: case 180: case 270: rotation_support = (deg == 90) ? 270 : (deg == 270) ? 90 : deg; break; default: rotation_support = -1; break; } printk (KERN_INFO VOUT_NAME ": Rotation %s\n", (rotation_support == -1) ? "none (supported: \"rotation=\ [-1|0|90|180|270]\")" : this_opt + 9); } else printk (KERN_INFO VOUT_NAME ": Invalid parameter \ \"%s\" " "(supported: \ \"rotation=[-1|0|90|180|270]\")\n", this_opt); return 0; } /* * If we get here no fb was specified. * We consider the argument to be a global video mode option. */ /* TODO - remove when FB is configured */ return 0;}__setup ("videoout=", omap24xxvout_setup);MODULE_AUTHOR ("Texas Instruments.");MODULE_DESCRIPTION ("OMAP24xx Video for Linux Video out driver");MODULE_LICENSE ("GPL");/* TODO -- Enabling it results in build erros, why?? */module_init (omap24xxvout_init);module_exit (omap24xxvout_cleanup);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?