* - S-Core Co., Ltd
*
*/
-
-#include <linux/init.h>
-#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
-#include <linux/device.h>
+#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/err.h>
#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
+#include <linux/sched.h>
#include <linux/semaphore.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-#define DRIVER_NAME "codec"
-#define CODEC_MAJOR 240
+#define DRIVER_NAME "codec"
+#define CODEC_MAJOR 240
MODULE_DESCRIPTION("Virtual Codec Device Driver");
MODULE_AUTHOR("Kitae KIM <kt920.kim@samsung.com");
MODULE_LICENSE("GPL2");
-#define USABLE_MMAP_MAX_SIZE 4
-#define CODEC_ERR_LOG(fmt, ...) \
- printk(KERN_ERR "%s: " fmt, DRIVER_NAME, ##__VA_ARGS__)
+#define USABLE_MMAP_MAX_SIZE 20
+#define CODEC_LOG(log_level, fmt, ...) \
+ printk(log_level "%s: " fmt, DRIVER_NAME, ##__VA_ARGS__)
+
+#define CODEC_IRQ 0x7f
+/* Clean up source. : _param, svcodec_param_offset, paramindex */
-struct _param {
- uint32_t apiIndex;
- uint32_t ctxIndex;
- uint32_t mmapOffset;
- uint32_t inArgsNum;
- uint32_t inArgs[20];
- uint32_t ret;
+struct codec_param {
+ uint32_t apiIndex;
+ uint32_t ctxIndex;
+ uint32_t mmapOffset;
+ uint32_t ret;
};
-enum svodec_param_offset {
- CODEC_API_INDEX = 0,
- CODEC_IN_PARAM,
- CODEC_RETURN_VALUE,
- CODEC_CONTEXT_INDEX,
- CODEC_MMAP_OFFSET,
- CODEC_FILE_INDEX,
- CODEC_CLOSED,
+enum codec_io_cmd {
+ CODEC_API_INDEX = 0,
+ CODEC_QUERY_STATE,
+ CODEC_CONTEXT_INDEX,
+ CODEC_MMAP_OFFSET,
+ CODEC_FILE_INDEX,
+ CODEC_CLOSED,
};
-enum svcodec_param_apiindex {
- EMUL_AV_REGISTER_ALL = 1,
- EMUL_AVCODEC_ALLOC_CONTEXT,
- EMUL_AVCODEC_ALLOC_FRAME,
- EMUL_AVCODEC_OPEN,
- EMUL_AVCODEC_CLOSE,
- EMUL_AV_FREE_CONTEXT,
- EMUL_AV_FREE_PICTURE,
- EMUL_AV_FREE_PALCTRL,
- EMUL_AV_FREE_EXTRADATA,
- EMUL_AVCODEC_FLUSH_BUFFERS,
- EMUL_AVCODEC_DECODE_VIDEO,
- EMUL_AVCODEC_ENCODE_VIDEO,
- EMUL_AVCODEC_DECODE_AUDIO,
- EMUL_AVCODEC_ENCODE_AUDIO,
- EMUL_AV_PICTURE_COPY,
- EMUL_AV_PARSER_INIT,
- EMUL_AV_PARSER_PARSE,
- EMUL_AV_PARSER_CLOSE,
- EMUL_GET_MMAP_INDEX,
- EMUL_GET_CODEC_VER = 50,
+enum codec_api_index {
+ EMUL_AV_REGISTER_ALL = 1,
+ EMUL_AVCODEC_ALLOC_CONTEXT,
+ EMUL_AVCODEC_ALLOC_FRAME,
+ EMUL_AVCODEC_OPEN,
+ EMUL_AVCODEC_CLOSE,
+ EMUL_AV_FREE,
+ EMUL_AVCODEC_FLUSH_BUFFERS,
+ EMUL_AVCODEC_DECODE_VIDEO,
+ EMUL_AVCODEC_ENCODE_VIDEO,
+ EMUL_AVCODEC_DECODE_AUDIO,
+ EMUL_AVCODEC_ENCODE_AUDIO,
+ EMUL_AV_PICTURE_COPY,
+ EMUL_AV_PARSER_INIT,
+ EMUL_AV_PARSER_PARSE,
+ EMUL_AV_PARSER_CLOSE,
+ EMUL_GET_MMAP_INDEX,
+ EMUL_GET_CODEC_VER = 50,
};
-typedef struct _svcodec_dev {
- struct pci_dev *dev;
+struct svcodec_device {
+ struct pci_dev *dev;
+
+ /* I/O and Memory Region */
+ unsigned int *ioaddr;
+ unsigned int *memaddr;
- volatile unsigned int *ioaddr;
- volatile unsigned int *memaddr;
+ resource_size_t io_start;
+ resource_size_t io_size;
+ resource_size_t mem_start;
+ resource_size_t mem_size;
- resource_size_t io_start;
- resource_size_t io_size;
- resource_size_t mem_start;
- resource_size_t mem_size;
+ /* irq handler */
+ wait_queue_head_t codec_wq;
+ spinlock_t lock;
+ int sleep_flag;
- uint8_t useMmap[USABLE_MMAP_MAX_SIZE + 1];
-} svcodec_dev;
+ uint8_t useMmap[USABLE_MMAP_MAX_SIZE + 1];
+};
-static svcodec_dev *svcodec;
+static struct svcodec_device *svcodec;
DEFINE_MUTEX(codec_mutex);
-static struct pci_device_id svcodec_pci_table[] __devinitdata = {
- {
- .vendor = PCI_VENDOR_ID_TIZEN,
- .device = PCI_DEVICE_ID_VIRTUAL_CODEC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
-};
-MODULE_DEVICE_TABLE(pci, svcodec_pci_table);
+static ssize_t svcodec_read(struct file *file, char __user *buf,
+ size_t count, loff_t *fops)
+{
+ CODEC_LOG(KERN_INFO, "do nothing in the read operation.\n");
+ return 0;
+}
/* Another way to copy data between guest and host. */
/* Copy data between guest and host using mmap operation. */
static ssize_t svcodec_write (struct file *file, const char __user *buf,
- size_t count, loff_t *fops)
+ size_t count, loff_t *fops)
{
- struct _param paramInfo;
-
- mutex_lock(&codec_mutex);
-
- if (!svcodec) {
- CODEC_ERR_LOG("fail to get codec device info\n");
- return -EINVAL;
- }
-
- if (copy_from_user(¶mInfo, buf, sizeof(struct _param))) {
- CODEC_ERR_LOG("fail to get codec parameter info from user\n");
- }
-
- if (paramInfo.apiIndex == EMUL_GET_MMAP_INDEX) {
- int i = 0;
- int max_size = USABLE_MMAP_MAX_SIZE;
- int *mmapIndex = (int*)paramInfo.ret;
- uint8_t *useMmapSize = &svcodec->useMmap[max_size];
-
- printk(KERN_DEBUG "%s: before available useMmap count:%d\n", DRIVER_NAME, (max_size - *useMmapSize));
-
- for (; i < max_size; i++) {
- if (svcodec->useMmap[i] == 1) {
- svcodec->useMmap[i] = 0;
- (*useMmapSize)++;
- file->private_data = &svcodec->useMmap[i];
- printk(KERN_DEBUG "%s: useMmap[%d]=%d\n", DRIVER_NAME, i, svcodec->useMmap[i]);
- printk(KERN_DEBUG "%s: file:%p private_data:%p\n", DRIVER_NAME, file, file->private_data);
- printk(KERN_DEBUG "%s: after available useMmap count:%d\n", DRIVER_NAME, (max_size - *useMmapSize));
- printk(KERN_DEBUG "%s: return %d as the index of mmap\n", DRIVER_NAME, i);
- break;
- }
- }
-
- if (i == max_size) {
- printk(KERN_DEBUG "%s: Usable mmap is none! struct file:%p\n", DRIVER_NAME, file);
- i = -1;
- }
-
- if (copy_to_user((void*)mmapIndex, &i, sizeof(int))) {
- printk(KERN_ERR "%s: fail to copy the index value to user.\n", DRIVER_NAME);
- }
- mutex_unlock(&codec_mutex);
-
- return 0;
- }
-
- if (paramInfo.apiIndex == EMUL_AVCODEC_ALLOC_CONTEXT) {
- writel((uint32_t)file, svcodec->ioaddr + CODEC_FILE_INDEX);
- }
-
- writel((uint32_t)paramInfo.ctxIndex, svcodec->ioaddr + CODEC_CONTEXT_INDEX);
- writel((uint32_t)paramInfo.mmapOffset, svcodec->ioaddr + CODEC_MMAP_OFFSET);
- writel((uint32_t)paramInfo.apiIndex, svcodec->ioaddr + CODEC_API_INDEX);
-
- mutex_unlock(&codec_mutex);
-
- return 0;
+ struct codec_param paramInfo;
+
+ mutex_lock(&codec_mutex);
+
+ if (!svcodec) {
+ CODEC_LOG(KERN_ERR, "failed to get codec device info\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(¶mInfo, buf, sizeof(struct codec_param)))
+ CODEC_LOG(KERN_ERR,
+ "failed to get codec parameter info from user\n");
+
+
+ if (paramInfo.apiIndex == EMUL_GET_MMAP_INDEX) {
+ int i = 0;
+ int max_size = USABLE_MMAP_MAX_SIZE;
+ int *mmapIndex = (int *)paramInfo.ret;
+ uint8_t *useMmapSize = &svcodec->useMmap[max_size];
+
+ CODEC_LOG(KERN_DEBUG, "before available useMmap count:%d\n",
+ (max_size - *useMmapSize));
+
+ for (; i < max_size; i++) {
+ if (svcodec->useMmap[i] == 1) {
+ svcodec->useMmap[i] = 0;
+ (*useMmapSize)++;
+ file->private_data = &svcodec->useMmap[i];
+ CODEC_LOG(KERN_DEBUG,
+ "useMmap[%d]=%d\n", i, svcodec->useMmap[i]);
+ CODEC_LOG(KERN_DEBUG,
+ "file:%p private_data:%p\n",
+ file, file->private_data);
+ CODEC_LOG(KERN_DEBUG,
+ "after available useMmap count:%d\n",
+ (max_size - *useMmapSize));
+ CODEC_LOG(KERN_DEBUG,
+ "return %d as the index of mmap\n", i);
+ break;
+ }
+ }
+
+ if (i == max_size) {
+ CODEC_LOG(KERN_DEBUG,
+ "Usable mmap is none! struct file:%p\n", file);
+ i = -1;
+ }
+
+ if (copy_to_user((void *)mmapIndex, &i, sizeof(int)))
+ CODEC_LOG(KERN_ERR,
+ "failed to copy the index value to user.\n");
+ mutex_unlock(&codec_mutex);
+ return 0;
+ }
+
+ if (paramInfo.apiIndex == EMUL_AVCODEC_ALLOC_CONTEXT)
+ writel((uint32_t)file, svcodec->ioaddr + CODEC_FILE_INDEX);
+
+ writel((uint32_t)paramInfo.ctxIndex,
+ svcodec->ioaddr + CODEC_CONTEXT_INDEX);
+ writel((uint32_t)paramInfo.mmapOffset,
+ svcodec->ioaddr + CODEC_MMAP_OFFSET);
+ writel((uint32_t)paramInfo.apiIndex,
+ svcodec->ioaddr + CODEC_API_INDEX);
+
+ /* wait decoding or encoding job */
+ if (paramInfo.apiIndex >= EMUL_AVCODEC_DECODE_VIDEO &&
+ paramInfo.apiIndex <= EMUL_AVCODEC_ENCODE_AUDIO) {
+ wait_event_interruptible(svcodec->codec_wq,
+ svcodec->sleep_flag != 0);
+ svcodec->sleep_flag = 0;
+ }
+
+ mutex_unlock(&codec_mutex);
+
+ return 0;
}
-static ssize_t svcodec_read (struct file *file, char __user *buf,
- size_t count, loff_t *fops)
+static int svcodec_mmap(struct file *file, struct vm_area_struct *vm)
{
- printk(KERN_INFO "%s: do nothing in the read operation \n", DRIVER_NAME);
- return 0;
+ unsigned long off;
+ unsigned long phys_addr;
+ unsigned long size;
+ int ret = -1;
+
+ off = vm->vm_pgoff << PAGE_SHIFT;
+ phys_addr = (PAGE_ALIGN(svcodec->mem_start) + off) >> PAGE_SHIFT;
+ size = vm->vm_end - vm->vm_start;
+
+ if (size > svcodec->mem_size) {
+ CODEC_LOG(KERN_ERR, "over mapping size\n");
+ return -EINVAL;
+ }
+
+ ret = remap_pfn_range(vm, vm->vm_start, phys_addr,
+ size, vm->vm_page_prot);
+ if (ret < 0) {
+ CODEC_LOG(KERN_ERR, "failed to remap page range\n");
+ return -EAGAIN;
+ }
+
+ vm->vm_flags |= VM_IO;
+ vm->vm_flags |= VM_RESERVED;
+
+ return 0;
}
-static int svcodec_mmap (struct file *file, struct vm_area_struct *vm)
+static irqreturn_t svcodec_irq_handler (int irq, void *dev_id)
{
- unsigned long off;
- unsigned long phys_addr;
- unsigned long size;
- int ret = -1;
-
- off = vm->vm_pgoff << PAGE_SHIFT;
- phys_addr = (PAGE_ALIGN(svcodec->mem_start) + off) >> PAGE_SHIFT;
- size = vm->vm_end - vm->vm_start;
-
- if (size > svcodec->mem_size) {
- CODEC_ERR_LOG("over mapping size\n");
- return -EINVAL;
- }
-
- ret = remap_pfn_range(vm, vm->vm_start, phys_addr, size, vm->vm_page_prot);
- if (ret < 0) {
- CODEC_ERR_LOG("failed to remap page range\n");
- return -EAGAIN;
- }
-
- vm->vm_flags |= VM_IO;
- vm->vm_flags |= VM_RESERVED;
-
- return 0;
-}
+ struct svcodec_device *dev = (struct svcodec_device *)dev_id;
+ int val = 0;
+ unsigned long flags;
-static int svcodec_open (struct inode *inode, struct file *file)
-{
- int i;
- int max_size = USABLE_MMAP_MAX_SIZE;
+ val = readl(dev->ioaddr + CODEC_QUERY_STATE);
+ if (!(val & CODEC_IRQ)) {
+ CODEC_LOG(KERN_DEBUG, "this irq is not for this module.\n");
+ return IRQ_NONE;
+ }
+
+ spin_lock_irqsave(&dev->lock, flags);
- mutex_lock(&codec_mutex);
+ CODEC_LOG(KERN_DEBUG, "irq is for this module.\n");
+ writel(0, dev->ioaddr + CODEC_QUERY_STATE);
- printk(KERN_DEBUG "%s: open! struct file:%p\n", DRIVER_NAME, file);
- if (svcodec->useMmap[max_size] == 0) {
- for (i = 0; i < max_size; i++) {
- svcodec->useMmap[i] = 1;
- printk(KERN_DEBUG "%s: reset useMmap[%d]=%d\n", DRIVER_NAME, i, svcodec->useMmap[i]);
- }
- }
+ spin_lock_irqsave(&dev->lock, flags);
- try_module_get(THIS_MODULE);
- mutex_unlock(&codec_mutex);
+ dev->sleep_flag = 1;
+ wake_up_interruptible(&dev->codec_wq);
- return 0;
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int svcodec_open(struct inode *inode, struct file *file)
+{
+ int i, max_size = USABLE_MMAP_MAX_SIZE;
+
+ mutex_lock(&codec_mutex);
+ CODEC_LOG(KERN_DEBUG, "open! struct file:%p\n", file);
+
+ svcodec->sleep_flag = 0;
+
+ CODEC_LOG(KERN_DEBUG, "register irq handler\n");
+ /* register interrupt handler */
+ if (request_irq(svcodec->dev->irq, svcodec_irq_handler,
+ IRQF_SHARED, DRIVER_NAME, svcodec)) {
+ CODEC_LOG(KERN_ERR, "failed to register irq handle\n");
+ return -EBUSY;
+ }
+
+ /* reset useMmap array */
+ if (svcodec->useMmap[max_size] == 0) {
+ for (i = 0; i < max_size; i++) {
+ svcodec->useMmap[i] = 1;
+ CODEC_LOG(KERN_DEBUG, "reset useMmap[%d]=%d\n",
+ i, svcodec->useMmap[i]);
+ }
+ }
+
+ try_module_get(THIS_MODULE);
+ mutex_unlock(&codec_mutex);
+
+ return 0;
}
static int svcodec_release (struct inode *inode, struct file *file)
{
- int max_size = USABLE_MMAP_MAX_SIZE;
- uint8_t *useMmap;
+ int max_size = USABLE_MMAP_MAX_SIZE;
+ uint8_t *useMmap;
+
+ mutex_lock(&codec_mutex);
- mutex_lock(&codec_mutex);
+ /* free irq */
+ if (svcodec->dev->irq) {
+ CODEC_LOG(KERN_DEBUG, "free registered irq\n");
+ free_irq(svcodec->dev->irq, svcodec);
+ }
- useMmap = (uint8_t*)file->private_data;
- printk(KERN_DEBUG "%s: close!! struct file:%p, priv_data:%p\n", DRIVER_NAME, file, useMmap);
+ /* manage codec context */
+ useMmap = (uint8_t *)file->private_data;
+ CODEC_LOG(KERN_DEBUG,
+ "close! struct file:%p, priv_data:%p\n", file, useMmap);
- if (file && file->private_data) {
- if (svcodec->useMmap[max_size] > 0) {
- (svcodec->useMmap[max_size])--;
- }
- *useMmap = 1;
- printk(KERN_DEBUG "%s: available useMmap count:%d\n",
- DRIVER_NAME, (max_size - svcodec->useMmap[max_size]));
+ if (file && file->private_data) {
+ if (svcodec->useMmap[max_size] > 0)
+ (svcodec->useMmap[max_size])--;
+ *useMmap = 1;
+ CODEC_LOG(KERN_DEBUG, "available useMmap count:%d\n",
+ (max_size - svcodec->useMmap[max_size]));
- /* notify closing codec device of qemu. */
- writel((uint32_t)file, svcodec->ioaddr + CODEC_CLOSED);
- }
+ /* notify closing codec device of qemu. */
+ writel((uint32_t)file, svcodec->ioaddr + CODEC_CLOSED);
+ }
#ifdef CODEC_DEBUG
- int i;
- for (i = 0; i < max_size; i++) {
- printk(KERN_DEBUG "%s: useMmap[%d]=%d\n", DRIVER_NAME, i, svcodec->useMmap[i]);
- }
+ int i;
+ for (i = 0; i < max_size; i++)
+ CODEC_LOG(KERN_DEBUG, "useMmap[%d]=%d\n",
+ i, svcodec->useMmap[i]);
#endif
- module_put(THIS_MODULE);
- mutex_unlock(&codec_mutex);
+ module_put(THIS_MODULE);
+ mutex_unlock(&codec_mutex);
- return 0;
+ return 0;
}
+/* define file opertion for CODEC */
struct file_operations svcodec_fops = {
- .owner = THIS_MODULE,
- .read = svcodec_read,
- .write = svcodec_write,
- .open = svcodec_open,
- .mmap = svcodec_mmap,
- .release = svcodec_release,
+ .owner = THIS_MODULE,
+ .read = svcodec_read,
+ .write = svcodec_write,
+ .open = svcodec_open,
+ .mmap = svcodec_mmap,
+ .release = svcodec_release,
};
-static void __devinit svcodec_remove (struct pci_dev *pci_dev)
+static int __devinit svcodec_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
{
- if (svcodec) {
- if (svcodec->ioaddr) {
- iounmap(svcodec->ioaddr);
- svcodec->ioaddr = 0;
- }
-
-#if 0
- if (svcodec->memaddr) {
- iounmap(svcodec->memaddr);
- svcodec->memaddr = 0;
- }
-#endif
-
- if (svcodec->io_start) {
- release_mem_region(svcodec->io_start, svcodec->io_size);
- svcodec->io_start = 0;
- }
+ svcodec = kmalloc(sizeof(struct svcodec_device), GFP_KERNEL);
+ memset(svcodec, 0x00, sizeof(struct svcodec_device));
- if (svcodec->mem_start) {
- release_mem_region(svcodec->mem_start, svcodec->mem_size);
- svcodec->mem_start = 0;
- }
+ init_waitqueue_head(&svcodec->codec_wq);
+ spin_lock_init(&svcodec->lock);
- kfree(svcodec);
- }
- pci_disable_device(pci_dev);
-}
-
-static int __devinit svcodec_probe (struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
-{
- svcodec = (svcodec_dev*)kmalloc(sizeof(svcodec_dev), GFP_KERNEL);
- memset(svcodec, 0x00, sizeof(svcodec_dev));
+ svcodec->dev = pci_dev;
- svcodec->dev = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+ CODEC_LOG(KERN_ERR, "pci_enable_device failed\n");
+ goto err_rel;
+ }
- if (pci_enable_device(pci_dev)) {
- CODEC_ERR_LOG("pci_enable_device failed\n");
- goto err_rel;
- }
+ pci_set_master(pci_dev);
- pci_set_master(pci_dev);
+ svcodec->mem_start = pci_resource_start(pci_dev, 0);
+ svcodec->mem_size = pci_resource_len(pci_dev, 0);
- svcodec->mem_start = pci_resource_start(pci_dev, 0);
- svcodec->mem_size = pci_resource_len(pci_dev, 0);
+ if (!svcodec->mem_start) {
+ CODEC_LOG(KERN_ERR, "pci_resource_start failed\n");
+ goto err_out;
+ }
- if (!svcodec->mem_start) {
- CODEC_ERR_LOG("pci_resource_start failed\n");
- goto err_out;
- }
-
- if (!request_mem_region(svcodec->mem_start, svcodec->mem_size, DRIVER_NAME)) {
- CODEC_ERR_LOG("request_mem_region failed\n");
- goto err_out;
- }
+ if (!request_mem_region(svcodec->mem_start,
+ svcodec->mem_size,
+ DRIVER_NAME)) {
+ CODEC_LOG(KERN_ERR, "request_mem_region failed\n");
+ goto err_out;
+ }
- svcodec->io_start = pci_resource_start(pci_dev, 1);
- svcodec->io_size = pci_resource_len(pci_dev, 1);
+ svcodec->io_start = pci_resource_start(pci_dev, 1);
+ svcodec->io_size = pci_resource_len(pci_dev, 1);
- if (!svcodec->io_start) {
- CODEC_ERR_LOG("pci_resource_start failed\n");
- goto err_mem_region;
- }
+ if (!svcodec->io_start) {
+ CODEC_LOG(KERN_ERR, "pci_resource_start failed\n");
+ goto err_mem_region;
+ }
- if (!request_mem_region(svcodec->io_start, svcodec->io_size, DRIVER_NAME)) {
- CODEC_ERR_LOG("request_io_region failed\n");
- goto err_mem_region;
- }
+ if (!request_mem_region(svcodec->io_start,
+ svcodec->io_size,
+ DRIVER_NAME)) {
+ CODEC_LOG(KERN_ERR, "request_io_region failed\n");
+ goto err_mem_region;
+ }
#if 0
- svcodec->memaddr = ioremap(svcodec->mem_start, svcodec->mem_size);
- if (!svcodec->memaddr) {
- CODEC_ERR_LOG( "[%s] : ioremap failed\n", __func__);
- goto err_io_region;
- }
+ svcodec->memaddr = ioremap(svcodec->mem_start, svcodec->mem_size);
+ if (!svcodec->memaddr) {
+ CODEC_LOG(KERN_ERR, "[%s] : ioremap failed\n", __func__);
+ goto err_io_region;
+ }
#endif
- svcodec->ioaddr = ioremap_nocache(svcodec->io_start, svcodec->io_size);
- if (!svcodec->ioaddr) {
- CODEC_ERR_LOG("ioremap failed\n");
- goto err_io_region;
- }
- if (register_chrdev(CODEC_MAJOR, DRIVER_NAME, &svcodec_fops)) {
- CODEC_ERR_LOG("register_chrdev failed\n");
- goto err_io_unmap;
- }
+ svcodec->ioaddr = ioremap_nocache(svcodec->io_start, svcodec->io_size);
+ if (!svcodec->ioaddr) {
+ CODEC_LOG(KERN_ERR, "ioremap failed\n");
+ goto err_io_region;
+ }
- return 0;
+ /* register chrdev */
+ if (register_chrdev(CODEC_MAJOR, DRIVER_NAME, &svcodec_fops)) {
+ CODEC_LOG(KERN_ERR, "register_chrdev failed\n");
+ goto err_io_unmap;
+ }
+
+ return 0;
err_io_unmap:
- iounmap(svcodec->ioaddr);
+ iounmap(svcodec->ioaddr);
#if 0
err_mem_unmap:
- iounmap(svcodec->memaddr);
+ iounmap(svcodec->memaddr);
#endif
err_io_region:
- release_mem_region(svcodec->io_start, svcodec->io_size);
+ release_mem_region(svcodec->io_start, svcodec->io_size);
err_mem_region:
- release_mem_region(svcodec->mem_start, svcodec->mem_size);
+ release_mem_region(svcodec->mem_start, svcodec->mem_size);
err_out:
- pci_disable_device(pci_dev);
+ pci_disable_device(pci_dev);
err_rel:
- return -EIO;
+ return -EIO;
+}
+
+static void __devinit svcodec_remove(struct pci_dev *pci_dev)
+{
+ if (svcodec) {
+ if (svcodec->ioaddr) {
+ iounmap(svcodec->ioaddr);
+ svcodec->ioaddr = 0;
+ }
+
+#if 0
+ if (svcodec->memaddr) {
+ iounmap(svcodec->memaddr);
+ svcodec->memaddr = 0;
+ }
+#endif
+
+ if (svcodec->io_start) {
+ release_mem_region(svcodec->io_start,
+ svcodec->io_size);
+ svcodec->io_start = 0;
+ }
+
+ if (svcodec->mem_start) {
+ release_mem_region(svcodec->mem_start,
+ svcodec->mem_size);
+ svcodec->mem_start = 0;
+ }
+
+ kfree(svcodec);
+ }
+ pci_disable_device(pci_dev);
}
+static struct pci_device_id svcodec_pci_table[] __devinitdata = {
+ {
+ .vendor = PCI_VENDOR_ID_TIZEN,
+ .device = PCI_DEVICE_ID_VIRTUAL_CODEC,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+};
+MODULE_DEVICE_TABLE(pci, svcodec_pci_table);
+
+/* define PCI Driver for CODEC */
static struct pci_driver driver = {
- .name = DRIVER_NAME,
- .id_table = svcodec_pci_table,
- .probe = svcodec_probe,
- .remove = svcodec_remove,
+ .name = DRIVER_NAME,
+ .id_table = svcodec_pci_table,
+ .probe = svcodec_probe,
+ .remove = svcodec_remove,
};
static int __init svcodec_init (void)
{
- printk(KERN_INFO "%s: device is initialized.\n", DRIVER_NAME);
- return pci_register_driver(&driver);
+ CODEC_LOG(KERN_INFO, "device is initialized.\n");
+ return pci_register_driver(&driver);
}
static void __exit svcodec_exit (void)
{
- pci_unregister_driver(&driver);
+ pci_unregister_driver(&driver);
}
module_init(svcodec_init);
module_exit(svcodec_exit);