From f54ba59d355f59e4c01b5b9c7dbc2d27b47302d2 Mon Sep 17 00:00:00 2001 From: Alison Wang Date: Thu, 4 Aug 2011 09:59:41 +0800 Subject: [PATCH 10/52] Add SRAM char device driver support for MCF5445x Created "/dev/sram" device file and implemented the sram mmap() operation to provide interface for userspace access. Signed-off-by: Alison Wang --- drivers/char/Kconfig | 11 ++++ drivers/char/Makefile | 2 + drivers/char/sram.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 0 deletions(-) create mode 100644 drivers/char/sram.c --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -97,6 +97,17 @@ config DEVKMEM kind of kernel debugging operations. When in doubt, say "N". +config DEVSRAM + tristate "/dev/sram virtual device support" + depends on M5445X + default m + help + Say Y here if you want to suppot the SRAM char device. When in + doubt, say "N". + + It implements mmap system call to provide interface for + user space access. + config BFIN_JTAG_COMM tristate "Blackfin JTAG Communication" depends on BLACKFIN --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -87,3 +87,5 @@ obj-$(CONFIG_RAMOOPS) += ramoops.o obj-$(CONFIG_JS_RTC) += js-rtc.o js-rtc-y = rtc.o + +obj-$(CONFIG_DEVSRAM) += sram.o --- /dev/null +++ b/drivers/char/sram.c @@ -0,0 +1,151 @@ +/* + * linux/drivers/char/sram.c + * + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Author: Lanttor.Guo@freescale.com + * + * SRAM char device driver, implements mmap() system call to provide + * interface for user space access. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static struct class *sram_class; +static int sram_major; +static int sram_minor; +static struct cdev sram_cdev; + +/* + * Set up the cdev structure for sram. + */ +static void sram_setup_cdev(struct cdev *dev, int minor, + const struct file_operations *fops) +{ + int err, devno = MKDEV(sram_major, minor); + + cdev_init(dev, fops); + dev->owner = THIS_MODULE; + dev->ops = fops; + err = cdev_add(dev, devno, 1); + /* Fail gracefully if need be */ + if (err) + printk(KERN_NOTICE "Error %d adding sram%d", err, minor); +} + +static int sram_open(struct inode *inode, struct file *filp) +{ + filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; + return 0; +} + +static int sram_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +void sram_vma_open(struct vm_area_struct *vma) +{ + printk(KERN_DEBUG "Sram VMA open, virt %lx, phys %lx\n", + vma->vm_start, + CONFIG_SRAM_BASE + (vma->vm_pgoff << PAGE_SHIFT)); +} + +void sram_vma_close(struct vm_area_struct *vma) +{ + printk(KERN_DEBUG "Sram VMA close.\n"); +} + + +static struct vm_operations_struct sram_remap_vm_ops = { + .open = sram_vma_open, + .close = sram_vma_close, +}; + +static int sram_remap_mmap(struct file *filp, struct vm_area_struct *vma) +{ + size_t size = vma->vm_end - vma->vm_start; + + if (PAGE_ALIGN(size) > CONFIG_SRAM_SIZE) { + printk(KERN_ERR "required length exceed the size " + "of physical sram (%x)\n", CONFIG_SRAM_SIZE); + return -EAGAIN; + } + + if ((CONFIG_SRAM_BASE + (vma->vm_pgoff << PAGE_SHIFT) + size) + > (CONFIG_SRAM_BASE + CONFIG_SRAM_SIZE)) { + printk(KERN_ERR "required sram range exceed the size " + "of phisical sram\n"); + return -EAGAIN; + } + + if (remap_pfn_range(vma, vma->vm_start, + (CONFIG_SRAM_BASE >> PAGE_SHIFT) + vma->vm_pgoff, + size, + vma->vm_page_prot)) { + printk(KERN_ERR "remap_pfn_range faile at %s()\n", __func__); + return -EAGAIN; + } + + vma->vm_ops = &sram_remap_vm_ops; + return 0; +} + +static const struct file_operations sram_ops = { + .owner = THIS_MODULE, + .open = sram_open, + .release = sram_release, + .mmap = sram_remap_mmap, +}; + +static int __init sram_chrdev_init(void) +{ + int minor_devs = 1; + int result; + dev_t dev = 0; + sram_minor = 0; + + result = alloc_chrdev_region(&dev, sram_minor, minor_devs, "sram"); + sram_major = MAJOR(dev); + if (result < 0) { + printk(KERN_WARNING "sram: can't get major %d\n", sram_major); + return result; + } + + sram_setup_cdev(&sram_cdev, 0, &sram_ops); + + sram_class = class_create(THIS_MODULE, "sram"); + device_create(sram_class, NULL, MKDEV(sram_major, sram_minor), + NULL, "sram"); + + return 0; +} + +static void sram_chrdev_cleanup(void) +{ + cdev_del(&sram_cdev); + device_destroy(sram_class, MKDEV(sram_major, sram_minor)); + class_destroy(sram_class); + unregister_chrdev_region(MKDEV(sram_major, 0), 1); +} + +module_init(sram_chrdev_init); +module_exit(sram_chrdev_cleanup);