天天看點

ARM-Linux自動建立裝置結點

硬體平台: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、配置核心

ARM-Linux自動建立裝置結點

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");