實驗平臺:s5pv210開發板 + kernel2.6
功能:驅動三顆led,led1 led2,共用一個fops,led3單獨使用一個fops。當open led1/led2 時,led1 和 led2 同時亮,open led3 時, led3亮;release 對應熄滅。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <mach/gpio-bank.h>
#include <mach/regs-gpio.h>
#include <linux/cdev.h>
#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DAT
#define rGPJ0CON *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT)
#define LED1_OFF (1 << 3)
#define LED2_OFF (1 << 4)
#define LED3_OFF (1 << 5)
unsigned int major_led1,major_led2;
struct cdev led1;
struct cdev led2;
static int led_01_open(struct inode *inode, struct file *file)
{
rGPJ0DAT &= ~(LED1_OFF | LED2_OFF);
return 0;
}
static int led_01_release(struct inode *inode, struct file *file)
{
rGPJ0DAT |= (LED1_OFF | LED2_OFF);
return 0;
}
struct file_operations led_01_fops = {
.open = led_01_open,
.release = led_01_release,
};
static int lll_open(struct inode *inode, struct file *file)
{
rGPJ0DAT &= ~LED3_OFF;
return 0;
}
static int lll_release(struct inode *inode, struct file *file)
{
rGPJ0DAT |= LED3_OFF;
return 0;
}
struct file_operations lll_fops = {
.open = lll_open,
.release = lll_release,
};
int led_gpio_init(void)
{
rGPJ0CON &= ~((0xff << 12) | (0xff << 16) | (0xff << 20)); //clear
rGPJ0CON |= ((1 << 12) | (1 << 16) | (1 << 20)); // set as output
rGPJ0DAT |= (LED1_OFF | LED2_OFF | LED3_OFF); //set all leds off
return 0;
}
int led_register(struct cdev *led, unsigned int *major, unsigned count,const char *name,struct file_operations *led_fops)
{
int err;
err = alloc_chrdev_region(major, 0, count, name);
if (err)
goto err1;
cdev_init(led, led_fops);
err = cdev_add(led, *major, count);
if (err)
goto err2;
return 0;
err2:
cdev_del(&led1);
unregister_chrdev_region(major_led1, 2);
err1:
return err;
}
int __init hello_init(void)
{
int ret;
led_gpio_init();
ret = led_register(&led1, &major_led1, 2,"led_01",&led_01_fops);
if (ret)
return ret;
ret = led_register(&led2, &major_led2, 1,"led_03",&lll_fops) ;
return ret;
}
void __exit hello_exit(void)
{
printk("hello exit\n");
cdev_del(&led1);
cdev_del(&led2);
unregister_chrdev_region(major_led2, 1);
unregister_chrdev_region(major_led1, 2);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
測試函數
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{
int fd;
if (2 != argc)
{
printf("usag:%s <device name>\n", argv[0]);
printf("Eg: %s /dev/led1\n", argv[0]);
return -1;
}
fd = open(argv[1], O_RDWR);
if(0 > fd) {
printf("open device %s fail\n", argv[1]);
perror("open");
return -1;
}
sleep(5);
close(fd);
return 0;
}
接下來將實現設備節點自動創建、在/sys目錄下創建文件夾並添加文件。