/* * init and exit */ static int __init imapx200_decode_init(void) { /* call probe */ if(platform_driver_register(&imapx200_decode_driver)) { decode_error("Fail to register platform driver for IMAPX200 Decode Driver\n"); decode_debug("IMAPX200 Decode Driver init failed\n"); return -EPERM; } decode_debug("IMAPX200 Hantro 9170 Decode Driver init OK\n"); return IMAPX200_DECODE_RET_OK; }
static void __exit imapx200_decode_exit(void) { /* call remove */ platform_driver_unregister(&imapx200_decode_driver); decode_debug("IMAPX200 Decode Driver exit OK\n"); }
/* * File operations, this system call should be called before * any interrupt occurs. You can call fcntl system call to set * driver node file property in order to get asynchronization * signal. */ static int imapx200_decode_fasync(int fd, struct file *file, int mode) { decode_param_t *dev; struct fasync_struct **async_queue; dev = &decode_param; async_queue = NULL; /* select whitch interrupt this instance will sign up for */ if((unsigned int *)(file->private_data) == &(decode_param.dec_instance)) { decode_debug("IMAPX200 Decode dec fasync called\n"); async_queue = &(decode_param.async_queue_dec); } else if((unsigned int *)(file->private_data) == &(decode_param.pp_instance)) { decode_debug("IMAPX200 Decode pp fasync called\n"); async_queue = &(decode_param.async_queue_pp); } else decode_error("IMAPX200 Decode wrong fasync called\n"); return fasync_helper(fd, file, mode, async_queue); }
/* * open system call just mark file private data as a decode * instance by default, and you can change it by a ioctl call */ static int imapx200_decode_open(struct inode *inode, struct file *file) { mutex_lock(&decode_lock); if(decode_open_count == 0) { #if defined(CONFIG_IMAP_MMPOOL_MANAGEMENT) /* 2010/10/21 */ power_on_mpool_in_memalloc(); #endif /* CONFIG_IMAP_MMPOOL_MANAGEMENT */ decode_enable_hw_power(); } decode_open_count++; mutex_unlock(&decode_lock); /* dec instance by default, you can change it by ioctl pp instance */ file->private_data = &(decode_param.dec_instance); decode_debug("IMAPX200 Decode open OK\n"); return IMAPX200_DECODE_RET_OK; }
/* * fasync system call be called here */ static int imapx200_decode_release(struct inode *inode, struct file *file) { #ifdef CONFIG_IMAP_DECODE_SIGNAL_MODE /* reset decode driver node file property */ if(file->f_flags & FASYNC) imapx200_decode_fasync(-1, file, 0); #endif /* CONFIG_IMAP_DECODE_SIGNAL_MODE */ mutex_lock(&decode_lock); decode_open_count--; if(decode_open_count == 0) { decode_disable_hw_power(); #if defined(CONFIG_IMAP_MMPOOL_MANAGEMENT) /* 2010/10/21 */ power_off_mpool_in_memalloc(); #endif /* CONFIG_IMAP_MMPOOL_MANAGEMENT */ } mutex_unlock(&decode_lock); decode_debug("IMAPX200 Decode release OK\n"); return IMAPX200_DECODE_RET_OK; }
/* tbc_decode: * If ptr is NULL then this uses in place decoding, * otherwise fills out the structure pointered to. * When not using in place decoding the structure should be * initialised with zeros. tlp elements will be decoded if * tbc->tlp is not NULL. */ int tbc_decode (BYTE *data, unsigned int length, tbc_t **ptr) { tenc_element_t element; tbc_t *tbc; int in_place; int ret; if (*ptr != NULL) { tbc = *ptr; in_place = 0; } else { tbc = (tbc_t *) data; in_place = 1; } /* Decode the required elements */ if ((ret = load_uint (&data, &length, "endU", &(tbc->endian))) < 0) return ret; if ((ret = load_uint (&data, &length, "ws U", &(tbc->ws))) < 0) return ret; if ((ret = load_uint (&data, &length, "vs U", &(tbc->vs))) < 0) return ret; if ((ret = tenc_walk_to_element (data, &length, "bc B", &element)) < 0) return ret; tbc->bytecode_len = element.length; tbc->bytecode = element.data.bytes; data = element.next; /* Decode optional elements */ if (in_place) { tbc->tlp = NULL; tbc->symbols = NULL; tbc->ffi = NULL; tbc->debug = NULL; } else { if (tbc->tlp != NULL) { tbc->tlp->fmt = NULL; tbc->tlp->symbol = NULL; } } /* Copy pointer */ *ptr = tbc; while (length > 0) { if (tenc_decode_element (data, &length, &element) < 0) return 0; /* ignore errors */ if (ids_match (element.id, "tlpL")) { tbc->tlp = decode_tlp (data, tbc->tlp, &element); } else if (in_place && ids_match (element.id, "ffiL")) { tbc->ffi = decode_ffi (data, &element); } else if (in_place && ids_match (element.id, "stbL")) { tbc->symbols = decode_symbols (&element); } else if (in_place && ids_match (element.id, "dbgL")) { tbc->debug = decode_debug (data, &element); } data = element.next; } return 0; }
/* * platform operation relate functions */ static int imapx200_decode_probe(struct platform_device *pdev) { int ret; unsigned int size; struct resource *res; /* get decode hardware clock and enable it */ imap_vdec_clock = NULL; imap_vdec_clock = clk_get(&pdev->dev, "vdec"); if(imap_vdec_clock == NULL) { decode_error("Fail to get decode hardware source\n"); return IMAPX200_DECODE_RET_ERROR; } clk_enable(imap_vdec_clock); /* * 9170 decode ic is supposed that powered on when using, but uboot powers on * it for some usage, so i have to power down it here to ensure that when system * boot, decode ic is not costing elec */ decode_disable_hw_power(); /* initualize open count */ decode_open_count = 0; /* initualize instances just for mark */ decode_param.dec_instance = 0; decode_param.pp_instance = 0; #ifdef CONFIG_IMAP_DECODE_POLL_MODE /* initualize wait queue */ init_waitqueue_head(&wait_decode); #endif /* CONFIG_IMAP_DECODE_POLL_MODE */ #ifdef CONFIG_IMAP_DECODE_SIGNAL_MODE /* initualize async queue */ decode_param.async_queue_dec = NULL; decode_param.async_queue_pp = NULL; #endif /* CONFIG_IMAP_DECODE_SIGNAL_MODE */ /* get register base address */ res = NULL; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if(res == NULL) { decode_error("Fail to get IMAPX200 Decode resource\n"); return -ENOENT; } /* request memory region for registers */ size = res->end - res->start + 1; decode_param.reg_reserved_size = size; decode_param.resource_mem = NULL; decode_param.resource_mem = request_mem_region(res->start, size, pdev->name); if(decode_param.resource_mem == NULL) { decode_error("Fail to get IMAPX200 Decode register memory region\n"); return -ENOENT; } decode_param.reg_base_phys_addr = res->start; decode_param.reg_base_virt_addr = NULL; /* * ATTENTON: memory map for registers should always be nocache method * cuz we don't want register data to be cached */ decode_param.reg_base_virt_addr = ioremap_nocache(res->start, size); if(decode_param.reg_base_virt_addr == NULL) { decode_error("Fail to ioremap IMAPX200 Decode register base address\n"); return -EINVAL; } /* get and config irq */ res = NULL; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if(res == NULL) { decode_error("Fail to get IMAPX200 Decode irq resource\n"); return -ENOENT; } if(res->start != IRQ_VDEC) { decode_error("Get wrong irq number for IMAPX200 Decode\n"); return -ENOENT; } /* * decoder and pp shared one irq line, so we must register irq in share mode */ ret = -1; ret = request_irq(res->start, imapx200_decode_irq_handle, IRQF_DISABLED, \ pdev->name, (void *)(&decode_param)); if(ret) { decode_error("Fail to request irq for IMAPX200 Decode device\n"); return ret; } /* register char device driver */ ret = -1; ret = decode_driver_register(); if(ret) { decode_error("Fail to register char device for IMAPX200 Decode\n"); return ret; } /* reset hardware */ reset_hw_reg_decode(); mutex_init(&decode_lock); decode_debug("IMAPX200 Decode Driver probe OK\n"); return IMAPX200_DECODE_RET_OK; }
/* * This irq handle function should never be reexecute at the same * time. Pp and decode share the same interrupt signal thread, in * pp external mode, a finished interruption refer to be a pp irq, * but in pp pipeline mode(decode pipeline with decode), recieved * irq refers to be a decode interruption. * In this driver, we use System V signal asynchronization thread * communication. So you should set System V in you kernel make * menuconfig. * ATTENTION: if your application runs in multi-thread mode, be * aware that if you set your application getting this signal * as process mode, the signal will be send to your application's * main thread, and signal will never be processed twice. So in * this case you won't get anything in your derived thread. */ static irqreturn_t imapx200_decode_irq_handle(int irq, void *dev_id) { unsigned int handled; unsigned int irq_status_dec; unsigned int irq_status_pp; decode_param_t *dev; handled = 0; dev = (decode_param_t *)dev_id; /* interrupt status register read */ irq_status_dec = readl(dev->reg_base_virt_addr + IMAPX200_DECODE_IRQ_STAT_DEC * 4); irq_status_pp = readl(dev->reg_base_virt_addr + IMAPX200_DECODE_IRQ_STAT_PP * 4); /* this structure is to enable irq in irq */ if((irq_status_dec & IMAPX200_DECODE_IRQ_BIT_DEC) || (irq_status_pp & IMAPX200_DECODE_IRQ_BIT_PP)) { if(irq_status_dec & IMAPX200_DECODE_IRQ_BIT_DEC) { #ifdef CONFIG_IMAP_DEC_HW_PERFORMANCE do_gettimeofday(&(dev->end_time)); #endif /* clear irq */ writel(irq_status_dec & (~IMAPX200_DECODE_IRQ_BIT_DEC), \ dev->reg_base_virt_addr + IMAPX200_DECODE_IRQ_STAT_DEC * 4); #ifdef CONFIG_IMAP_DECODE_SIGNAL_MODE /* fasync kill for decode instances to send signal */ if(dev->async_queue_dec != NULL) kill_fasync(&(dev->async_queue_dec), SIGIO, POLL_IN); else decode_alert("IMAPX200 Decode dec received w/o anybody waiting for it\n"); #endif /* CONFIG_IMAP_DECODE_SIGNAL_MODE */ #ifdef CONFIG_IMAP_DECODE_POLL_MODE dec_poll_mark = 1; wake_up(&wait_decode); #endif /* CONFIG_IMAP_DECODE_POLL_MODE */ decode_debug("IMAPX200 Decode get dec irq\n"); } /* In pp pipeline mode, only one decode interrupt will be set */ if(irq_status_pp & IMAPX200_DECODE_IRQ_BIT_PP) { #ifdef CONFIG_IMAP_DEC_HW_PERFORMANCE do_gettimeofday(&(dev->end_time)); #endif /* clear irq */ writel(irq_status_dec & (~IMAPX200_DECODE_IRQ_BIT_PP), \ dev->reg_base_virt_addr + IMAPX200_DECODE_IRQ_STAT_PP * 4); #ifdef CONFIG_IMAP_DECODE_SIGNAL_MODE /* fasync kill for pp instance */ if(dev->async_queue_pp != NULL) kill_fasync(&dev->async_queue_pp, SIGIO, POLL_IN); else decode_alert("IMAPX200 Decode pp received w/o anybody waiting for it\n"); #endif /* CONFIG_IMAP_DECODE_SIGNAL_MODE */ #ifdef CONFIG_IMAP_DECODE_POLL_MODE pp_poll_mark = 1; wake_up(&wait_decode); #endif /* CONFIG_IMAP_DECODE_POLL_MODE */ decode_debug("IMAPX200 Decode get pp irq\n"); } handled = 1; } else decode_debug("IMAPX200 Decode Driver get an unknown irq\n"); return IRQ_RETVAL(handled); }