# CONFIG_TELCLOCK is not set
CONFIG_DEVPORT=y
# CONFIG_XILLYBUS is not set
-CONFIG_VDPRAM=y
#
# I2C support
CONFIG_MARU_VIRTIO_SENSOR=y
CONFIG_MARU_VIRTIO_NFC=y
CONFIG_MARU_BRILLCODEC=y
+CONFIG_MARU_VDPRAM=y
CONFIG_MARU_VIRTIO_VMODEM=y
CONFIG_MARU_VIRTIO_ROTARY=y
CONFIG_MARU_TV=y
source "drivers/char/xillybus/Kconfig"
-config VDPRAM
- tristate "vdpram kernel driver for VMODEM"
- help
- vdpram is a telephony driver works with the Emulator Control Panel.
-
endmenu
obj-$(CONFIG_TILE_SROM) += tile-srom.o
obj-$(CONFIG_XILLYBUS) += xillybus/
-
-obj-$(CONFIG_VDPRAM) += vdpram.o
+++ /dev/null
-/*
- * Virtual DPRAM for emulator
- *
- * Copyright (c) 2009 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Contact:
- * Sooyoung Ha <yoosah.ha@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-#include <linux/types.h>
-#include <linux/kernel.h> /* printk(), min() */
-#include <linux/slab.h> /* kmalloc() */
-#include <linux/fs.h> /* everything... */
-#include <linux/proc_fs.h>
-#include <linux/errno.h> /* error codes */
-#include <linux/types.h> /* size_t */
-#include <linux/fcntl.h>
-#include <linux/poll.h>
-#include <linux/cdev.h>
-#include <linux/device.h>
-#include <linux/sched.h>
-#include <asm/uaccess.h>
-
-#define VDPRAM_MAJOR 249 /* 240 */
-#define VDPRAM_NR_DEVS 2
-#define VDPRAM_BUFFER (16*1024)
-#define VDPRAM_SEM_UNLOCK 100
-#define VDPRAM_SEM_LOCK 200
-#define VDPRAM_STATUS 300
-#define VDPRAM_LOCK_ENABLE
-
-
-/* #if 1
-#define printk(...)
-#endif
-*/
-
-MODULE_LICENSE("GPL");
-
-struct buffer_t {
- char *begin;
- char *end;
- int buffersize;
- struct semaphore sem;
-};
-
-struct queue_t {
- wait_queue_head_t inq;
- wait_queue_head_t outq;
-};
-
-struct vdpram_dev {
- int flag;
- struct vdpram_dev *adj;
- char *rp, *wp; /* where to read, where to write */
- int nreaders, nwriters; /* number of openings for r/w */
- struct fasync_struct *async_queue; /* asynchronous readers */
- struct cdev cdev; /* Char device structure */
- int index;
- int adj_index;
-};
-
-struct vdpram_status_dev {
- int index;
- char *rp, *wp; /* where to read, where to write */
- int rp_cnt;
- int wp_cnt;
-
- int adj_index;
- char *adj_rp, *adj_wp; /* where to read, where to write */
- int adj_rp_cnt;
- int adj_wp_cnt;
-};
-
-
-/* parameters */
-static int vdpram_nr_devs = VDPRAM_NR_DEVS; /* number of devices */
-int vdpram_buffer = VDPRAM_BUFFER; /* buffer size */
-dev_t vdpram_devno; /* Our first device number */
-int vdpram_major = VDPRAM_MAJOR;
-
-module_param(vdpram_nr_devs, int, 0); /* FIXME check perms */
-module_param(vdpram_buffer, int, 0);
-
-static struct vdpram_dev *vdpram_devices;
-static struct buffer_t *buffer;
-static struct queue_t *queue;
-static struct class *vdpram_class;
-
-static int vdpram_fasync(int fd, struct file *filp, int mode);
-static int spacefree(struct vdpram_dev *dev);
-
-long vdpram_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
-
-/* Open and close */
-static int vdpram_open(struct inode *inode, struct file *filp)
-{
- struct vdpram_dev *dev;
- int index;
-
- dev = container_of(inode->i_cdev, struct vdpram_dev, cdev);
- filp->private_data = dev;
- index = dev->index ;
-
-// printk("%s:%d:index:%d\n", __FUNCTION__,current->pid,index);
-
-#ifdef VDPRAM_LOCK_ENABLE
- if (down_interruptible(&buffer[index].sem))
- return -ERESTARTSYS;
-#endif //VDPRAM_LOCK_ENABLE
-
- dev->wp = dev->adj->rp = buffer[index].begin; /* rd and wr from the beginning */
-
- /* use f_mode,not f_flags: it's cleaner (fs/open.c tells why) */
- if (filp->f_mode & FMODE_READ)
- dev->nreaders++;
- if (filp->f_mode & FMODE_WRITE)
- dev->nwriters++;
-#ifdef VDPRAM_LOCK_ENABLE
- up(&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
-
- return nonseekable_open(inode, filp);
-}
-
-
-
-static int vdpram_release(struct inode *inode, struct file *filp)
-{
- struct vdpram_dev *dev = filp->private_data;
- int index = dev->index ;
-
-// printk("%s:%d\n", __FUNCTION__,current->pid);
-
- /* remove this filp from the asynchronously notified filp's */
- vdpram_fasync(-1, filp, 0);
-#ifdef VDPRAM_LOCK_ENABLE
- down(&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- if (filp->f_mode & FMODE_READ)
- dev->nreaders--;
- if (filp->f_mode & FMODE_WRITE)
- dev->nwriters--;
- if (dev->nreaders + dev->nwriters == 0) {
- //kfree(dev->buffer);
- //dev->buffer = NULL; /* the other fields are not checked on open */
- }
-#ifdef VDPRAM_LOCK_ENABLE
- up(&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- return 0;
-}
-
-
-/*
- * Data management: read and write
- */
-
-static ssize_t vdpram_read (struct file *filp, char __user *buf, size_t count,
- loff_t *f_pos)
-{
- struct vdpram_dev *dev = filp->private_data;
- int index = dev->adj_index ;
- char *curr_rp, *curr_adj_wp;
- int restData_len = 0, data_len = 0;
-#if 0
- int i = 0; /* for debug */
-#endif
-// printk("%s:%d start rp=%x adj_wp=%x \n", __FUNCTION__,current->pid, dev->rp, dev->adj->wp);
-
-#ifdef VDPRAM_LOCK_ENABLE
- if (down_interruptible(&buffer[index].sem))
- return -ERESTARTSYS;
-#endif //VDPRAM_LOCK_ENABLE
- curr_rp = dev->rp;
- curr_adj_wp = dev->adj->wp ;
-#ifdef VDPRAM_LOCK_ENABLE
- up(&buffer[index].sem); /* release the lock */
-#endif //VDPRAM_LOCK_ENABLE
-
- while (curr_rp == curr_adj_wp) { /* nothing to read */
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- if (wait_event_interruptible(queue[index].inq, (dev->adj->wp != dev->rp)))
- return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
- /* otherwise loop, but first reacquire the lock */
-#ifdef VDPRAM_LOCK_ENABLE
- if (down_interruptible(&buffer[index].sem))
- return -ERESTARTSYS;
-#endif //VDPRAM_LOCK_ENABLE
- curr_rp = dev->rp;
- curr_adj_wp = dev->adj->wp ;
-#ifdef VDPRAM_LOCK_ENABLE
- up(&buffer[index].sem); /* release the lock */
-#endif //VDPRAM_LOCK_ENABLE
- }
- /* ok, data is there, return something */
-#ifdef VDPRAM_LOCK_ENABLE
- if (down_interruptible(&buffer[index].sem))
- return -ERESTARTSYS;
-#endif //VDPRAM_LOCK_ENABLE
-
- if (dev->adj->wp > dev->rp)
- {
- count = min(count, (size_t)(dev->adj->wp - dev->rp));
- data_len = count;
- if (copy_to_user(buf, dev->rp, count)) {
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- return -EFAULT;
- }
-
- dev->rp += count;
- if (dev->rp >= buffer[index].end)
- {
- dev->rp = buffer[index].begin; /* wrapped */
- }
- }
- else /* the write pointer has wrapped, return data up to dev->end */
- {
- data_len = min(count, (size_t)(buffer[index].end - dev->rp));
- if (copy_to_user(buf, dev->rp, data_len)) {
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- return -EFAULT;
- }
-
- dev->rp += data_len;
- if(dev->rp >= buffer[index].end)
- dev->rp = buffer[index].begin;
-
- if ( count - data_len > 0)
- {
- restData_len = min ( count - data_len, (size_t)(dev->adj->wp - buffer[index].begin));
- if (copy_to_user(buf + data_len, dev->rp, restData_len)) {
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- return -EFAULT;
- }
- dev->rp += restData_len;
- }
- }
-
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
-
-#ifdef NOT_CIRCLE_QUEUE // hwjang del for circular queue
- if (copy_to_user(buf, dev->rp, count)) {
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- return -EFAULT;
- }
-
- dev->rp += count;
- if(dev->rp >= buffer[index].end)
- {
- dev->rp = buffer[index].begin; /* wrapped */
- }
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
-#endif //NOT_CIRCLE_QUEUE
-
-// printk("%s:%d rp[%d]=%d cnt=%d \n", __FUNCTION__,current->pid,dev->index, dev->rp-buffer[index].begin,count);
- /* finally, awake any writers and return */
- wake_up_interruptible(&queue[index].outq);
- return data_len + restData_len;
-}
-
-/* Wait for space for writing; caller must hold device semaphore. On
- * error the semaphore will be released before returning. */
-static int vdpram_getwritespace(struct vdpram_dev *dev, struct file *filp)
-{
- int ret ;
- int index = dev->index ;
-
- while (spacefree(dev) == 0) { /* full */
- DEFINE_WAIT(wait);
-
-#ifdef VDPRAM_LOCK_ENABLE
- up(&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- prepare_to_wait(&queue[index].outq, &wait, TASK_INTERRUPTIBLE);
-#ifdef VDPRAM_LOCK_ENABLE
- if (down_interruptible(&buffer[index].sem))
- return -ERESTARTSYS;
-#endif //VDPRAM_LOCK_ENABLE
- ret = spacefree(dev) ;
-#ifdef VDPRAM_LOCK_ENABLE
- up(&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- if (ret == 0)
- schedule();
- finish_wait(&queue[index].outq, &wait);
- if (signal_pending(current))
- return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
-#ifdef VDPRAM_LOCK_ENABLE
- if (down_interruptible(&buffer[index].sem))
- return -ERESTARTSYS;
-#endif //VDPRAM_LOCK_ENABLE
- }
- return 0;
-}
-
-/* How much space is free? */
-static int spacefree(struct vdpram_dev *dev)
-{
- int index = dev->index;
-
- if (dev->wp == dev->adj->rp)
- return buffer[index].buffersize - 1;
- return ((dev->adj->rp + buffer[index].buffersize - dev->wp) % buffer[index].buffersize) - 1;
-}
-
-static ssize_t vdpram_write(struct file *filp, const char __user *buf, size_t count,
- loff_t *f_pos)
-{
- struct vdpram_dev *dev = filp->private_data;
- int result;
- int index = dev->index ;
-
-#ifdef VDPRAM_LOCK_ENABLE
- if (down_interruptible(&buffer[index].sem))
- return -ERESTARTSYS;
-#endif //VDPRAM_LOCK_ENABLE
-
- /* Make sure there's space to write */
- result = vdpram_getwritespace(dev, filp);
- if (result)
- return result; /* vdpram_getwritespace called up(&dev->sem) */
-
- /* ok, space is there, accept something */
- count = min(count, (size_t)spacefree(dev));
- // hwjang need to be fixed for full circular queue
- if ( count > 0 )
- {
- if (dev->wp >= dev->adj->rp)
- {
- int data_len;
- data_len = min(count, (size_t)(buffer[index].end - dev->wp)); /* to end-of-buf */
-
- if (data_len != 0 && copy_from_user(dev->wp, buf, data_len))
- {
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- return -EFAULT;
- }
-
- dev->wp += data_len;
- if (dev->wp >= buffer[index].end)
- {
-// printk("%s: back 0 !! \n",__FUNCTION__);
- dev->wp = buffer[index].begin; /* wrapped */
- }
-
- if (count - data_len > 0 )
- {
- int restData_len = 0;
- restData_len = min ( count - data_len, (size_t)(dev->adj->rp - buffer[index].begin) - 1 );
- if(copy_from_user(dev->wp, buf + data_len, restData_len))
- {
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- return -EFAULT;
- }
- dev->wp += restData_len;
- }
- }
- else /* the write pointer has wrapped, fill up to rp-1 */
- {
- count = min(count, (size_t)(dev->adj->rp - dev->wp - 1));
-
- if (copy_from_user(dev->wp, buf, count)) {
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- return -EFAULT;
- }
-
- dev->wp += count;
- if (dev->wp > buffer[index].end)
- {
-// printk("%s: back 0 !! \n",__FUNCTION__);
- dev->wp = buffer[index].begin; /* wrapped */
- }
-
- }
- }
- /* for debug */
-#if 0
- int i;
- printk("write[%d]: ", index);
- for(i=0; i<count; ++i) {
- printk("%x ", *(dev->wp+i));
- }
- printk("\n");
-#endif
-
-#ifdef NOT_CIRCLE_QUEUE // hwjang del for circular queue
- if (copy_from_user(dev->wp, buf, count)) {
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- return -EFAULT;
- }
- dev->wp += count;
- if (dev->wp == buffer[index].end)
- {
- dev->wp = buffer[index].begin; /* wrapped */
- }
-#endif // NOT_CIRCLE_QUEUE
-
-
-#ifdef VDPRAM_LOCK_ENABLE
- up(&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
-
-// printk("%s:%d wp[%d]=%d, cnt=%d \n", __FUNCTION__,current->pid,dev->index, dev->wp -buffer[index].begin, count);
- /* finally, awake any reader */
- wake_up_interruptible(&queue[index].inq); /* blocked in read() and select() */
-
- /* and signal asynchronous readers, explained late in chapter 5 */
- if (dev->async_queue)
- kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
- return count;
-}
-
-static unsigned int vdpram_poll(struct file *filp, poll_table *wait)
-{
- struct vdpram_dev *dev = filp->private_data;
- unsigned int mask = 0;
-
-// printk("%s:%d:index:%d\n", __FUNCTION__,current->pid,dev->index);
- /*
- * The buffer is circular; it is considered full
- * if "wp" is right behind "rp" and empty if the
- * two are equal.
- */
- poll_wait(filp, &queue[dev->adj_index].inq, wait);
- poll_wait(filp, &queue[dev->index].outq, wait);
-
-#ifdef VDPRAM_LOCK_ENABLE
- down(&buffer[dev->adj_index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- if (dev->rp && dev->adj->wp && (dev->rp != dev->adj->wp))
- mask |= POLLIN | POLLRDNORM; /* readable */
-#ifdef VDPRAM_LOCK_ENABLE
- up(&buffer[dev->adj_index].sem);
-#endif //VDPRAM_LOCK_ENABLE
-
-#ifdef VDPRAM_LOCK_ENABLE
- down(&buffer[dev->index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- if (spacefree(dev))
- mask |= POLLOUT | POLLWRNORM; /* writable */
-#ifdef VDPRAM_LOCK_ENABLE
- up(&buffer[dev->index].sem);
-#endif //VDPRAM_LOCK_ENABLE
-// printk("%s:%d:index:%d:end!!\n", __FUNCTION__,current->pid,index);
- return mask;
-}
-
-
-static int vdpram_fasync(int fd, struct file *filp, int mode)
-{
- struct vdpram_dev *dev = filp->private_data;
-
- return fasync_helper(fd, filp, mode, &dev->async_queue);
-}
-
-
-/*
- * The file operations for the vdpram device
- */
-struct file_operations vdpram_even_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = vdpram_read,
- .write = vdpram_write,
- .poll = vdpram_poll,
- .open = vdpram_open,
- .release = vdpram_release,
- .fasync = vdpram_fasync,
- .unlocked_ioctl = vdpram_ioctl,
-};
-
-struct file_operations vdpram_odd_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = vdpram_read,
- .write = vdpram_write,
- .poll = vdpram_poll,
- .open = vdpram_open,
- .release = vdpram_release,
- .fasync = vdpram_fasync,
- .unlocked_ioctl = vdpram_ioctl,
-};
-
-long vdpram_ioctl(struct file* filp, unsigned int cmd, unsigned long arg)
-{
- struct vdpram_dev *dev;
- struct vdpram_status_dev dev_status;
- int index;
- dev = (struct vdpram_dev*)filp->private_data;
- index = dev->index ;
-
- memset( &dev_status, 0, sizeof(struct vdpram_status_dev));
-
- switch( cmd )
- {
- case VDPRAM_SEM_UNLOCK :
-#ifdef VDPRAM_LOCK_ENABLE
- up (&buffer[index].sem);
-#endif //VDPRAM_LOCK_ENABLE
- break;
- case VDPRAM_STATUS :
- dev_status.index = dev->index;
- dev_status.adj_index = dev->adj_index;
-
- dev_status.rp = dev->rp;
- dev_status.wp = dev->wp;
- dev_status.adj_rp = dev->rp;
- dev_status.adj_wp = dev->wp;
-
- if ( dev_status.rp != 0 )
- dev_status.rp_cnt = dev->rp-buffer[index].begin;
-
- if ( dev_status.wp != 0 )
- dev_status.wp_cnt = dev->wp-buffer[index].begin;
-
- dev_status.adj_rp = dev->adj->rp;
- dev_status.adj_wp = dev->adj->wp;
-
- if ( dev_status.adj_rp != 0 )
- dev_status.adj_rp_cnt = dev->adj->rp-buffer[dev->adj_index].begin;
- if ( dev_status.adj_wp != 0 )
- dev_status.adj_wp_cnt = dev->adj->wp-buffer[dev->adj_index].begin;
-
-
- if (copy_to_user((char*)arg, &dev_status, sizeof(struct vdpram_status_dev))) {
- return -EFAULT;
- }
- default :
-// printk("%s[%d]:p=%d:cmd=%d\n", __FUNCTION__,index,current->pid,cmd);
- break;
-
- }
- return 0;
-}
-
-/*
- * Set up a cdev entry.
- */
-static void vdpram_setup_cdev(struct vdpram_dev *dev, int index)
-{
- dev_t node = MKDEV(vdpram_major, index);
- int err;
- int is_odd = index & 1; // "index % 2" equivalent
-
- dev->flag = !is_odd;
- cdev_init(&dev->cdev, is_odd ? &vdpram_odd_fops : &vdpram_even_fops);
- dev->cdev.owner = THIS_MODULE;
- err = cdev_add (&dev->cdev, node, 1);
- dev->index = index;
-
- /* Fail gracefully if need be */
- if (err)
- printk(KERN_NOTICE "Error %d adding device%d\n", err, index);
-}
-
-static char *vdpram_devnode(struct device *dev, umode_t *mode)
-{
- return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
-}
-
-/* Initialize the devs; return how many we did */
-int vdpram_init(void)
-{
- int i, result;
- dev_t dev = MKDEV(vdpram_major, 0);
-
- printk("Initializing vdpram device driver ...\n");
- result = register_chrdev_region(dev, vdpram_nr_devs, "vdpram");
- if (result < 0) {
- printk("Unable to get vdpram region, error %d\n", result);
- goto err_out;
- }
-
- printk("vdpram device major num = %d \n", vdpram_major);
- vdpram_devno = dev;
-
- vdpram_devices = kmalloc(vdpram_nr_devs * sizeof(struct vdpram_dev), GFP_KERNEL);
- buffer = kmalloc(vdpram_nr_devs * sizeof(struct buffer_t), GFP_KERNEL);
- queue = kmalloc(vdpram_nr_devs * sizeof(struct queue_t), GFP_KERNEL);
- if (!vdpram_devices || !buffer || !queue) {
- result = -ENOMEM;
- goto err_alloc;
- }
-
- vdpram_class = class_create(THIS_MODULE, "vdpram");
- if (IS_ERR(vdpram_class)) {
- result = PTR_ERR(vdpram_class);
- goto err_alloc;
- }
- vdpram_class->devnode = vdpram_devnode;
-
- memset(vdpram_devices, 0, vdpram_nr_devs * sizeof(struct vdpram_dev));
- for (i = 0; i < vdpram_nr_devs; i++) {
- if (i% 2 ==1) {
- vdpram_devices[i].adj = &vdpram_devices[i-1];
- vdpram_devices[i-1].adj = &vdpram_devices[i];
-// hwjang
- vdpram_devices[i].adj->adj_index=i;
- vdpram_devices[i-1].adj->adj_index=i-1;
- }
- vdpram_setup_cdev(vdpram_devices + i, i);
- }
-
- memset(buffer, 0, vdpram_nr_devs * sizeof(struct buffer_t));
- // hwjang fix buffer -> queue
- memset(queue, 0, vdpram_nr_devs * sizeof(struct queue_t));
- for (i = 0; i < vdpram_nr_devs; i++) {
-#ifdef VDPRAM_LOCK_ENABLE
-// init_MUTEX(&buffer[i].sem);
- sema_init(&buffer[i].sem, 1);
-#endif //VDPRAM_LOCK_ENABLE
- buffer[i].begin = kmalloc(vdpram_buffer, GFP_KERNEL);
- buffer[i].buffersize = vdpram_buffer;
- buffer[i].end = buffer[i].begin + buffer[i].buffersize;
-
- init_waitqueue_head(&queue[i].inq);
- init_waitqueue_head(&queue[i].outq);
-//printk("%s buffer[%x].begin =%x\n", __FUNCTION__, i, buffer[i].begin );
-//printk("%s buffer[%x].buffersize =%x\n", __FUNCTION__, i, buffer[i].buffersize );
-//printk("%s buffer[%x].end =%x\n", __FUNCTION__, i, buffer[i].end );
- }
-
- for (i = 0; i < vdpram_nr_devs; i++)
- device_create(vdpram_class, NULL, MKDEV(vdpram_major, i), NULL,
- kasprintf(GFP_KERNEL, "vdpram%d", i));
-
- return 0;
-
-err_alloc:
- kfree(vdpram_devices);
- kfree(buffer);
- kfree(queue);
-
- unregister_chrdev_region(dev, vdpram_nr_devs);
-
-err_out:
- return result;
-}
-
-/*
- * This is called by cleanup_module or on failure.
- * It is required to never fail, even if nothing was initialized first
- */
-void vdpram_cleanup(void)
-{
- int i;
-
-// printk("%s:%d\n", __FUNCTION__,current->pid);
-
- if (!vdpram_devices)
- return; /* nothing else to release */
-
- for (i = 0; i < vdpram_nr_devs; i++) {
- device_destroy(vdpram_class, MKDEV(vdpram_major, i));
- cdev_del(&vdpram_devices[i].cdev);
- }
- class_destroy(vdpram_class);
- kfree(vdpram_devices);
-
- for (i= 0;i < vdpram_nr_devs ; i++) {
- kfree(buffer[i].begin);
- }
- kfree(buffer);
-
- unregister_chrdev_region(vdpram_devno, vdpram_nr_devs);
- vdpram_devices = NULL; /* pedantic */
-}
-
-module_init(vdpram_init);
-module_exit(vdpram_cleanup);
tristate "MARU brillcodec driver"
depends on MARU != n
+config MARU_VDPRAM
+ tristate "vdpram kernel driver for VMODEM"
+ depends on MARU != n
+
config MARU_VIRTIO_VMODEM
tristate "MARU VirtIO Virtual Modem Device Driver"
depends on MARU != n
obj-$(CONFIG_MARU_VIRTIO_EVDI) += maru_virtio_evdi.o
obj-$(CONFIG_MARU_VIRTIO_SENSOR) += sensors/ #maru_virtio_sensor.o
obj-$(CONFIG_MARU_BRILLCODEC) += maru_brillcodec.o
+obj-$(CONFIG_MARU_VDPRAM) += maru_vdpram.o
obj-$(CONFIG_MARU_VIRTIO_VMODEM) += maru_virtio_vmodem.o
obj-$(CONFIG_MARU_VIRTIO_ROTARY) += maru_virtio_rotary.o
obj-$(CONFIG_MARU_VIRTIO_TABLET) += maru_virtio_tablet.o
--- /dev/null
+/*
+ * Virtual DPRAM for emulator
+ *
+ * Copyright (c) 2009 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Sooyoung Ha <yoosah.ha@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/types.h>
+#include <linux/kernel.h> /* printk(), min() */
+#include <linux/slab.h> /* kmalloc() */
+#include <linux/fs.h> /* everything... */
+#include <linux/proc_fs.h>
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+
+#define VDPRAM_NR_DEVS 2
+#define VDPRAM_BUFFER (16*1024)
+#define VDPRAM_SEM_UNLOCK 100
+#define VDPRAM_SEM_LOCK 200
+#define VDPRAM_STATUS 300
+#define VDPRAM_LOCK_ENABLE
+
+
+/* #if 1
+#define printk(...)
+#endif
+*/
+
+MODULE_LICENSE("GPL");
+
+struct buffer_t {
+ char *begin;
+ char *end;
+ int buffersize;
+ struct semaphore sem;
+};
+
+struct queue_t {
+ wait_queue_head_t inq;
+ wait_queue_head_t outq;
+};
+
+struct vdpram_dev {
+ int flag;
+ struct vdpram_dev *adj;
+ char *rp, *wp; /* where to read, where to write */
+ int nreaders, nwriters; /* number of openings for r/w */
+ struct fasync_struct *async_queue; /* asynchronous readers */
+ struct cdev cdev; /* Char device structure */
+ int index;
+ int adj_index;
+};
+
+struct vdpram_status_dev {
+ int index;
+ char *rp, *wp; /* where to read, where to write */
+ int rp_cnt;
+ int wp_cnt;
+
+ int adj_index;
+ char *adj_rp, *adj_wp; /* where to read, where to write */
+ int adj_rp_cnt;
+ int adj_wp_cnt;
+};
+
+
+/* parameters */
+static int vdpram_nr_devs = VDPRAM_NR_DEVS; /* number of devices */
+int vdpram_buffer = VDPRAM_BUFFER; /* buffer size */
+dev_t vdpram_devno; /* Our first device number */
+int vdpram_major = 0;
+
+module_param(vdpram_nr_devs, int, 0); /* FIXME check perms */
+module_param(vdpram_buffer, int, 0);
+
+static struct vdpram_dev *vdpram_devices;
+static struct buffer_t *buffer;
+static struct queue_t *queue;
+static struct class *vdpram_class;
+
+static int vdpram_fasync(int fd, struct file *filp, int mode);
+static int spacefree(struct vdpram_dev *dev);
+
+long vdpram_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+
+/* Open and close */
+static int vdpram_open(struct inode *inode, struct file *filp)
+{
+ struct vdpram_dev *dev;
+ int index;
+
+ dev = container_of(inode->i_cdev, struct vdpram_dev, cdev);
+ filp->private_data = dev;
+ index = dev->index ;
+
+// printk("%s:%d:index:%d\n", __FUNCTION__,current->pid,index);
+
+#ifdef VDPRAM_LOCK_ENABLE
+ if (down_interruptible(&buffer[index].sem))
+ return -ERESTARTSYS;
+#endif //VDPRAM_LOCK_ENABLE
+
+ dev->wp = dev->adj->rp = buffer[index].begin; /* rd and wr from the beginning */
+
+ /* use f_mode,not f_flags: it's cleaner (fs/open.c tells why) */
+ if (filp->f_mode & FMODE_READ)
+ dev->nreaders++;
+ if (filp->f_mode & FMODE_WRITE)
+ dev->nwriters++;
+#ifdef VDPRAM_LOCK_ENABLE
+ up(&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+
+ return nonseekable_open(inode, filp);
+}
+
+
+
+static int vdpram_release(struct inode *inode, struct file *filp)
+{
+ struct vdpram_dev *dev = filp->private_data;
+ int index = dev->index ;
+
+// printk("%s:%d\n", __FUNCTION__,current->pid);
+
+ /* remove this filp from the asynchronously notified filp's */
+ vdpram_fasync(-1, filp, 0);
+#ifdef VDPRAM_LOCK_ENABLE
+ down(&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ if (filp->f_mode & FMODE_READ)
+ dev->nreaders--;
+ if (filp->f_mode & FMODE_WRITE)
+ dev->nwriters--;
+ if (dev->nreaders + dev->nwriters == 0) {
+ //kfree(dev->buffer);
+ //dev->buffer = NULL; /* the other fields are not checked on open */
+ }
+#ifdef VDPRAM_LOCK_ENABLE
+ up(&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ return 0;
+}
+
+
+/*
+ * Data management: read and write
+ */
+
+static ssize_t vdpram_read (struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ struct vdpram_dev *dev = filp->private_data;
+ int index = dev->adj_index ;
+ char *curr_rp, *curr_adj_wp;
+ int restData_len = 0, data_len = 0;
+#if 0
+ int i = 0; /* for debug */
+#endif
+// printk("%s:%d start rp=%x adj_wp=%x \n", __FUNCTION__,current->pid, dev->rp, dev->adj->wp);
+
+#ifdef VDPRAM_LOCK_ENABLE
+ if (down_interruptible(&buffer[index].sem))
+ return -ERESTARTSYS;
+#endif //VDPRAM_LOCK_ENABLE
+ curr_rp = dev->rp;
+ curr_adj_wp = dev->adj->wp ;
+#ifdef VDPRAM_LOCK_ENABLE
+ up(&buffer[index].sem); /* release the lock */
+#endif //VDPRAM_LOCK_ENABLE
+
+ while (curr_rp == curr_adj_wp) { /* nothing to read */
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ if (wait_event_interruptible(queue[index].inq, (dev->adj->wp != dev->rp)))
+ return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
+ /* otherwise loop, but first reacquire the lock */
+#ifdef VDPRAM_LOCK_ENABLE
+ if (down_interruptible(&buffer[index].sem))
+ return -ERESTARTSYS;
+#endif //VDPRAM_LOCK_ENABLE
+ curr_rp = dev->rp;
+ curr_adj_wp = dev->adj->wp ;
+#ifdef VDPRAM_LOCK_ENABLE
+ up(&buffer[index].sem); /* release the lock */
+#endif //VDPRAM_LOCK_ENABLE
+ }
+ /* ok, data is there, return something */
+#ifdef VDPRAM_LOCK_ENABLE
+ if (down_interruptible(&buffer[index].sem))
+ return -ERESTARTSYS;
+#endif //VDPRAM_LOCK_ENABLE
+
+ if (dev->adj->wp > dev->rp)
+ {
+ count = min(count, (size_t)(dev->adj->wp - dev->rp));
+ data_len = count;
+ if (copy_to_user(buf, dev->rp, count)) {
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ return -EFAULT;
+ }
+
+ dev->rp += count;
+ if (dev->rp >= buffer[index].end)
+ {
+ dev->rp = buffer[index].begin; /* wrapped */
+ }
+ }
+ else /* the write pointer has wrapped, return data up to dev->end */
+ {
+ data_len = min(count, (size_t)(buffer[index].end - dev->rp));
+ if (copy_to_user(buf, dev->rp, data_len)) {
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ return -EFAULT;
+ }
+
+ dev->rp += data_len;
+ if(dev->rp >= buffer[index].end)
+ dev->rp = buffer[index].begin;
+
+ if ( count - data_len > 0)
+ {
+ restData_len = min ( count - data_len, (size_t)(dev->adj->wp - buffer[index].begin));
+ if (copy_to_user(buf + data_len, dev->rp, restData_len)) {
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ return -EFAULT;
+ }
+ dev->rp += restData_len;
+ }
+ }
+
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+
+#ifdef NOT_CIRCLE_QUEUE // hwjang del for circular queue
+ if (copy_to_user(buf, dev->rp, count)) {
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ return -EFAULT;
+ }
+
+ dev->rp += count;
+ if(dev->rp >= buffer[index].end)
+ {
+ dev->rp = buffer[index].begin; /* wrapped */
+ }
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+#endif //NOT_CIRCLE_QUEUE
+
+// printk("%s:%d rp[%d]=%d cnt=%d \n", __FUNCTION__,current->pid,dev->index, dev->rp-buffer[index].begin,count);
+ /* finally, awake any writers and return */
+ wake_up_interruptible(&queue[index].outq);
+ return data_len + restData_len;
+}
+
+/* Wait for space for writing; caller must hold device semaphore. On
+ * error the semaphore will be released before returning. */
+static int vdpram_getwritespace(struct vdpram_dev *dev, struct file *filp)
+{
+ int ret ;
+ int index = dev->index ;
+
+ while (spacefree(dev) == 0) { /* full */
+ DEFINE_WAIT(wait);
+
+#ifdef VDPRAM_LOCK_ENABLE
+ up(&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ prepare_to_wait(&queue[index].outq, &wait, TASK_INTERRUPTIBLE);
+#ifdef VDPRAM_LOCK_ENABLE
+ if (down_interruptible(&buffer[index].sem))
+ return -ERESTARTSYS;
+#endif //VDPRAM_LOCK_ENABLE
+ ret = spacefree(dev) ;
+#ifdef VDPRAM_LOCK_ENABLE
+ up(&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ if (ret == 0)
+ schedule();
+ finish_wait(&queue[index].outq, &wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
+#ifdef VDPRAM_LOCK_ENABLE
+ if (down_interruptible(&buffer[index].sem))
+ return -ERESTARTSYS;
+#endif //VDPRAM_LOCK_ENABLE
+ }
+ return 0;
+}
+
+/* How much space is free? */
+static int spacefree(struct vdpram_dev *dev)
+{
+ int index = dev->index;
+
+ if (dev->wp == dev->adj->rp)
+ return buffer[index].buffersize - 1;
+ return ((dev->adj->rp + buffer[index].buffersize - dev->wp) % buffer[index].buffersize) - 1;
+}
+
+static ssize_t vdpram_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ struct vdpram_dev *dev = filp->private_data;
+ int result;
+ int index = dev->index ;
+
+#ifdef VDPRAM_LOCK_ENABLE
+ if (down_interruptible(&buffer[index].sem))
+ return -ERESTARTSYS;
+#endif //VDPRAM_LOCK_ENABLE
+
+ /* Make sure there's space to write */
+ result = vdpram_getwritespace(dev, filp);
+ if (result)
+ return result; /* vdpram_getwritespace called up(&dev->sem) */
+
+ /* ok, space is there, accept something */
+ count = min(count, (size_t)spacefree(dev));
+ // hwjang need to be fixed for full circular queue
+ if ( count > 0 )
+ {
+ if (dev->wp >= dev->adj->rp)
+ {
+ int data_len;
+ data_len = min(count, (size_t)(buffer[index].end - dev->wp)); /* to end-of-buf */
+
+ if (data_len != 0 && copy_from_user(dev->wp, buf, data_len))
+ {
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ return -EFAULT;
+ }
+
+ dev->wp += data_len;
+ if (dev->wp >= buffer[index].end)
+ {
+// printk("%s: back 0 !! \n",__FUNCTION__);
+ dev->wp = buffer[index].begin; /* wrapped */
+ }
+
+ if (count - data_len > 0 )
+ {
+ int restData_len = 0;
+ restData_len = min ( count - data_len, (size_t)(dev->adj->rp - buffer[index].begin) - 1 );
+ if(copy_from_user(dev->wp, buf + data_len, restData_len))
+ {
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ return -EFAULT;
+ }
+ dev->wp += restData_len;
+ }
+ }
+ else /* the write pointer has wrapped, fill up to rp-1 */
+ {
+ count = min(count, (size_t)(dev->adj->rp - dev->wp - 1));
+
+ if (copy_from_user(dev->wp, buf, count)) {
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ return -EFAULT;
+ }
+
+ dev->wp += count;
+ if (dev->wp > buffer[index].end)
+ {
+// printk("%s: back 0 !! \n",__FUNCTION__);
+ dev->wp = buffer[index].begin; /* wrapped */
+ }
+
+ }
+ }
+ /* for debug */
+#if 0
+ int i;
+ printk("write[%d]: ", index);
+ for(i=0; i<count; ++i) {
+ printk("%x ", *(dev->wp+i));
+ }
+ printk("\n");
+#endif
+
+#ifdef NOT_CIRCLE_QUEUE // hwjang del for circular queue
+ if (copy_from_user(dev->wp, buf, count)) {
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ return -EFAULT;
+ }
+ dev->wp += count;
+ if (dev->wp == buffer[index].end)
+ {
+ dev->wp = buffer[index].begin; /* wrapped */
+ }
+#endif // NOT_CIRCLE_QUEUE
+
+
+#ifdef VDPRAM_LOCK_ENABLE
+ up(&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+
+// printk("%s:%d wp[%d]=%d, cnt=%d \n", __FUNCTION__,current->pid,dev->index, dev->wp -buffer[index].begin, count);
+ /* finally, awake any reader */
+ wake_up_interruptible(&queue[index].inq); /* blocked in read() and select() */
+
+ /* and signal asynchronous readers, explained late in chapter 5 */
+ if (dev->async_queue)
+ kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
+ return count;
+}
+
+static unsigned int vdpram_poll(struct file *filp, poll_table *wait)
+{
+ struct vdpram_dev *dev = filp->private_data;
+ unsigned int mask = 0;
+
+// printk("%s:%d:index:%d\n", __FUNCTION__,current->pid,dev->index);
+ /*
+ * The buffer is circular; it is considered full
+ * if "wp" is right behind "rp" and empty if the
+ * two are equal.
+ */
+ poll_wait(filp, &queue[dev->adj_index].inq, wait);
+ poll_wait(filp, &queue[dev->index].outq, wait);
+
+#ifdef VDPRAM_LOCK_ENABLE
+ down(&buffer[dev->adj_index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ if (dev->rp && dev->adj->wp && (dev->rp != dev->adj->wp))
+ mask |= POLLIN | POLLRDNORM; /* readable */
+#ifdef VDPRAM_LOCK_ENABLE
+ up(&buffer[dev->adj_index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+
+#ifdef VDPRAM_LOCK_ENABLE
+ down(&buffer[dev->index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ if (spacefree(dev))
+ mask |= POLLOUT | POLLWRNORM; /* writable */
+#ifdef VDPRAM_LOCK_ENABLE
+ up(&buffer[dev->index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+// printk("%s:%d:index:%d:end!!\n", __FUNCTION__,current->pid,index);
+ return mask;
+}
+
+
+static int vdpram_fasync(int fd, struct file *filp, int mode)
+{
+ struct vdpram_dev *dev = filp->private_data;
+
+ return fasync_helper(fd, filp, mode, &dev->async_queue);
+}
+
+
+/*
+ * The file operations for the vdpram device
+ */
+struct file_operations vdpram_even_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = vdpram_read,
+ .write = vdpram_write,
+ .poll = vdpram_poll,
+ .open = vdpram_open,
+ .release = vdpram_release,
+ .fasync = vdpram_fasync,
+ .unlocked_ioctl = vdpram_ioctl,
+};
+
+struct file_operations vdpram_odd_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = vdpram_read,
+ .write = vdpram_write,
+ .poll = vdpram_poll,
+ .open = vdpram_open,
+ .release = vdpram_release,
+ .fasync = vdpram_fasync,
+ .unlocked_ioctl = vdpram_ioctl,
+};
+
+long vdpram_ioctl(struct file* filp, unsigned int cmd, unsigned long arg)
+{
+ struct vdpram_dev *dev;
+ struct vdpram_status_dev dev_status;
+ int index;
+ dev = (struct vdpram_dev*)filp->private_data;
+ index = dev->index ;
+
+ memset( &dev_status, 0, sizeof(struct vdpram_status_dev));
+
+ switch( cmd )
+ {
+ case VDPRAM_SEM_UNLOCK :
+#ifdef VDPRAM_LOCK_ENABLE
+ up (&buffer[index].sem);
+#endif //VDPRAM_LOCK_ENABLE
+ break;
+ case VDPRAM_STATUS :
+ dev_status.index = dev->index;
+ dev_status.adj_index = dev->adj_index;
+
+ dev_status.rp = dev->rp;
+ dev_status.wp = dev->wp;
+ dev_status.adj_rp = dev->rp;
+ dev_status.adj_wp = dev->wp;
+
+ if ( dev_status.rp != 0 )
+ dev_status.rp_cnt = dev->rp-buffer[index].begin;
+
+ if ( dev_status.wp != 0 )
+ dev_status.wp_cnt = dev->wp-buffer[index].begin;
+
+ dev_status.adj_rp = dev->adj->rp;
+ dev_status.adj_wp = dev->adj->wp;
+
+ if ( dev_status.adj_rp != 0 )
+ dev_status.adj_rp_cnt = dev->adj->rp-buffer[dev->adj_index].begin;
+ if ( dev_status.adj_wp != 0 )
+ dev_status.adj_wp_cnt = dev->adj->wp-buffer[dev->adj_index].begin;
+
+
+ if (copy_to_user((char*)arg, &dev_status, sizeof(struct vdpram_status_dev))) {
+ return -EFAULT;
+ }
+ default :
+// printk("%s[%d]:p=%d:cmd=%d\n", __FUNCTION__,index,current->pid,cmd);
+ break;
+
+ }
+ return 0;
+}
+
+/*
+ * Set up a cdev entry.
+ */
+static void vdpram_setup_cdev(struct vdpram_dev *dev, int index)
+{
+ dev_t node = MKDEV(vdpram_major, index);
+ int err;
+ int is_odd = index & 1; // "index % 2" equivalent
+
+ dev->flag = !is_odd;
+ cdev_init(&dev->cdev, is_odd ? &vdpram_odd_fops : &vdpram_even_fops);
+ dev->cdev.owner = THIS_MODULE;
+ err = cdev_add (&dev->cdev, node, 1);
+ dev->index = index;
+
+ /* Fail gracefully if need be */
+ if (err)
+ printk(KERN_NOTICE "Error %d adding device%d\n", err, index);
+}
+
+static char *vdpram_devnode(struct device *dev, umode_t *mode)
+{
+ return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
+}
+
+/* Initialize the devs; return how many we did */
+int vdpram_init(void)
+{
+ int i, result;
+ dev_t dev = 0;
+
+ printk("Initializing vdpram device driver ...\n");
+ result = alloc_chrdev_region(&dev, 0, vdpram_nr_devs, "vdpram");
+ if (result < 0) {
+ printk("Unable to get vdpram region, error %d\n", result);
+ goto err_out;
+ }
+
+ vdpram_major = MAJOR(dev);
+ printk("vdpram device major num = %d \n", vdpram_major);
+ vdpram_devno = dev;
+
+ vdpram_devices = kmalloc(vdpram_nr_devs * sizeof(struct vdpram_dev), GFP_KERNEL);
+ buffer = kmalloc(vdpram_nr_devs * sizeof(struct buffer_t), GFP_KERNEL);
+ queue = kmalloc(vdpram_nr_devs * sizeof(struct queue_t), GFP_KERNEL);
+ if (!vdpram_devices || !buffer || !queue) {
+ result = -ENOMEM;
+ goto err_alloc;
+ }
+
+ vdpram_class = class_create(THIS_MODULE, "vdpram");
+ if (IS_ERR(vdpram_class)) {
+ result = PTR_ERR(vdpram_class);
+ goto err_alloc;
+ }
+ vdpram_class->devnode = vdpram_devnode;
+
+ memset(vdpram_devices, 0, vdpram_nr_devs * sizeof(struct vdpram_dev));
+ for (i = 0; i < vdpram_nr_devs; i++) {
+ if (i% 2 ==1) {
+ vdpram_devices[i].adj = &vdpram_devices[i-1];
+ vdpram_devices[i-1].adj = &vdpram_devices[i];
+// hwjang
+ vdpram_devices[i].adj->adj_index=i;
+ vdpram_devices[i-1].adj->adj_index=i-1;
+ }
+ vdpram_setup_cdev(vdpram_devices + i, i);
+ }
+
+ memset(buffer, 0, vdpram_nr_devs * sizeof(struct buffer_t));
+ // hwjang fix buffer -> queue
+ memset(queue, 0, vdpram_nr_devs * sizeof(struct queue_t));
+ for (i = 0; i < vdpram_nr_devs; i++) {
+#ifdef VDPRAM_LOCK_ENABLE
+// init_MUTEX(&buffer[i].sem);
+ sema_init(&buffer[i].sem, 1);
+#endif //VDPRAM_LOCK_ENABLE
+ buffer[i].begin = kmalloc(vdpram_buffer, GFP_KERNEL);
+ buffer[i].buffersize = vdpram_buffer;
+ buffer[i].end = buffer[i].begin + buffer[i].buffersize;
+
+ init_waitqueue_head(&queue[i].inq);
+ init_waitqueue_head(&queue[i].outq);
+//printk("%s buffer[%x].begin =%x\n", __FUNCTION__, i, buffer[i].begin );
+//printk("%s buffer[%x].buffersize =%x\n", __FUNCTION__, i, buffer[i].buffersize );
+//printk("%s buffer[%x].end =%x\n", __FUNCTION__, i, buffer[i].end );
+ }
+
+ for (i = 0; i < vdpram_nr_devs; i++)
+ device_create(vdpram_class, NULL, MKDEV(vdpram_major, i), NULL,
+ kasprintf(GFP_KERNEL, "vdpram%d", i));
+
+ return 0;
+
+err_alloc:
+ kfree(vdpram_devices);
+ kfree(buffer);
+ kfree(queue);
+
+ unregister_chrdev_region(dev, vdpram_nr_devs);
+
+err_out:
+ return result;
+}
+
+/*
+ * This is called by cleanup_module or on failure.
+ * It is required to never fail, even if nothing was initialized first
+ */
+void vdpram_cleanup(void)
+{
+ int i;
+
+// printk("%s:%d\n", __FUNCTION__,current->pid);
+
+ if (!vdpram_devices)
+ return; /* nothing else to release */
+
+ for (i = 0; i < vdpram_nr_devs; i++) {
+ device_destroy(vdpram_class, MKDEV(vdpram_major, i));
+ cdev_del(&vdpram_devices[i].cdev);
+ }
+ class_destroy(vdpram_class);
+ kfree(vdpram_devices);
+
+ for (i= 0;i < vdpram_nr_devs ; i++) {
+ kfree(buffer[i].begin);
+ }
+ kfree(buffer);
+
+ unregister_chrdev_region(vdpram_devno, vdpram_nr_devs);
+ vdpram_devices = NULL; /* pedantic */
+}
+
+module_init(vdpram_init);
+module_exit(vdpram_cleanup);