硬件平台:FL2440
内核版本:2.6.28
主机平台:Ubuntu 11.04
内核版本:2.6.39
原创作品,转载请标明出处http://blog.csdn.net/yming0221/archive/2011/06/27/6570072.aspx
1、首先配置busybox
busybox
Linux System Utilities --->
[*] mdev
[*] Support /etc/mdev.conf
[*] Support command execution at device addition/removal
2、配置内核
3、修改文件系统里的/etc/init.d/rcS
#!/bin/sh
/bin/mount -a
/sbin/ifconfig eth0 192.168.0.3 up
#exec /usr/etc/rc.mouse
4、修改文件系统中/linuxrc文件
#!/bin/sh
#echo "mount /etc as ramfs"
#/bin/mount -n -t ramfs ramfs /etc
#/bin/cp -a /mnt/etc/* /etc
#/bin/mount -n -t ramfs ramfs /var/state/dhcp
#/bin/mount -n -t ramfs ramfs /var/log/boa
#/bin/mount -n -t ramfs ramfs /usr/Setting
#/bin/cp -a /mnt/Setting/* /usr/Setting
#/bin/mount -n -t ramfs ramfs /tmp
#/bin/cp -a /mnt/etc/* /etc
/bin/mount -t proc proc /proc
/bin/mount -t sysfs sysfs /sys
/bin/mount -t tmpfs tmpfs /dev
mkdir /dev/pts
mkdir /dev/shm
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s
exec /sbin/init
4、修改/etcfstab
vi ./etc/fstab
#device mount-point type options dump fsck order
none /dev/pts devpts mode=0622 0 0
tmpfs /dev/shm tmpfs defaults 0 0
这样编写驱动时不用手动创建设备结点文件了
下面是改写的使用混杂设备的ADC驱动程序,这样可以自动创建和删除设备结点了
#include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/miscdevice.h> /*创建设备节点*/ #include <linux/clk.h> #include <linux/wait.h> /*定义DECLARE_WAIT_QUEUE_HEAD*/ #include <linux/irqreturn.h> /*定义了irqreturn_t等*/ #include <linux/interrupt.h> /*request_irq disable_irq enable_irq*/ #include <asm/io.h> #include <asm/uaccess.h> #include <asm/irq.h> /*其中包含了#include "mach/irqs.h" */ #include <plat/regs-adc.h> #include <mach/regs-clock.h> #define ADC_MAJOR 102 #define ADC_NAME "my_adc" #define SUCCESS 0 static int adc_open(struct inode *,struct file *); static int adc_release(struct inode *,struct file *); static int __init adc_init(void); static int __exit adc_exit(void); static ssize_t adc_read(struct file *,char *,size_t,loff_t *); volatile unsigned long adc_con; unsigned long adc_dat0; int flag;//等待任务完成标志 unsigned long buf;//存放转换完成的数据 //声明等待队列 DECLARE_WAIT_QUEUE_HEAD(adc_wait); struct clk *adc_clk; static irqreturn_t adc_interrupt(int irq,void * dev_id)//中断处理程序 { if(flag==0) { buf=(readw(adc_dat0) & 0x3ff );//读取转换完成的数据 flag=1; wake_up_interruptible(&adc_wait);//唤醒等待其上的进程 printk("Read value is %ld\n",buf); } return IRQ_HANDLED; } static struct file_operations adc_ops = { .owner = THIS_MODULE, .read = adc_read, .open = adc_open, .release = adc_release, }; static struct miscdevice adc_misc = { .name = ADC_NAME, .minor = ADC_MAJOR, .fops = &adc_ops, }; static int __init adc_init(void) { int ret; adc_clk = clk_get(NULL,"adc");//获取时钟 clk_enable(adc_clk);//使能时钟 ret=misc_register(&adc_misc); //注册设备 if(ret<0) { printk("register device fail\n"); return ret; } adc_con=(unsigned long)ioremap(0x58000000,4); adc_dat0=(volatile unsigned long)ioremap(0x58000000+S3C2410_ADCDAT0,4); if( !(adc_con & adc_dat0) ) { printk("Failed to ioremap\n"); goto handle; } printk("Initialized...\n"); return SUCCESS; handle: misc_deregister(&adc_misc); return -1; } static int adc_open(struct inode * inode,struct file * file) //打开设备函数 { //注册中断 int ret; //disable_irq(IRQ_ADC); //enable_irq(IRQ_ADC); ret=request_irq(IRQ_ADC,adc_interrupt,IRQF_SHARED,ADC_NAME,1);//注册中断 IRQ_ADC在 mach/irqs.h中定义 if(ret<0) { printk("IRQ %d can not request\n",IRQ_ADC); return ret; } return SUCCESS; } static int adc_release(struct inode * inode,struct file * file) //关闭设备函数 { free_irq(IRQ_ADC,1);//释放中断 return SUCCESS; } static ssize_t adc_read(struct file *file, char * buffer, size_t length, loff_t * offset)//设备读取函数 { writew((1<<14)|(0x31<<6),adc_con); //设置ADCCON writew((readw(adc_con) | 0x1),adc_con); //启动AD转换 wait_event_interruptible(adc_wait,flag); flag=0; } static int __exit adc_exit(void) //驱动卸载函数 { iounmap(adc_con); iounmap(adc_dat0); misc_deregister(&adc_misc); clk_disable(adc_clk); clk_put(adc_clk); printk("The adc is unintialized\n"); return SUCCESS; } module_init(adc_init); module_exit(adc_exit); MODULE_LICENSE("GPL");