Makefile
TARGET := leds_dev
obj-m += $(TARGET).o
ROOTFS = /home/flinn/smart210-SDK/fs/drv
KERNEL = /home/flinn/smart210-SDK/linux-3.10.79
all:
make -C $(KERNEL) M=`pwd` modules
clean:
make -C $(KERNEL) M=`pwd` clean
install:
sudo cp $(TARGET).ko $(ROOTFS)
make.sh
#!/bin/bash
echo -e "\e[1;31m##make clean \e[0m"
make clean
echo -e "\e[1;31m##make \e[0m"
make
echo -e "\e[1;31m##make install \e[0m"
make install
leds_dev.c
/*
* linux-3.10.27
* arm-linux-gcc-4.5.1
*
* @ leds driver
*/
#include <linux/module.h>
#include <linux/init.h> /* module_init, ... */
#include <linux/kernel.h> /* everything */
#include <linux/cdev.h> /* cdev_init, ... */
#include <linux/fs.h> /* file_operations, */
#include <linux/device.h> /* class_create,... */
#include <linux/platform_device.h>
#include <linux/slab.h> /* kmalloc, ... */
#include <asm/io.h> /* ioremap,... */
#include <linux/uaccess.h> /* copy_from_user, ... */
static void leds_dev_release(struct device *dev)
{
pr_info("%s called .\n", __func__);
}
static struct resource leds_dev_res[] =
{
{
.start = 0xE0200280,
.end = 0xE0200280 + 0x10,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device leds_dev =
{
.name = "myleds",
.dev = {
.release = leds_dev_release,
},
.num_resources = ARRAY_SIZE(leds_dev_res),
.resource = &leds_dev_res[0],
};
static int leds_dev_init(void)
{
int ret = 0;
pr_info("%s called.\n", __func__);
ret = platform_device_register(&leds_dev);
if(ret < 0){
pr_err("register leds dev err.\n");
return ret;
}
return 0;
}
static void leds_dev_exit(void)
{
pr_info("%s called.\n", __func__);
platform_device_unregister(&leds_dev);
}
module_init(leds_dev_init);
module_exit(leds_dev_exit);
MODULE_LICENSE("GPL");
leds_drv.c
/*
* linux-3.10.27
* arm-linux-gcc-4.5.1
*
* @ leds driver
*/
#include <linux/module.h>
#include <linux/init.h> /* module_init, ... */
#include <linux/kernel.h> /* everything */
#include <linux/cdev.h> /* cdev_init, ... */
#include <linux/fs.h> /* file_operations, */
#include <linux/device.h> /* class_create,... */
#include <linux/platform_device.h>
#include <linux/slab.h> /* kmalloc, ... */
#include <asm/io.h> /* ioremap,... */
#include <linux/uaccess.h> /* copy_from_user, ... */
struct _gpio {
unsigned long __iomem con;
unsigned long __iomem dat;
unsigned long __iomem pud;
unsigned long __iomem drv;
unsigned long __iomem conpdn;
unsigned long __iomem pudpdn;
};
#define DEF_DEVICE_NAME "myleds"
struct priv_data
{
char *name;
int major;
dev_t dev;
struct cdev *cdev;
struct class *class;
};
static struct priv_data *priv_data;
static struct _gpio *gpio_regs;
static int leds_open (struct inode *inode, struct file *file)
{
pr_info("%s called.\n", __func__);
return 0;
}
static int leds_close (struct inode *inode, struct file *file)
{
pr_info("%s called.\n", __func__);
return 0;
}
static ssize_t leds_write (struct file *pfile, const char __user *usrbuf,
size_t len, loff_t *offset )
{
int revbuf[8];
int cmd, opt;
printk(KERN_INFO "write \n");
if(copy_from_user(revbuf,usrbuf,8))
{
return -EFAULT;
}
cmd = revbuf[0];
opt = revbuf[1];
printk(KERN_NOTICE "cmd : %d opt : %d \n", cmd, opt);
if(cmd == 0) // close
{
gpio_regs->dat |= (1 << opt);
}
else if(1 == cmd) // open
{
gpio_regs->dat &= ~(1 << opt);
}
else
{
// do nothing .
}
return 0;
}
const struct file_operations fops =
{
.owner = THIS_MODULE,
.open = leds_open,
.release = leds_close,
.write = leds_write,
};
static int leds_drv_probe(struct platform_device *pdev)
{
struct resource *res = NULL;
int ret = 0;
struct device *dev = &pdev->dev;
pr_info("%s called.\n", __func__);
if(!dev)
{
pr_err("no resource available.\n");
return -EFAULT;
}
//priv_data = kmalloc(sizeof(struct priv_data), GFP_KERNEL);
priv_data = devm_kzalloc(dev, sizeof(*priv_data), GFP_KERNEL);
if(!priv_data){
pr_err("no mem.\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpio_regs = devm_ioremap_resource(dev, res);
if (IS_ERR(gpio_regs))
return PTR_ERR(gpio_regs);
priv_data->name = DEF_DEVICE_NAME;
priv_data->major = 0;
if(priv_data->major){
priv_data->dev = MKDEV(priv_data->major, 0);
register_chrdev_region(priv_data->dev, 1, priv_data->name);
}
else {
ret = alloc_chrdev_region(&priv_data->dev, 1, 1, priv_data->name);
priv_data->major = MAJOR(priv_data->dev);
}
if(ret < 0){
pr_err("register chrdev fail.\n");
return -EFAULT;
}
priv_data->cdev = cdev_alloc();
if(!priv_data->cdev){
pr_err("alloc cdev err.\n");
unregister_chrdev_region(priv_data->dev, 1);
}
cdev_init(priv_data->cdev, &fops);
priv_data->cdev->ops = &fops;
priv_data->cdev->owner = THIS_MODULE;
cdev_add(priv_data->cdev, priv_data->dev, 1);
/* add device */
priv_data->class = class_create(THIS_MODULE, priv_data->name);
if(!priv_data->class){
pr_err("class create err.\n");
goto cls_err;
}
/* create the device below /dev/ */
device_create(priv_data->class, NULL, priv_data->dev, NULL, priv_data->name);
/* set as output */
gpio_regs->con |= (1 << 4 * 0) + (1 << 4 * 1) + \
(1 << 4 * 2) + (1 << 4 * 3);
gpio_regs->dat = 0x0f;
return 0;
cls_err:
cdev_del(priv_data->cdev);
unregister_chrdev_region(priv_data->dev, 1);
return -EFAULT;
}
static int leds_drv_remove(struct platform_device *pdev)
{
pr_info("%s called.\n", __func__);
device_destroy(priv_data->class, priv_data->dev);
class_destroy(priv_data->class);
cdev_del(priv_data->cdev);
unregister_chrdev_region(priv_data->dev, 1);
return 0;
}
const struct of_device_id leds_ids = {
.compatible = "smart210,leds",
};
static struct platform_driver leds_drv =
{
.probe = leds_drv_probe,
.remove = leds_drv_remove,
.driver = {
.name = "myleds",
.of_match_table = &leds_ids,
},
};
static int leds_drv_init(void)
{
int ret = 0;
pr_info("%s called.\n", __func__);
ret = platform_driver_register(&leds_drv);
if(ret < 0){
pr_err("register leds drv err.\n");
return ret ;
}
return 0;
}
static void leds_drv_exit(void)
{
pr_info("%s called.\n", __func__);
platform_driver_unregister(&leds_drv);
}
module_init(leds_drv_init);
module_exit(leds_drv_exit);
MODULE_LICENSE("GPL");