在学习安卓时候对驱动还是有疑惑 ,用jz2440重写驱动
板子:jz2440
系统:ubutu16
最后所有代码在底部
先配置板子uboot能与主机互相联通
如果配置是
开发版 192.168.31.10
电脑 192.168.31.5
2440_ubuntu 192.168.31.51
4412 192.168.31.200
配置uboot的ip和服务器ip
set ipaddr 192.168.31.10
set serverip 192.168.31.51
setenv netmask 255.255.255.0
setenv gatewayip 192.168.31.1
save
ping 的到虚拟机
可以使用nfs挂载根目录 板子启动根文件系统在主机上方便传输,也可以不弄,在windos传输
进入uboot 输入print
bootarg root(根文件系统)在nandflash上 改为在虚拟机上
bootcmd 启动内核的命令
进入板子的linux 用nfs传输文件
mount -t nfs -o intr,nolock,rsize=1024,wsize=1024 192.168.31.51:/work/nfs_root /mnt
根据button_test.c 编译出可执行驱动的文件 button_test
执行make命令生成驱动文件
装载驱动文件
insmod buttons.ko
用 lsmod 查看装载了没有
cat /proc/devices
分配给我的设备号是252
在main函数中 要打开dev/buttons
查看是否有这个设备节点
现在已经有了如果没有手工创建设备节点
mknod /dev/buttons c 252 0
代码里有自动创建设备节点
register_chrdev 分配主设备号,给内核知道,把驱动注册进内核数组
class_create 创建一个/sys/class/sixth_dev的类,类下面生成buttons设备
class_device_create 创建/dev/buttons 文件,给 app 的 fb = open() 使用
里面有主设备号信息次设备号信息
mdev根据这些设备信息生成设备节点
系统自带的热拔插程序 当有了设备信息后 自动生成设备节点 应用程序只要名字对了,打开里面的设备节点就能使用
驱动和应用程序交换数据
在驱动程序里里有 copy_to_usr copy_from_usr 对应着应用程序里的read write
copy_to_usr( to, &from, sizeof(from))
To:用户空间函数 (可以是数组)
From:内核空间函数(可以是数组)
sizeof(from):内核空间要传递的数组的长度
驱动代码
应用代码
copy_from_usr(&from , to , sizeof(to) )
To:用户空间函数 (可以是数组)
From:内核空间函数(可以是数组)
sizeof(from):内核空间要传递的数组的长度
驱动代码
应用代码
button_test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
/* sixthdrvtest
*/
int fd;
void my_signal_fun(int signum)
{
unsigned char key_val;
read(fd, &key_val, 1);
printf("key_val: 0x%x\n", key_val);
}
int main(int argc, char **argv)
{
unsigned char key_val;
int ret;
int Oflags;
//signal(SIGIO, my_signal_fun);
fd = open("/dev/buttons", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
return -1;
}
//fcntl(fd, F_SETOWN, getpid());
//Oflags = fcntl(fd, F_GETFL);
//fcntl(fd, F_SETFL, Oflags | FASYNC);
while (1)
{
ret = read(fd, &key_val, 1);
printf("key_val: 0x%x, ret = %d\n", key_val, ret);
//sleep(5);
}
return 0;
}
button.c(驱动文件,用makefile编译)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>
static struct class *sixthdrv_class;
static struct class_device *sixthdrv_class_dev;
volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;
volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;
static struct timer_list buttons_timer;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/* 中断事件标志, 中断服务程序将它置1,sixth_drv_read将它清0 */
static volatile int ev_press = 0;
static struct fasync_struct *button_async;
struct pin_desc{
unsigned int pin;
unsigned int key_val;
};
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val;
struct pin_desc pins_desc[4] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPG3, 0x03},
{S3C2410_GPG11, 0x04},
};
static struct pin_desc *irq_pd;
//static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量并初始化为1
static DECLARE_MUTEX(button_lock); //定义互斥锁
/*
* 确定按键值
*/
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
/* 10ms后启动定时器 */
irq_pd = (struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies+HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
static int sixth_drv_open(struct inode *inode, struct file *file)
{
#if 0
if (!atomic_dec_and_test(&canopen))
{
atomic_inc(&canopen);
return -EBUSY;
}
#endif
if (file->f_flags & O_NONBLOCK)
{
if (down_trylock(&button_lock))
return -EBUSY;
}
else
{
/* 获取信号量 */
down(&button_lock);
}
/* 配置GPF0,2为输入引脚 */
/* 配置GPG3,11为输入引脚 */
request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);
return 0;
}
ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
if (size != 1)
return -EINVAL;
if (file->f_flags & O_NONBLOCK)
{
if (!ev_press)
return -EAGAIN;
}
else
{
/* 如果没有按键动作, 休眠 */
wait_event_interruptible(button_waitq, ev_press);
}
/* 如果有按键动作, 返回键值 */
copy_to_user(buf, &key_val, 1);
ev_press = 0;
return 1;
}
int sixth_drv_close(struct inode *inode, struct file *file)
{
//atomic_inc(&canopen);
free_irq(IRQ_EINT0, &pins_desc[0]);
free_irq(IRQ_EINT2, &pins_desc[1]);
free_irq(IRQ_EINT11, &pins_desc[2]);
free_irq(IRQ_EINT19, &pins_desc[3]);
up(&button_lock);
return 0;
}
static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait); // 不会立即休眠
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static int sixth_drv_fasync (int fd, struct file *filp, int on)
{
printk("driver: sixth_drv_fasync\n");
return fasync_helper (fd, filp, on, &button_async);
}
static struct file_operations sencod_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = sixth_drv_open,
.read = sixth_drv_read,
.release = sixth_drv_close,
.poll = sixth_drv_poll,
.fasync = sixth_drv_fasync,
};
int major;
static void buttons_timer_function(unsigned long data)
{
struct pin_desc * pindesc = irq_pd;
unsigned int pinval;
if (!pindesc)
return;
pinval = s3c2410_gpio_getpin(pindesc->pin);
if (pinval)
{
/* 松开 */
key_val = 0x80 | pindesc->key_val;
}
else
{
/* 按下 */
key_val = pindesc->key_val;
}
ev_press = 1; /* 表示中断发生了 */
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
kill_fasync (&button_async, SIGIO, POLL_IN);
}
static int sixth_drv_init(void)
{
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
//buttons_timer.expires = 0;
add_timer(&buttons_timer);
major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);//给内核知道
sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");
/* 为了让mdev根据这些信息来创建设备节点 */
sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
gpfdat = gpfcon + 1;
gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
gpgdat = gpgcon + 1;
return 0;
}
static void sixth_drv_exit(void)
{
unregister_chrdev(major, "sixth_drv");
class_device_unregister(sixthdrv_class_dev);
class_destroy(sixthdrv_class);
iounmap(gpfcon);
iounmap(gpgcon);
return 0;
}
module_init(sixth_drv_init);
module_exit(sixth_drv_exit);
MODULE_LICENSE("GPL");
makefile
KERN_DIR = /work/system/linux-2.6.22.6
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += buttons.o
KERM_DIR是驱动程序要根据所用内核才能编译出 虚拟机里要有这个内核