led.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/miscdevice.h>
#define DEVICE_NAME "tiny4412-leds"
#define GPM4CON (0x11000000+0x02E0)
#define GPM4DAT (0x11000000+0x02E4)
#define GPM4_0 0
#define GPM4_1 1
#define GPM4_2 2
#define GPM4_3 3
#define GPM4_ON 0
#define GPM4_OFF 1
//幻数
#define LEDS_MAGIC 'a'
#define LEDS_PGM4_0_ON _IO(LEDS_MAGIC, 1)
#define LEDS_PGM4_0_OFF _IO(LEDS_MAGIC, 2)
#define LEDS_PGM4_1_ON _IO(LEDS_MAGIC, 3)
#define LEDS_PGM4_1_OFF _IO(LEDS_MAGIC, 4)
#define LEDS_PGM4_2_ON _IO(LEDS_MAGIC, 5)
#define LEDS_PGM4_2_OFF _IO(LEDS_MAGIC, 6)
#define LEDS_PGM4_3_ON _IO(LEDS_MAGIC, 7)
#define LEDS_PGM4_3_OFF _IO(LEDS_MAGIC, 8)
unsigned int *gpm4_con = NULL;
unsigned int *gpm4_dat = NULL;
/* 设置IO口输出电平 */
static void set_gmp4_out(unsigned char cpm4_n, unsigned char status)
{
unsigned int temp;
temp = readl(gpm4_dat);
if (status == GPM4_ON)
temp &= ~(0x1<<cpm4_n);
else
temp |= 0x1<<cpm4_n;
writel(temp, gpm4_dat);
}
static long tiny4412_leds_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case LEDS_PGM4_0_ON: set_gmp4_out(GPM4_0, GPM4_ON);
break;
case LEDS_PGM4_0_OFF: set_gmp4_out(GPM4_0, GPM4_OFF);
break;
case LEDS_PGM4_1_ON: set_gmp4_out(GPM4_1, GPM4_ON);
break;
case LEDS_PGM4_1_OFF: set_gmp4_out(GPM4_1, GPM4_OFF);
break;
case LEDS_PGM4_2_ON: set_gmp4_out(GPM4_2, GPM4_ON);
break;
case LEDS_PGM4_2_OFF: set_gmp4_out(GPM4_2, GPM4_OFF);
break;
case LEDS_PGM4_3_ON: set_gmp4_out(GPM4_3, GPM4_ON);
break;
case LEDS_PGM4_3_OFF: set_gmp4_out(GPM4_3, GPM4_OFF);
break;
defautl :
break;
}
return 0;
}
static const struct file_operations tiny4412_leds_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = tiny4412_leds_ioctl,
};
static struct miscdevice tiny4412_leds_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &tiny4412_leds_fops,
};
static int tiny4412_leds_init(void)
{
unsigned int data;
unsigned int ret;
//IO初始化,将物理地址映射为虚拟地址
gpm4_con = ioremap(GPM4CON, 4);
gpm4_dat = ioremap(GPM4DAT, 4);
if (!gpm4_con || !gpm4_con) {
printk("ioremap faild!\n");
goto error1;
}
/* 将GPM4[0]-GPM4[3]设置为输出 */
data = readl(gpm4_con);
data &= ~((0xf<<12)|(0xf<<8)|(0xf<<4)|(0xf<<0));
data |= (0x1<<12)|(0x1<<8)|(0x1<<4)|(0x1<<0);
writel(data, gpm4_con);
ret = misc_register(&tiny4412_leds_miscdev); //注册混杂设备驱动
if (ret) {
printk("misc_register faild!\n");
goto error2;
}
printk("tiny4412_leds_init!\n");
return 0;
error2:
iounmap(gpm4_con);
iounmap(gpm4_dat);
error1:
return -ENOMEM;
}
static void tiny4412_leds_exit(void)
{
unsigned int data;
misc_deregister(&tiny4412_leds_miscdev);
data = readl(gpm4_dat);
data |= (0x1<<3)|(0x1<<2)|(0x1<<1)|(0x1<<0);
writel(data, gpm4_dat);
iounmap(gpm4_con);
iounmap(gpm4_dat);
printk("tiny4412_leds_exit!\n");
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ChunquanL");
module_init(tiny4412_leds_init);
module_exit(tiny4412_leds_exit);
led_test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#define DEVICE_NAME "/dev/tiny4412-leds"
//幻数
#define LEDS_MAGIC 'a'
#define LEDS_PGM4_0_ON _IO(LEDS_MAGIC, 1)
#define LEDS_PGM4_0_OFF _IO(LEDS_MAGIC, 2)
#define LEDS_PGM4_1_ON _IO(LEDS_MAGIC, 3)
#define LEDS_PGM4_1_OFF _IO(LEDS_MAGIC, 4)
#define LEDS_PGM4_2_ON _IO(LEDS_MAGIC, 5)
#define LEDS_PGM4_2_OFF _IO(LEDS_MAGIC, 6)
#define LEDS_PGM4_3_ON _IO(LEDS_MAGIC, 7)
#define LEDS_PGM4_3_OFF _IO(LEDS_MAGIC, 8)
int main (int argc, char *argv[])
{
int leds_fd = 0;
int cmd;
if (argc < 2) {
printf("please entry the correct operation parameter! \n");
return 0;
}
leds_fd = open(DEVICE_NAME, O_RDWR);
if (leds_fd == -1) {
printf("open device faild! \n");
return 0;
}
cmd = atoi(argv[1]); //把终端上收到的字符串命令转换成整型
//printf("argv:%s \n", argv[1]);
/* 执行 ./led_oper 11 点亮LED1 , 执行./led_oper 10 关闭LED1,其他LED灯以此类推 */
switch (cmd) {
case 10: ioctl(leds_fd, LEDS_PGM4_0_OFF);
break;
case 11: ioctl(leds_fd, LEDS_PGM4_0_ON);
break;
case 20: ioctl(leds_fd, LEDS_PGM4_1_OFF);
break;
case 21: ioctl(leds_fd, LEDS_PGM4_1_ON);
break;
case 30: ioctl(leds_fd, LEDS_PGM4_2_OFF);
break;
case 31: ioctl(leds_fd, LEDS_PGM4_2_ON);
break;
case 40: ioctl(leds_fd, LEDS_PGM4_3_OFF);
break;
case 41: ioctl(leds_fd, LEDS_PGM4_3_ON);
break;
defautl :
break;
}
close(leds_fd);
return 0;
}
Makefile
obj-m := led.o
KDIR :=/home/can//linux/4412/linux-3.8 # arm
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
arm-linux-gcc -static led_test.c -o led_test
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers modul* *oper
编译此段代码与运行此段代码的内核需一致,否则将无法加载模块
使用uname -r 查看内核版本
uname 查看操作系统信息 r选项查看内核版本