Created
April 18, 2013 07:49
-
-
Save creamidea/5410963 to your computer and use it in GitHub Desktop.
led.c arm入门练习 交叉编译
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "led.h" | |
#include <linux/init.h> | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/moduleparam.h> /* Param header */ | |
#include <linux/cdev.h> | |
#include <linux/slab.h> | |
#include <linux/fs.h> | |
#include <linux/types.h> | |
#include <asm/uaccess.h> /* 资源控制 */ | |
#include <linux/sched.h> /* 进程控制 */ | |
#include <asm/io.h> /* 内存读写方法 | |
* read: ioread32 | |
* write: iowrite32*/ | |
#define DRIVER_AUTHOR "icecream <[email protected]>" | |
#define DRIVER_DESC "A sample driver" | |
/* 引入两个变量 */ | |
module_param(mymajor, int, 0644); | |
module_param(name, charp, 0644); | |
/* 自己封装,以自己需求 */ | |
struct led_dev { | |
struct cdev cdev; | |
unsigned int* caddr; /* 代表ARM中的控制寄存器 0x56000010 */ | |
unsigned int* daddr; /* 代表ARM中的数据寄存器 0x56000014 */ | |
}; | |
struct led_dev* led_dev; /* 全局指针,方便后面的引用 */ | |
/* 读写操作 */ | |
/* inode描述节点,file描述的是系统中的 */ | |
static int led_open(struct inode* inode, struct file* file) | |
{ | |
struct led_dev* led_dev; | |
/* 根据结构体中的一个成员来获取到整个结构体的内容: struct led_dev, cdev */ | |
/* inode 代表一个设备, 后面获取的结构体会放到其中*/ | |
led_dev = container_of(inode->i_cdev, struct led_dev, cdev); | |
/* 保存led灯的私有数据,让灯与灯之间数据私有 */ | |
file->private_data = led_dev; | |
/* ACCMODE当前文件权限 */ | |
if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | |
file->f_pos = 0; /* 保证每次写数据从起始写到最后 */ | |
printk ("open suc[w]\n"); | |
} | |
return 0; | |
} | |
static int led_close(struct inode* inode, struct file* file) | |
{ | |
/* 系统会帮忙清理,这里只是简单的打印提示 */ | |
printk ("led_close Close\n"); | |
return 0; | |
} | |
/* 控制灯 */ | |
static void setup(unsigned long num, int p) | |
{ | |
unsigned int v = *(led_dev->daddr); /* 获取内容 */ | |
if (p) { | |
/* 灯亮 */ | |
/* 为何+4, 难道是移动到下一个位?0x56000010 */ | |
unsigned int t = ~(0x01 << (num + 4)); | |
v &= t; /* clear 0 */ | |
} else { | |
/* 灯灭 */ | |
unsigned int t = (0x01 << (num+4)); | |
v |= t; /* set 1 */ | |
} | |
/* 写回数据寄存器 */ | |
iowrite32(v, led_dev->daddr); | |
} | |
/* */ | |
//arg: 第几个灯 | |
//cmd: LED_ON(1), LED_OFF(0) | |
static int led_ioctl(struct inode* inode, struct file* file | |
, unsigned int cmd, unsigned long arg) | |
{ | |
switch(cmd) { | |
case LED_ON: | |
setup(arg, 1); | |
break; | |
default: | |
setup(arg, 0); | |
break; | |
} | |
return 0; | |
} | |
static const struct file_operations fops = { | |
.open = led_open, | |
.release = led_close, | |
.ioctl = led_ioctl, | |
/* .compat_ioctl = led_ioctl, */ | |
.owner = THIS_MODULE | |
}; | |
static int __init led_init(void) | |
{ | |
int ret; | |
dev_t devno; | |
unsigned int out = 0; | |
devno = MKDEV(mymajor, 0); | |
ret = register_chrdev_region(devno, 1, name); | |
if (ret < 0) { | |
alloc_chrdev_region(&devno, 0, 1, name); | |
mymajor = MAJOR(devno); | |
} | |
printk ("Major: %d, Minor: %d\n", mymajor, MINOR(devno)); | |
/* request memory */ | |
led_dev = (unsigned int*)kmalloc(sizeof(led_dev), GFP_KERNEL); | |
if (led_dev) { | |
printk ("Get memory successfully!\n"); | |
} else { | |
printk ("Get memory error!\n"); | |
return ENOMEN; | |
} | |
/* 对硬件到初始化 */ | |
/* 从内存空间映射的上层虚拟空间, 4:映射长度 */ | |
led_dev->caddr = (unsigned int*)ioremap(0x56000010, 4); | |
led_dev->daddr = (unsigned int*)ioremap(0x56000014, 4); | |
out = *(led_dev->caddr); | |
/* GPB5/6/7/8 --> 10,11;12,13;14,15;16,17 */ | |
/* 01 01 01 01 */ | |
/* 01 输出 */ | |
out |= 0x01 << 10; | |
out |= 0x01 << 12; | |
out |= 0x01 << 14; | |
out |= 0x01 << 16; | |
iowrite32(out, led_dev->caddr); | |
/* iowrite8(): 每次写入8字节 */ | |
/* iowrite16() 半字*/ | |
/* iowrite32() 1个字*/ | |
/* init cdev structor */ | |
cdev_init(&led_dev->cdev, &fops); | |
led_dev->cdev.owner = THIS_MODULE; | |
led_dev->cdev.ops = &fops; | |
if ((cdev_add(&led_dev->cdev, devno, 1))) { | |
printk ("add successfully!\n"); | |
} else { | |
printk ("add error!\n"); | |
} | |
return 0; | |
} | |
static void __exit led_exit(void) | |
{ | |
dev_t devno = MKDEV(mymajor, 0); | |
cdev_del(&led_dev->cdev); | |
/* 解除两个映射 */ | |
iounmap(&led_dev->caddr); | |
iounmap(&led_dev->daddr); | |
/* 释放空间 */ | |
kfree(led_dev); | |
led_dev = NULL; | |
/* 卸载设备 */ | |
unregister_chrdev_region(devno, 1); | |
printk("Exit the driver module!\n"); | |
} | |
module_init(led_init); /* enter */ | |
module_exit(led_exit); /* out */ | |
MODULE_LICENSE("Dual BSD/GPL"); | |
MODULE_AUTHOR(DRIVER_AUTHOR); | |
MODULE_DESCRIPTION(DRIVER_DESC); | |
MODULE_ALIAS("Linux Module"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment