#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/pci.h>
#include<linux/ioctl.h>
#include<linux/types.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/gpio.h>
#include<mach/hardware.h>
#include<mach/regs-gpio.h>
#include<mach/gpio-bank-m.h>
#include<plat/gpio-cfg.h>
#include <mach/map.h>
#define DEVICE_NAME "s3c6410leds"
#define LED_ON 1
#define LED_OFF 0
dev_t devid;
static int leds_open(struct inode *inode , struct file *file)
{
unsigned tmp;
for(tmp=0;tmp<4;tmp++)
s3c_gpio_cfgpin(S3C64XX_GPM(tmp),S3C_GPIO_SFN(1));
return 0;
}
static long leds_ioctl( struct file *filp,unsigned int cmd,
unsigned long arg)
{
if(arg>4) return -EINVAL;
//tmp = __raw_readl(S3C64XX_GPMDAT);
switch(cmd)
{
case LED_ON: //tmp &= ~(1<<arg); writel(tmp,S3C64XX_GPMDAT);
gpio_set_value(S3C64XX_GPM(arg),0);
return 0;
case LED_OFF: //tmp |= 1<<arg; writel(tmp,S3C64XX_GPMDAT);
gpio_set_value(S3C64XX_GPM(arg),1);
return 0;
default: return -EINVAL;
}
}
static struct file_operations leds_ops = {
.owner = THIS_MODULE,
.open = leds_open,
.unlocked_ioctl = leds_ioctl,
};
static struct cdev *cdev_led;
static struct class *led_class;
static int __init s3c6410_leds_init(void)
{
int val;
unsigned tmp;
tmp = readl(S3C64XX_GPMPUD); //pull up gpiom0~3
tmp &= ~(0xffff);
tmp |= 0xaa;
writel(tmp,S3C64XX_GPMPUD);
// devid = MKDEV(LED_MAJOR,0);
// val = register_chrdev_region(devid,1,DEVICE_NAME);
val = alloc_chrdev_region(&devid,0,1,DEVICE_NAME);
if(val) return -1;
cdev_led = cdev_alloc();
cdev_init(cdev_led,&leds_ops);
val = cdev_add(cdev_led,devid,1);
if(val)
{
// printk(KERN_INFO "Add device led error!\n");
return -1;
}
led_class = class_create(THIS_MODULE,DEVICE_NAME);
device_create(led_class,NULL,devid,NULL,"%s",DEVICE_NAME);
// printk(KERN_INFO "LED Initilized I'm in! ^_^ \n");
return 0;
}
static void __exit s3c6410_leds_exit(void)
{
cdev_del(cdev_led);
device_destroy(led_class,devid);
class_destroy(led_class);
unregister_chrdev_region(devid, 1);
}
module_init(s3c6410_leds_init);
module_exit(s3c6410_leds_exit);
MODULE_AUTHOR("embedded lover");
MODULE_DESCRIPTION("s3c6410 led test");
MODULE_LICENSE("GPL");
在linux2.6版本之后我们是可以让驱动程序自动建立设备节点文件的,注意下这点。
下面是自己的测试程序:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>
#define LED_ON 1
#define LED_OFF 0
int main(int argc, char **argv)
{
int fd = -1;
unsigned int led_no;
fd = open("/dev/s3c6410leds",0);
if(fd<0)
{
printf("Can not open device leds\n");
return -1;
}
led_no = strtoul(argv[1],0,0) - 1;
if(!strcmp(argv[2],"on"))
{
ioctl(fd,LED_ON,led_no);
}
else if(!strcmp(argv[2],"off"))
{
ioctl(fd,LED_OFF,led_no);
}
else goto err;
close(fd);
return 0;
err:
if(fd>0) close(fd);
return -1;
}
在写完驱动程序后有两个方法可以编译成可加载的.ko模块文件,一个是将驱动放到内核原码的driver/char目录下,再在Makefile下新增一个obj-m += name.o。再在顶层文件夹下执行make modules ,然后就可以在driver/char下找到对应的.ko文件。另外一个方法就是自己写makefile了,这样也方便。
Makefile如下:
---------------------------------------------
all: default
obj-m += create_chrdev.o
default:
make -C /home/xu/Myworks/kernel/linux-2.6.22 M=`pwd` modules
clean:
make -C /home/xu/Myworks/kernel/linux-2.6.22 M=`pwd` clean
最后将模块文件加载到目标板上:insmod,移除模块用:rmmod。 |