在學習安卓時候對驅動還是有疑惑 ,用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是驅動程序要根據所用內核才能編譯出 虛擬機裏要有這個內核