驱动文件
gpio_led.c
# include "gpio_led.h"
struct gpioled_dev gpioled;
static int gpioled_open ( struct inode * inode, struct file * filp)
{
filp-> private_data = & gpioled;
return 0 ;
}
static int gpioled_release ( struct inode * inode, struct file * filp)
{
struct gpioled_dev * dev = ( struct gpioled_dev * ) filp-> private_data;
return 0 ;
}
static ssize_t gpioled_write ( struct file * filp, const char __user * buf, size_t count, loff_t * ppos)
{
struct gpioled_dev * dev = ( struct gpioled_dev * ) filp-> private_data;
int retval = 0 ;
unsigned char buffer[ 1 ] = { 0 } ;
retval = copy_from_user ( buffer, buf, count) ;
if ( retval < 0 ) {
printk ( "kernel write failed\r\n" ) ;
return - EFAULT;
}
printk ( "read sta = %d\r\n" , buffer[ 0 ] ) ;
if ( buffer[ 0 ] == LEDON) {
gpio_set_value ( dev-> led_gpio, 0 ) ;
} else if ( buffer[ 0 ] == LEDOFF) {
gpio_set_value ( dev-> led_gpio, 1 ) ;
}
return 0 ;
}
static struct file_operations gpioled_fops = {
. owner = THIS_MODULE,
. open = gpioled_open,
. release = gpioled_release,
. write = gpioled_write,
} ;
static int __init dts_led_start ( void )
{
int ret = 0 ;
if ( gpioled. major) {
gpioled. devid = MKDEV ( gpioled. major, 0 ) ;
ret = register_chrdev_region ( gpioled. major, DTSLED_CNT, DTSLED_NAME) ;
}
else {
ret = alloc_chrdev_region ( & ( gpioled. devid) , 0 , DTSLED_CNT, DTSLED_NAME) ;
gpioled. major = MAJOR ( gpioled. devid) ;
gpioled. minor = MINOR ( gpioled. devid) ;
}
if ( ret < 0 ) {
goto FAILED_DEVID;
}
printk ( "gpioled major=%d,minor=%d\r\n" , gpioled. major, gpioled. minor) ;
cdev_init ( & ( gpioled. ledCdev) , & gpioled_fops) ;
ret = cdev_add ( & ( gpioled. ledCdev) , gpioled. devid, DTSLED_CNT) ;
if ( ret < 0 ) {
printk ( "添加字符设备错误\r\n" ) ;
goto FAILED_CDEV;
}
gpioled. ledClass = class_create ( THIS_MODULE, DTSLED_NAME) ;
if ( IS_ERR ( gpioled. ledClass) ) {
ret = PTR_ERR ( gpioled. ledClass) ;
goto FAILED_CLASS;
}
gpioled. ledDevice = device_create ( gpioled. ledClass, NULL , gpioled. devid, NULL , DTSLED_NAME) ;
if ( IS_ERR ( gpioled. ledDevice) ) {
ret = PTR_ERR ( gpioled. ledDevice) ;
goto FAILED_DEVICE;
}
gpioled. nd = of_find_node_by_path ( "/gpioled" ) ;
if ( gpioled. nd == NULL ) {
ret = - EINVAL;
printk ( "gpioled node cant not found!\r\n" ) ;
goto FAILED_GETDTSNODE;
}
else {
printk ( "gpioled node has been found!\r\n" ) ;
}
gpioled. led_gpio = of_get_named_gpio ( gpioled. nd, "led-gpio" , 0 ) ;
if ( gpioled. led_gpio < 0 ) {
printk ( "can't get led-gpio" ) ;
ret = - EINVAL;
goto FAILED_GETDTSNODE;
}
printk ( "led-gpio num = %d\r\n" , gpioled. led_gpio) ;
gpio_request ( gpioled. led_gpio, "led" ) ;
ret = gpio_direction_output ( gpioled. led_gpio, 1 ) ;
if ( ret < 0 ) {
printk ( "can't set gpio!\r\n" ) ;
}
return 0 ;
FAILED_GETDTSNODE:
device_destroy ( gpioled. ledClass, gpioled. devid) ;
FAILED_DEVICE:
class_destroy ( gpioled. ledClass) ;
FAILED_CLASS:
cdev_del ( & ( gpioled. ledCdev) ) ;
FAILED_CDEV:
unregister_chrdev_region ( gpioled. devid, DTSLED_CNT) ;
FAILED_DEVID:
return ret;
}
static void __exit dts_led_exit ( void )
{
gpio_set_value ( gpioled. led_gpio, 1 ) ;
device_destroy ( gpioled. ledClass, gpioled. devid) ;
class_destroy ( gpioled. ledClass) ;
cdev_del ( & ( gpioled. ledCdev) ) ;
unregister_chrdev_region ( gpioled. devid, DTSLED_CNT) ;
}
module_init ( dts_led_start) ;
module_exit ( dts_led_exit) ;
MODULE_LICENSE ( "GPL" ) ;
头文件
gpio_led.h
# ifndef __GPIO_LED_H
# define __GPIO_LED_H
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/ide.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/cdev.h>
# include <linux/device.h>
# include <asm/mach/map.h>
# include <asm/uaccess.h>
# include <linux/gpio.h>
# include <asm/io.h>
# include <linux/fs.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_gpio.h>
# define DTSLED_CNT 1
# define DTSLED_NAME "gpioled"
# define LEDOFF 0
# define LEDON 1
struct gpioled_dev {
dev_t devid;
struct cdev ledCdev;
struct class * ledClass;
struct device * ledDevice;
int major;
int minor;
struct device_node * nd;
unsigned int led_gpio;
} ;
extern struct gpioled_dev gpioled;
# endif
测试文件
gpioled_test.c
# include <stdio.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
int main ( int argc, char * argv[ ] )
{
int fd;
unsigned char sta = 0 ;
int i;
fd = open ( "/dev/gpioled" , O_RDWR) ;
if ( fd == - 1 ) {
printf ( "/dev/dtsled open failed\r\n" ) ;
return - 1 ;
}
for ( i = 0 ; i < 10 ; i++ ) {
sta = i % 2 ;
printf ( "sta = %d\r\n" , sta) ;
write ( fd, & sta, sizeof ( sta) ) ;
sleep ( 1 ) ;
}
close ( fd) ;
return 0 ;
}