移植U-Boot-2009.08到友善之臂mini2440

移植U-Boot-2009.08到友善之臂mini2440
移植U-Boot-2009.08到友善之臂mini2440

移植U-Boot-2009.08到友善之臂mini2440

声明

我也是学习Linux和ARM的新手,在收集资料的过程中发现了Tekkaman Ninja

和 flyslightly以及另外一些高手的文章,仔细的研究了他们的移植u-boot的过程,从中受益匪浅,他们给出了详细的移植步骤和完善的源码以及补丁,衷心感谢的他们分享他们的经验和工作成果,向他们的敬业和无私奉献精神致敬!

我在3.22-4.25中一个月的时间,仔细的看了他们的移植u-boot的文章,同时也自己试试移植,在经历10来次失败之后,在上周u-boot移植有了重大突破,将2008.10和2009.08初步移植成功,不过没完全实现他们已经实现的功能,不过可以通过tftp、nfs来启动内核和文件系统!在此再次感谢Tekkaman Ninja和 flyslightly!

我将他们两人的移植步骤综合了,形成了即将要贴出来的《移植U-Boot-2009.08到mini2440》,我已经检验过这上面的步骤内容大体没有问题,可以将2009.08移植成功,我此次贴出这个移植步骤,我

只是当了一个小编辑,将他们的文章重新组合了一下,不过我也加入了我移植过程遇到的问题。

主要参考的是:

Tekkaman Ninja:

移植U-Boot.1.3.1到S3C244和S3C2410

flyslightly:

移植U-Boot-2008.10到友善之臂mini2440

移植步骤将分为几个部分贴出来!

移植U-Boot-2009.08到友善之臂mini2440

本文是针对在友善之臂公司出品的以S3C2440 为核心的mini2440 开发板上实现U-Boot-2009.08的移植。其中存储介质为一片256 MB 的NAND Flash(K9F2G08),一片2MB的NOR Flash(SST-39VF1601),两片32 MB 的SDRAM(HY57V561620FTP),网卡芯片为DM9000a46 。

移植U-Boot.2009.08到友善之臂mini2440(一)

一、在U-Boot中建立自己的开发板类型,并测试编译。

在U-Boot中建立自己的开发板文件(以友善之臂的sbc2410x为基础)。开发板取名《mini2440》。

(1)在工作目录/opt下解压U-Boot-2009.08

[root@localhost opt]$ tar -xjvf u-boot-2009.08.tar.bz2

(2) 进入U-Boot-2009.08的根目录,修改Makefile,使用vi或gedit编辑器

[root@localhost opt] # cd u-boot-2009.08

[root@localhost u-boot-2009.08] # vi Makefile

u-boot-2009.08的根目录下面的Makefile中为mini2440建立编译项,以sbc2410x 为例子。

在2985行的后面加上对mini2440板子的支持!

sbc2410x_config: unconfig

@$(MKCONFIG) $(@:_config=) arm arm920t sbc2410x NULL s3c24x0

mini2440_config : unconfig

@$(MKCONFIG) $(@:_config=) arm arm920t mini2440 NULL s3c24x0

各项的意思如下:

arm: CPU的架构(ARCH)

arm920t: CPU的类型(CPU),其对应于cpu/arm920t子目录。

mini2440: 开发板的型号(BOARD),对应于board/ mini2440目录。

NULL: 开发者/或经销商(vender),NULL为没有。

s3c24x0: 片上系统(SOC)。

注意下面要与自己的开发系统一致,一般是默认arm-linux-!

CROSS_COMPILE=arm-linux-

特别注意:

在u-boot1.3.3及以上版本Makefile有一定的变化,使得对于24x0处理器从nand 启动的遇到问题。也就是网上有人说的:无法运行过lowlevel_init。其实这个问题是由于编译器将我们自己添加的用于nandboot的子函数nand_read_ll放到了

4K之后造成的(到这不理解的话,请仔细看看24x0处理器nandboot原理)。运行失败后,利用mini2440的4个LED调试发现u-boot根本没有完成自我拷贝,然后看uboot根目录下的System.map文件可知道原因。解决办法其实很简单,将下面这个语句:在uboot根目录下的Makefile中。在289行

__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))

改为:__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))

2 在/board子目录中建立自己的开发板mini2440目录

由于在上一步板子的开发者/或经销商(vender)中填了NULL ,所以开发板

mini2440目录一定要建在/board目录下,目录结构为board/mini2440。如果开发者/经销商(vender)不为NULL,则目录结构为board/verder_name/mini2440,否则编译会出错。

[root@localhost u-boot-2009.08]$ cd board

[root@localhost board]$ mkdir mini2440

[root@localhost board]$ cp -arf sbc2410x/* mini2440/

[root@localhost board]$ cd mini2440/

[root@localhost mini2440]$ mv sbc2410x.c mini2440.c

还要记得修改自己的开发板mini2440目录下的Makefile文件28行,不然编译时会出错:

[root@localhost mini2440]$ vi Makefile

修改Makefile的依赖文件

COBJS := sbc2410x.o flash.o

COBJS := mini2440.o flash.o

3 在include/configs/中建立开发板的配置头文件

[root@localhost mini2440]$ cd ../../.. (回到u-boot-2009.08的根目录下)[root@localhost u-boot-2009.08]$ cp include/configs/sbc2410x.h

include/configs/mini2440.h (添加mini2440的配置头文件)

4 测试编译能否成功

回到U-Boot主目录,(若之前有编译过,最好执行一下make clean) make mini2440_config,再make,编译生成u-boot.bin成功。

1、配置

[root@localhost u-boot-2009.08]$ make mini2440_config

Configuring for mini2440 board...

可能出现的问题:

(1) 如果出现:

$ make mini2440_config

Makefile:1927: *** 遗漏分隔符。停止。

请在U-boot的根目录下的Makefile的

@$(MKCONFIG) $(@:_config=) arm arm920t mini2440 NULL s3c24x0

前加上“Tab”键

2、测试编译

[root@localhost u-boot-2009.08]$ make

测试通过后进行下一步

移植U-Boot-2009.08到友善之臂mini2440(二)

2.1 修改cpu/arm920t/start.S

(1)删除AT91RM9200使用的LED代码,117、118行,关闭LED代码。start_code:

/*

* set the cpu to SVC32 mode

*/

mrs r0,cpsr

bic r0,r0,#0x1f

orr r0,r0,#0xd3

msr cpsr,r0

//bl coloured_LED_init

//bl red_LED_on

(2)修改编译条件支持s3c2440,在134行,修改寄存器地址定义,修改CPU频率初始化设置

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2440) ||

defined(CONFIG_S3C2410)

/* turn off the watchdog */

# if defined(CONFIG_S3C2400)

# define pWTCON 0x15300000

# define INTMSK 0x14400008 /* Interupt-Controller base addresses */

# define CLKDIVN 0x14800014 /* clock divisor register */

#else

# define pWTCON 0x53000000

# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */

# define INTSUBMSK 0x4A00001C

# define CLKDIVN 0x4C000014 /* clock divisor register */

# endif

修改CPU频率初始化设置

//xujun

#define CLK_CTL_BASE 0x4C000000

#define MDIV_405 0x7f << 12

#define PSDIV_405 0x21

#define MDIV_200 0xa1 <<12

#define PSDIV_200 0x31

(3)修改中断禁止部分

165行修改0x3ff为0x7ff

#if defined(CONFIG_S3C2410)

ldr r1, =0x7ff /*根据2410芯片手册,INTSUBMSK有11位可用*/

ldr r0, =INTSUBMSK

str r1, [r0]

#endif

169行添加

#if defined(CONFIG_S3C2440)

ldr r1, =0x7fff

ldr r0, =INTSUBMSK

str r1, [r0]

#endif

(4)修改时钟设置(2440的主频为405MHz。)

//xujun

#if defined(CONFIG_S3C2440)

/* FCLK:HCLK:PCLK = 1:4:8 */

ldr r0,=CLKDIVN

mov r1,#5

str r1,[r0]

mrc p15,0,r1,c1,c0,0

orr r1,r1,#0xc0000000

mcr p15,0,r1,c1,c0,0

mov r1,#CLK_CTL_BASE

mov r2,#MDIV_405

add r2,r2,#PSDIV_405

str r2,[r1,#0x04]

#else

/* FCLK:HCLK:PCLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

//xujun

mrc p15,0,r1,c1,c0,0

orr r1,r1,#0xc0000000

mcr p15,0,r1,c1,c0,0

mov r1,#CLK_CTL_BASE

mov r2,#MDIV_200

add r2,r2,#PSDIV_200

str r2,[r2,#0x04]

#endif

(5)将从Flash启动改成从NAND Flash启动

将relocate U-Boot to RAM 的代码注释或者删除

#if 0

#ifndef CONFIG_SKIP_RELOCATE_UBOOT 。。。。。。。。。。。。。。。。。

#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

#endif // if 0

在以下U-Boot的设置堆栈语句段(作用是将u-boot的源代码从nor flash到sdram 中):

/* Set up the stack */

stack_setup:

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot

的前面添加上(#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

#endif的后面添加上:)以下的nand boot代码:

定义u-boot在nand flash中存放的长度为#define LENGTH_UBOOT 0x60000,可以方便修改u-boot因为裁剪和增添大小的改变而占的长度。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。//xujun

#define LENGTH_UBOOT 0x60000

#define NAND_CTL_BASE 0x4E000000

#ifdef CONFIG_S3C2440_NAND_BOOT

@reset NAND

#define oNFCONF 0x00

#define oNFCONT 0x04

#define oNFSTAT 0x08

#define oNFCMD 0x20

mov r1,#NAND_CTL_BASE

ldr r2,=( (7<<12)|(7<<8)|(7<<4)|(0<<0))

str r2,[r1,#oNFCONF]

ldr r2,[r1,#oNFCONF]

ldr r2,=((1<<4)|(0<<1)|(1<<0))

str r2,[r1,#oNFCONT]

ldr r2,[r1,#oNFCONT]

ldr r2,=(0x6)

str r2,[r1,#oNFSTAT]

ldr r2,[r1,#oNFSTAT]

mov r2,#0xff

strb r2,[r1,#oNFCMD]

mov r3,#0

nand1:

add r3,r3,#0x1

cmp r3,#0xa

blt nand1

nand2:

ldr r2,[r1,#oNFSTAT]

tst r2,#0x4

beq nand2

ldr r2,[r1,#oNFCONT]

orr r2,r2,#0x2

str r2,[r1,#oNFCONT]

@get read to call C functions (for nand_read())

ldr sp,DW_STACK_START

mov fp,#0

@copy U-Boot to Ram

ldr r0,=TEXT_BASE

mov r1,#0x0

mov r2,#LENGTH_UBOOT //the u-boot’s len th

bl nand_read_ll

tst r0,#0x0

beq ok_nand_read

bad_nand_read:

loop2: b loop2

ok_nand_read:

@verify

mov r0,#0

ldr r1,=TEXT_BASE

mov r2,#0x400

go_next:

ldr r3,[r0],#4

ldr r4,[r1],#4

teq r3,r4

bne notmatch

subs r2,r2,#4

beq stack_setup

bne go_next

notmatch:

loop3: b loop3 @CONFIG_S3C2440_NAND_BOOT

#endif 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。在“ldr pc, _start_armboot”之后加入LED代码:

ldr pc, _start_armboot

#if defined(CONFIG_MINI2440_LED)

mov r1, #GPIO_CTL_BASE

add r1, r1, #oGPIO_B

ldr r2,=0x156aa

str r2, [r1, #oGPIO_CON]

mov r2, #0xff

str r2, [r1, #oGPIO_UP]

mov r2, #0x1c0

str r2, [r1, #oGPIO_DAT]

#endif

_start_armboot: .word start_armboot

在“_start_armboot: .word start_armboot ”后加入:

_start_armboot: .word start_armboot

#define STACK_BASE 0x33f00000

#define STACK_SIZE 0x10000

.align 2

DW_STACK_START: .word STACK_BASE+STACK_SIZE-4

移植U-Boot-2009.08到友善之臂mini2440(三)

3.1 在board/mini2440/目录下加入NAND Flash读取函数(start.S中需要的nand_read_ll函数)文件nand_read.c,新建nand_read.c,这里的开发板使用的是128MB ,大页的读写。下面是nand_read.c文件的内容。(注意和小页的NandFlash的不同)

board/mini2440/nand_read.c

#include

#include

#define __REGb(x) (*(volatile unsigned char *)(x))

#define __REGw(x) (*(volatile unsigned short *)(x))

#define __REGi(x) (*(volatile unsigned int *)(x))

#define NF_BASE 0x4e000000

#if defined(CONFIG_S3C2410)

#define NFCONF __REGi(NF_BASE + 0x0)

#define NFCMD __REGb(NF_BASE + 0x4)

#define NFADDR __REGb(NF_BASE + 0x8)

#define NFDATA __REGb(NF_BASE + 0xc)

#define NFSTAT __REGb(NF_BASE + 0x10)

#define NFSTAT_BUSY 1

#define nand_select() (NFCONF &= ~0x800)

#define nand_deselect() (NFCONF |= 0x800)

#define nand_clear_RnB() do {} while (0)

#elif defined(CONFIG_S3C2440)

#define NFCONF __REGi(NF_BASE + 0x0)

#define NFCONT __REGi(NF_BASE + 0x4)

#define NFCMD __REGb(NF_BASE + 0x8)

#define NFADDR __REGb(NF_BASE + 0xc)

#define NFDATA __REGb(NF_BASE + 0x10)

#define NFDATA16 __REGw(NF_BASE + 0x10)

#define NFSTAT __REGb(NF_BASE + 0x20)

#define NFSTAT_BUSY (1 << 2)

#define nand_select() (NFCONT &= ~(1 << 1))

#define nand_deselect() (NFCONT |= (1 << 1))

#define nand_clear_RnB() (NFSTAT |= NFSTAT_BUSY)

#endif

static inline void nand_wait(void)

{

int i;

while (!(NFSTAT & NFSTAT_BUSY))

for (i=0; i<10; i++);

}

#if defined(CONFIG_S3C2410)

#define NAND_PAGE_SIZE 512

#define BAD_BLOCK_OFFSET 517

#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)

#define NAND_BLOCK_SIZE 0x4000

#else

#define NAND_5_ADDR_CYCLE

#define NAND_PAGE_SIZE 2048

#define BAD_BLOCK_OFFSET NAND_PAGE_SIZE

#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)

#define NAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64)

#endif

#if defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512) #error "S3C2410 does not support nand page size != 512"

#endif

static int is_bad_block(unsigned long i)

{

unsigned char data;

unsigned long page_num;

nand_clear_RnB();

#if (NAND_PAGE_SIZE == 512)

NFCMD = NAND_CMD_READOOB;

NFADDR = BAD_BLOCK_OFFSET & 0xf;

NFADDR = (i >> 9) & 0xff;

NFADDR = (i >> 17) & 0xff;

NFADDR = (i >> 25) & 0xff;

#elif (NAND_PAGE_SIZE == 2048)

page_num = i >> 11;

NFCMD = NAND_CMD_READ0;

NFADDR = BAD_BLOCK_OFFSET & 0xff;

NFADDR = (BAD_BLOCK_OFFSET >> 8) & 0xff;

NFADDR = page_num & 0xff;

NFADDR = (page_num >> 8) & 0xff;

NFADDR = (page_num >> 16) & 0xff;

NFCMD = NAND_CMD_READSTART;

#endif

nand_wait();

data = (NFDATA & 0xff);

if (data != 0xff)

return 1;

return 0;

}

static int nand_read_page_ll(unsigned char *buf, unsigned long addr) {

unsigned short *ptr16 = (unsigned short *)buf;

unsigned int i, page_num;

nand_clear_RnB();

NFCMD = NAND_CMD_READ0;

#if (NAND_PAGE_SIZE == 512)

NFADDR = addr & 0xff;

NFADDR = (addr >> 9) & 0xff;

NFADDR = (addr >> 17) & 0xff;

NFADDR = (addr >> 25) & 0xff;

#elif (NAND_PAGE_SIZE == 2048)

page_num = addr >> 11;

NFADDR = 0;

NFADDR = 0;

NFADDR = page_num & 0xff;

NFADDR = (page_num >> 8) & 0xff;

NFADDR = (page_num >> 16) & 0xff;

NFCMD = NAND_CMD_READSTART;

#else

#error "unsupported nand page size"

#endif

nand_wait();

for (i = 0; i < NAND_PAGE_SIZE; i++)

{

*buf = (NFDATA & 0xff);

buf++;

}

return NAND_PAGE_SIZE;

}

int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)

{

int i, j;

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {

return -1;

}

nand_select();

nand_clear_RnB();

for (i=0; i<10; i++);

for (i=start_addr; i < (start_addr + size);)

{

j = nand_read_page_ll(buf, i);

i += j;

buf += j;

}

nand_deselect();

return 0;

}

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

3.2修改board/mini2440/Makefile文件,28行,将nand_read.c编译进u-boot:OBJS := mini2440.o nand_read.o flash.o

3.3修改board/mini2440/lowlevel_init.S文件

(1)修改REFRESH 的刷新周期:

/* REFRESH parameter */

#define REFEN 0x1 /* Refresh enable */

#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */

//#define Trp 0x0 /* 2clk */

#define Trc 0x3 /* 7clk */

#define Tchr 0x2 /* 3clk */

//#define REFCNT 0x0459

# if defined(CONFIG_S3C2440)

#define Trp 0x2 /* 4clk */

#define REFCNT 1012

#else

#define Trp 0x0 /* 2clk */

#define REFCNT 0x0459

#endif

3.4 在/board/mini2440/mini2440.c中对GPIO和PLL的配置进行修改

(1)添加网络头文件的支持

#include

#include

#include

#include

#include

(2)修改GPIO和PLL的配置

#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */

#define M_MDIV 0xC3

#define M_PDIV 0x4

#define M_SDIV 0x1

#elif FCLK_SPEED==1 /* Fout = 202.8MHz */

//#define M_MDIV 0x5c

//define M_PDIV 0x4

//#define M_SDIV 0x0

//xujun

#if defined(CONFIG_S3C2440)

/* Fout = 405MHz */

#define M_MDIV 0x7f

#define M_PDIV 0x2

#define M_SDIV 0x1

#endif

#endif

#if USB_CLOCK==0

#define U_M_MDIV 0xA1

#define U_M_PDIV 0x3

#define U_M_SDIV 0x1

#elif USB_CLOCK==1

//#define U_M_MDIV 0x48

//#define U_M_PDIV 0x3

//xujun

#if defined(CONFIG_S3C2440)

#define U_M_MDIV 0x38

#define U_M_PDIV 0x2

#endif

#define U_M_SDIV 0x2

#endif

(3)为连接LED和蜂鸣器的GPIO修改配置寄存器:

/* set up the I/O ports */

gpio->GPACON = 0x007FFFFF;

#if defined(CONFIG_MINI2440)

gpio->GPBCON = 0x00055555;

#else

gpio->GPBCON = 0x00044556;

#endif

gpio->GPBUP = 0x000007FF;

。。。。。。

(4)为引导linux内核,修改开发板的类型代码

/* arch number of SMDK2410-Board */

//gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

#if defined(CONFIG_S3C2440)

/* arch number ofMINI2440-Board */

gd->bd->bi_arch_number = MACH_TYPE_MINI2440 ;

#endif

(5)为使int board_init (void)设置完成后,LED1和LED2同时亮起,在int board_init (void)的最后添加:

/* adress of boot parameters */

gd->bd->bi_boot_params = 0x30000100

icache_enable();

dcache_enable();

# if defined(CONFIG_MINI2440_LED)

gpio->GPBDAT = 0x181;

#endif

return 0;

}

(6) 添加对dm9000的初始化函数

#ifdef CONFIG_DRIVER_DM9000

int board_eth_init(bd_t *bis)

{

return dm9000_initialize(bis);

#endif

(7)删除自带的nandflash的初始化函数

#if 0

#if defined(CONFIG_CMD_NAND)

extern ulong nand_probe(ulong physadr);

static inline void NF_Reset(void)

{

int i;

………………

#ifdef DEBUG

printf("NAND flash probing at 0x%.8lX\n", (ulong)nand);

#endif

printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20);

}

#endif

#endif

3.5修改 lib_arm/board.c文件

(1) 添加头文件支持

#include

#include

#include

(2)添加LED功能,指示进度

#if 0

/******************************************************************** ****

* Coloured LED functionality

******************************************************************** ****

* May be supplied by boards if desired

*/

void inline __coloured_LED_init (void) {}

……………………

void inline blue_LED_off(void)__attribute__((weak,

alias("__blue_LED_off")));

#endif

static int display_banner (void)

{

#if defined(CONFIG_MINI2440_LED)

S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); gpio->GPBDAT = 0x101;

#endif

………

if defined(CONFIG_RESET_PHY_R)

debug ("Reset Ethernet PHY\n");

reset_phy();

#endif

#endif

#if defined(CONFIG_MINI2440_LED)

S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();

#endif

# if defined(CONFIG_MINI2440_LED)

gpio->GPBDAT = 0x0;

#endif

printf("\n********************************************************** ");

printf("\n\thello! this U-BOOT is modified by XUJUN, at 2010-04-22\n ");

printf("\t-USTB--xujun--beijing--mini2440-uboot-\n");

printf("\t QQ is 306141829\n");

printf("\t-LOVE ARM Linux and U-BOOT-\n");

printf("******************************************************

****\n");

/* main_loop() can return to retry autoboot, if so just run it again. */

for (;;) {

main_loop ();

4.1 Nand Flash驱动

(1)修改/drivers/mtd/nand/s3c2410_nand.c,原来的nand驱动在

/cpu/arm920t/s3c24x0/nand.c中文件名和放置的位置都已经改变。#define NF_BASE 0x4e000000

#if defined(CONFIG_S3C2410)

#define NFCONF __REGi(NF_BASE + 0x0)

#define NFCMD __REGb(NF_BASE + 0x4)

#define NFADDR __REGb(NF_BASE + 0x8)

#define NFDATA __REGb(NF_BASE + 0xc)

#define NFSTAT __REGb(NF_BASE + 0x10)

#define NFECC0 __REGb(NF_BASE + 0x14)

#define NFECC1 __REGb(NF_BASE + 0x15)

#define NFECC2 __REGb(NF_BASE + 0x16)

#define S3C2410_NFCONF_EN (1<<15)

#define S3C2410_NFCONF_512BYTE (1<<14)

#define S3C2410_NFCONF_4STEP (1<<13)

#define S3C2410_NFCONF_INITECC (1<<12)

#define S3C2410_NFCONF_nFCE (1<<11)

#define S3C2410_NFCONF_TACLS(x) ((x)<<8)

#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)

#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)

#define S3C2410_ADDR_NALE 4

#define S3C2410_ADDR_NCLE 8

#endif

#if defined(CONFIG_S3C2440)

#define S3C2410_ADDR_NALE 0x08

#define S3C2410_ADDR_NCLE 0x0c

#define NFCONF __REGi(NF_BASE + 0x0)

#define NFCONT __REGb(NF_BASE + 0x4)

#define NFCMD __REGb(NF_BASE + 0x8)

#define NFADDR __REGb(NF_BASE + 0xc)

#define NFDATA __REGb(NF_BASE + 0x10)

#define NFMECCD0 __REGb(NF_BASE + 0x14)

#define NFMECCD1 __REGb(NF_BASE + 0x18)

#define NFSECCD __REGb(NF_BASE + 0x1c)

#define NFSTAT __REGb(NF_BASE + 0x20)

#define NFESTAT0 __REGb(NF_BASE + 0x24)

#define NFESTAT1 __REGb(NF_BASE + 0x28)

#define NFMECC0 __REGb(NF_BASE + 0x2c)

#define NFMECC1 __REGb(NF_BASE + 0x30)

#define NFSECC __REGb(NF_BASE + 0x34)

#define NFSBLK __REGb(NF_BASE + 0x38)

#define NFEBLK __REGb(NF_BASE + 0x3c)

#define NFECC0 __REGb(NF_BASE + 0x2c)

#define NFECC1 __REGb(NF_BASE + 0x2d)

#define NFECC2 __REGb(NF_BASE + 0x2e)

#define S3C2410_NFCONT_EN (1<<0)

#define S3C2410_NFCONT_INITECC (1<<4)

#define S3C2410_NFCONT_nFCE (1<<1)

#define S3C2410_NFCONT_MAINECCLOCK (1<<5)

#define S3C2410_NFCONF_TACLS(x) ((x)<<12)

#define S3C2410_NFCONF_TWRPH0(x) ((x)<<8)

#define S3C2410_NFCONF_TWRPH1(x) ((x)<<4)

#endif

(2)u-boot.2009.08自带的S3C2410_nand.c的s3c2410_hwcontrol函数有错。在此函数中,把chip->IO_ADDR_W值改写了,导致在写数据时出现错误。解决方法是使用一全局变量代替chip->IO_ADDR_W。在s3c2410_hwcontrol函数上一行定义这个全局变量,然后修改s3c2410_hwcontrol函数,让它支持

S3C2440,修改后如下:

ulong IO_ADDR_W = NF_BASE;

static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) {

//struct nand_chip *chip = mtd->priv;

DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);

if (ctrl & NAND_CTRL_CHANGE) {

//ulong IO_ADDR_W = NF_BASE;

IO_ADDR_W = NF_BASE;

if (!(ctrl & NAND_CLE))

IO_ADDR_W |= S3C2410_ADDR_NCLE;

if (!(ctrl & NAND_ALE))

IO_ADDR_W |= S3C2410_ADDR_NALE;

//chip->IO_ADDR_W = (void *)IO_ADDR_W;

#if defined(CONFIG_S3C2410)

if (ctrl & NAND_NCE)

NFCONF &= ~S3C2410_NFCONF_nFCE;

else

NFCONF |= S3C2410_NFCONF_nFCE;

}

#endif

#if defined(CONFIG_S3C2440)

if (ctrl & NAND_NCE)

NFCONT &= ~S3C2410_NFCONT_nFCE;

else

NFCONT |= S3C2410_NFCONT_nFCE;

}

#endif

if (cmd != NAND_CMD_NONE)

//writeb(cmd, chip->IO_ADDR_W);

writeb(cmd, (void *)IO_ADDR_W);

}

#ifdef CONFIG_S3C2410_NAND_HWECC

void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)

{

DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode); #if defined(CONFIG_S3C2410)

NFCONF |= S3C2410_NFCONF_INITECC;

#endif

#if defined(CONFIG_S3C2440)

NFCONT |= S3C2410_NFCONT_INITECC;

#endif

}

(3)修改board_nand_init函数如下

int board_nand_init(struct nand_chip *nand)

{

u_int32_t cfg;

u_int8_t tacls, twrph0, twrph1;

S3C24X0_CLOCK_POWER *const clk_power =

S3C24X0_GetBase_CLOCK_POWER();

DEBUGN("board_nand_init()\n");

clk_power->CLKCON |= (1 << 4);

#if defined(CONFIG_S3C2410)

/* initialize hardware */

twrph0 = 3; twrph1 = 0; tacls = 0;

cfg = S3C2410_NFCONF_EN;

cfg |= S3C2410_NFCONF_TACLS(tacls - 1);

cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);

cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);

NFCONF = cfg;

/* initialize nand_chip data structure */

nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c;

#endif

#if defined(CONFIG_S3C2440)

twrph0 = 4; twrph1 = 2; tacls = 0;

cfg = 0;

cfg |= S3C2410_NFCONF_TACLS(tacls - 1);

cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);

cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);

NFCONF = cfg;

NFCONT=

(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0);

/* initialize nand_chip data structure */

nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;

#endif

/* read_buf and write_buf are default */

/* read_byte and write_byte are default */

移植U-Boot-2009.08到友善之臂mini2440(五)

5.1在文件中添加“CONFIG_S3C2440”,使得原来s3c2410的代码可以编译进来

(1)/include/common.h文件的第496行:

基于linux的led驱动程序实现

基于linux的led驱动程序实现 一. 博创开发平台硬件LED的实现 博创开发平台设置了3个GPIO控制的LED和一个可直接产生外部硬件中断的按键,LED分别使用了S3C2410的GPC5,GPC6,GPC7三个GPIO,按键接到INT5中断。下面对S3C2410 GPIO的各个寄存器作出说明,用GPIO控制的LED就是通过操作GPIO的各个寄存器进行配置和操作的。S3C2410包含GPA 、GPB 、……、GPH 八个I/O端口。它们的寄存器是相似的:GPxCON 用于设置端口功能(00 表示输入、01表示输出、10 表示特殊功能、11 保留不用),GPxDAT 用于读/写数据,GPxUP 用于决定是否使用内部上拉电阻(某位为0 时,相应引脚无内部上拉;为1时,相应引脚使用内部上拉)。这里要稍微注意一点的地方是PORTA和其他几组端口的使用不太一样,这里不讨论A口,B到H组口的使用完全相同。以下是S3C2410手册上的数据[13]: 图1.1 S3C2410端口 GPC口有16个IO口,查datasheet《S3C2410》所用的地址为: 图1.2 C组GPIO的地址 即GPCCON 地址为0x56000020,GPCDAT地址为0x56000024,各位的设置具体见下图,则对应的GPCCON寄存器的位为:

图1.3 GPCCON寄存器相应的位 这里用到了5,6,7三个口,CON寄存器要完成对对应口的设置工作,将相应的口设置为输出状态,其他的口不用考虑,设置为输出的话就是0x15<<10,这样3个IO口就设置为了输出。下面就可以通过向DATA口写入低电平来点亮LED,GPCDAT的各位分布如下,每一个bit对应一个口。 图1.4 GPCDAT的位分布 GPCDAT有16位,我们这里要用到的就是5,6,7三位即将这3位设置为低电平点亮LED。具体使用情况见驱动的实现。 这三个LED的硬件原理图如下: 图1.5 GPIO控制的LED硬件原理图 二.通过GPIO控制的LED驱动程序 本驱动中没有用到内核提供的write_gpio宏,对硬件地址的操作完全自己实现,可分为以下几部分: ①模块的初始化和退出: int led_init(void)

USB键盘驱动程序

/* * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * * USB HIDBP Keyboard support */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to <>, or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include #include #include #include #include #include #include /* * Version Information */ #define DRIVER_VERSION "" #define DRIVER_AUTHOR "Vojtech Pavlik <>" #define DRIVER_DESC "USB HID Boot Protocol keyboard driver" #define DRIVER_LICENSE "GPL"

linux 设备输入子系统---源代码示例。自动捕获键盘鼠标等外设消息

Linux input 子系统详解与代码示例 李邦柱于杭州2014/01/09 Email:helpylee@https://www.360docs.net/doc/eb11050513.html, 由于linux的驱动模型增加了input层,导致几乎所有的底层驱动都把数据封装在event里上报给input子系统。由此看来,这种改变让kernel 更具有模块化,各个模块的耦合度更低了。下面我们一起来研究input 层^_^ 1.从用户层的角度看input(event事件) 了解linux的人一定会对/dev,/ sys, /proc这几个目录有所印象,这是从内核导出到用户层的接口(从这里几乎可以观览内核)。kernel为我们导出了input在用户态的接口,就是/dev/input/下的接口,所以我们只关注这个目录下的event*(event0/event1/……)字符设备。 那么这些event*是干什么用的?简单来说就是我们对计算机的输入(包括敲击键盘,移动鼠标等等操作)经过内核(底层驱动,input)处理最后就上报到这些event*里面了。 而这里event0,event1,..就是用来区分各个外设的,可以通过命令来查看外设具体和哪个event相关联:这个命令是:cat /proc/bus/input/devices 所以我们用此命令在linux系统查看外设信息。 2.在linux/input.h中有这些数据的结构: structinput_event { structtimeval time; //事件发生的时间 __u16 type; //事件类类型:按键和移动鼠标就是不同类型 __u16 code; __s32 value; //事件值:按键a和按键b就对应不同值 }; code: 事件的代码.如果事件的类型代码是EV_KEY,该代码code为设备键盘代码.代码植0~127为键盘上的按键代码,0x110~0x116 为鼠标上按键代码,其中0x110(BTN_ LEFT)为鼠标左键,0x111(BTN_RIGHT)为鼠标右键,0x112(BTN_ MIDDLE)为鼠标中键.其它代码含义请参

LINUX系统必备程序安装步骤

1.红帽企业版5获得root权限方法: su root

2. 红帽企业版5 启动samba的方法: a.在安装LINUX的过程中将所有选项都选择上,这样可以确保samba等软件 都已经安装好。 b. 修改/etc/samba/smb.conf,添加: [root] comment = Root Directories browseable = yes writeable = yes path = / valid users = smb(用户名) c.添加用户: RHEL5: Useradd smb //添加smb系统用户 Smbpasswd -a smb //修改密码 d.重新启动samba: /etc/init.d/smb restart e.windows访问LINUX 访问LINUX的IP地址,输入用户名smb及密码就可以正常访问linux了

3.建立tftp服务器: a.在安装LINUX的过程中将所有选项都选择上,这样可以确保tftp等软件都 已经安装好。 b.建立TFTP主工作目录: mkdir /tftpboot c.修改配置文件 vi /etc/xinet d.d/tftp修改内容如下: d.重新启动tftp /etc/init.d/xinetd restart e.确认TFTP启动的是否成功:netstat –a | grep tftp

4.NFS a.配置vi /etc/exports b.重新启动NFS服务器:/etc/init.d/nfs restart

5.升级安装LINUX内核: a.解压缩内核代码tar –xvzf linux-2.6.32.27 b.拷贝config 文件将目录boot下的原先LINUX内核的CONFIG文件复制到 新内核的根目录下名字为.config c.make menuconfig d.make bzImage e.make modules f. make modules_install g.制作init ramdisk: h.内核安装: i.升级内核后重新启动机器所遇到的问题解决办法: 方法:编译时修改.config文件中的“CONFIG_SYSFS_DEPRECATED_V2”,默认该选项为not set,被注释掉的,将其改为y。即修改为 “CONFIG_SYSFS_DEPRECATED_V2=y”,修改后,再编译,重启即正常了。

Linux下的一个使用中断的按键驱动程序v

Linux下的一个使用中断的按键驱动程序(S3C2440)#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*timer*/ #define BUTTON_IRQ IRQ_EINT8 //申请的中断号 #define DEVICE_NAME "button" //设备名字 #define BUTTONMINOR 0

#define DELAY (HZ/100) //延时100MS DECLARE_WAIT_QUEUE_HEAD(wq); //申请一个wq等待队列并初始化, //wait_queue_heat_t wq; //也可用两句来替换(申请初始化一个等待队列)//int_waitqueue_heat(&wq); static unsigned char key_down_cnt=0; //中断计数 static int ev_press=0; //唤醒等待的条件 static int button_Major; struct timer_list timer; //定时器链表 void timer_function()//定时产生后的处理函数 { int down; if(down = !s3c2410_gpio_getpin(BUTTON_IRQ)) //如果按键按下执行以下程序{ key_down_cnt++; //来一次,中断计数加一 ev_press = 1; //表示中断发生了 wake_up_interruptible(&wq); } //唤醒休眠的进程 return 0; } static irqreturn_t button_irq_ser(int irq,void *dev_id,struct pt_regs *regs) //中断服务程序 { //初始化定时器链表 init_timer(&timer); timer.data=0; timer.expires=jiffies+DELAY;

嵌入式LINUX四按键驱动

对一个具有四个按键的按键驱动的分析 源代码: /*Headers-------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_DEVFS_FS #include #endif /*V ars----------------------------------------------------*/ #define DEVICE_NAME "buttons" #define EXTINT_OFF (IRQ_EINT4 - 4) unsigned int buttons_major=0; unsigned int buttons_minor=0; unsigned int type = IRQT_FALLING; struct button_info { unsigned int irq_no; unsigned int gpio_port; unsigned int IN; int button_no; }; struct button_info realarm_button_info[4] = { { IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_INP, 1 }, { IRQ_EINT8, S3C2410_GPG0, S3C2410_GPG0_INP, 2 },

linux触摸屏驱动

linux-触摸屏驱动(2009-04-23 14:50) 分类:driver 开发触摸屏驱动,最好的范例莫过于mc68328digi.c的实现。在没有看到原文之前,我把其中用到的结构解析一下。 1,struct ts_pen_info 该结构是触摸屏的核心数据结构。用户程序和驱动程序的交互就是通过该数据结构完成的。结构体里面的x,y坐标和状态是gui中事件驱动的原始数据源。 2,环形队列 gui程序通过read完成对ts_pen_info的提取。而在内核中维护了一个环形队列,只要队列不为空,将立即返回数据给应用程序。 3,中断驱动机制 触摸屏是输入设备,因此使用的是中断驱动机制。只要有触摸事件发生,即向环形队列里面填充一项。 4,定时器的必要性 触摸屏的中断处理函数必然启动一个定时器。定时器的使用是为了检测出Drag操作。当按下触摸屏一直没有松开时,中断只会相应一次。这和触发方式关系不大,不是沿触发和电平触发的问题。主要是触摸屏的中断处理函数没有处理到松开是不会开放中断的。在这段时间内,就是通过定时器不停的启动,检测触摸屏的新坐标的。 5,misc驱动 触摸屏采用Misc结构的驱动。 12.2.1 触摸屏的硬件原理 12.2 触摸屏的设备驱动 12.2.1 触摸屏的硬件原理 按照触摸屏的工作原理和传输信息的介质,我们把触摸屏分为4种:电阻式、电容感应式、红外线式以及表面声波式。 电阻式触摸屏利用压力感应进行控制,包含上下叠合的两个透明层,通常还要用一种弹性材料来将两层隔开。在触摸某点时,两层会在此点接通。四线和八线触摸屏由两层具有相同表面电阻的透明阻性材料组成,五线和七线触摸屏由一个阻性层和一个导电层组成。 所有的电阻式触摸屏都采用分压器原理来产生代表X坐标和Y坐标的电压。如图12.4所示,分压器是通过将两个电阻进行串联来实现的。电阻R1连接正参考电压VREF,电阻R2接地。两个电阻连接点处的电压测量值与R2的阻值成正比。

实现了多键齐按和重复按键的嵌入式系统键盘驱动设计

实现了多键齐按和重复按键的嵌入式系统键盘驱动设计 1 键盘驱动程序的设计随着电子信息技术飞速发展,嵌入式系统构成的各种设备得到了广泛的应用,嵌入式Linux是一种开放源码、软实时、多任务的操作系统,是开发嵌入式产品的优秀操作系统平台,其中键盘是人机界面中人类监控计算机重要数据输入设备。实现键盘有两种方法:一种是采用现有的一些芯片实现键盘扫描;二是用软件实现键盘扫描。目前许多芯片可用来实现键盘扫描,但是键盘扫描的软件实现方法有助于缩减系统的重复开发成本,而只需很少的CPU 开销。嵌入式控制器的功能很强,可以充分利用这一资源。本课题提出的键盘方案是以嵌入式Linux和PXA255为软硬件平台,通过测试,表明其具有良好的稳定性和实时性。 2 矩阵式键盘的结构与工作原理本课题采用矩阵键盘,如图1所示。四根行线四根列线组成4 *4矩阵键盘,分别用CPU 的4个GPIO口。当有键按下,某个列GPI O 口电平被下拉从而产生下降沿,触发中断。其中按键行阵列必须提供上拉信号,列阵列加二极管,防止瞬间电流过大对GPI O口造成冲击。 图1 矩阵键盘原理图。 3 Linux键盘驱动简介在Linux中,键盘驱动被划分成两层来实现。上层是一个通用键盘抽象层,下层则是硬件处理层,主要对硬件进行直接的操作。键盘驱动程序上层公共部分在driver /keyboard 。c里。文件中最重要的是内核用EXPORT _SYM BOL这个宏导出的handle_scancode函数。在这个文件中还定义了其它的几个回调函数,它们由键盘驱动程序中上层公共部分调用,并且由底层硬件处理函数实现。键盘驱动程序的底层硬件处理部分则根据不同硬件有不同实现。 4 键盘驱动程序的实现4.1 宏定义module init和module exit通过宏定义module init和module exit可以看出,驱动程序的入口从kd_ctrl_init()开始。当内核模块加载的时候,默认调用module_ i nit(kd_c trl_init),在kd_ctr l_ i nit()中将完成一些初始化工作,主要如下:

精通Linux设备驱动程序开发-第7章-输入设备驱动

第7章 输入设备驱动 内核的输入子系统是为了对分散的、多种不同类别的输入设备(如键盘、鼠标、跟踪球、操纵杆、辊轮、触摸屏、加速计和手写板)进行统一处理的驱动。输入子系统带 来了如下好处: ?统一了物理形态各异的相似的输入设备的处理功能。例如,各种鼠标,不论 PS/2、USB,还是蓝牙,都被同样处理。 ?提供了用于分发输入报告给用户应用程序的简单的事件(event)接口。你的驱动不必创建、管理/dev节点以及相关的访问方法。因此它能很方便的调用输入API以发送鼠标移动、键盘按键,或触摸事件给用户空间。X Windows这样的应用程序能够无缝地运行于输入子系统提供的event接口之上。 ?抽取出了输入驱动的通用部分,简化了驱动,并提供了一致性。例如,输入子系统提供了一个底层驱动(成为serio)的集合,支持对串口和键盘控制器等硬 件输入设备的访问。 图7.1展示了输入子系统的操作。此子系统包括一前一后运行的两类驱动:事件驱动和设备驱动。事件驱动负责和应用程序的接口,而设备驱动负责和底层输入设备的通信。鼠标事件产生者mousedev,是前者的实例;而PS/2鼠标驱动是后者的实例。事件驱动和设备驱动都可以利用输入子系统的高效、可重用的核心提供的服务。 图 7.1. 输入子系统

事件驱动是标准的,对所有的输入类都是可用的,所以你更可能的是实现设备驱动而不是事件驱动。你的设备驱动可以利用一个已经存在的、合适的事件驱动通过输入核心和用户应用程序接口。需要注意的是本章使用的名辞“设备驱动”指的是输入设备驱动,而不是输入事件驱动。 输入事件驱动 输入子系统提供的事件接口已经发展成为很多图形窗口系统理解的标准。事件驱动提供一个硬件无关的抽象,以和输入设备交互;如同帧缓冲接口(在第12章《视频设备驱动》中讨论)提供一个通用的机制以和显示设备通信一样。事件驱动和帧缓冲驱动一起,将图形用户接口(GUI)和各种各样的底层硬件隔离开来。

s3c2410按键驱动完整版

/* 2410 中断按键驱动 *基于s3c2410的16个按键驱动,采用中断的方式,实现了阻塞和非阻塞,并用定时*器进行了消抖处理消抖,也实现的异步通知,POLL机制,每个源文件我都加了比较*详细的注释。各位刚刚学习ARM/Linux *驱动的同学可以参考。 */ // button_irq_driver .c 驱动源文件 // button_irq_test.c 应用程序---按键测试(open可实现阻塞和非阻塞) // button_poll_test.c 应用程序---poll机制按键测试 // button_fasync.c 应用程序---异步通知方式按键测试 /* button_irq_driver .c */ #include #include #include #include #include #include #include #include #include #include static unsigned int buttons_major = 0; //本地结构体,表示一个按键 struct fsbuttons_cdev{ struct cdev *buttons_cdev; //按键设备结构体

struct class *buttons_class;//所属类 unsigned int key_buttons; //按键管脚电?1 /0 wait_queue_head_t buttons_wq; struct timer_list button_timer; }; static struct fsbuttons_cdev *fs_buttons ; //构建一个结构体,用来描述中断管脚 struct fspin{ int irq; int pin; char *name; int num; int row_input; int row_output; int int_put; int key_val; }; static struct fspin fspin_desc[4]={ {IRQ_EINT0, S3C2410_GPF0, "row0", 0, S3C2410_GPF0_INP, S3C2410_GPF0_OUTP, S3C2410_GPF0_EINT0}, {IRQ_EINT2, S3C2410_GPF2, "row1", 1, S3C2410_GPF2_INP, S3C2410_GPF2_OUTP, S3C2410_GPF2_EINT2}, {IRQ_EINT11, S3C2410_GPG3, "row2", 2, S3C2410_GPG3_INP, S3C2410_GPG3_OUTP, S3C2410_GPG3_EINT11}, {IRQ_EINT19, S3C2410_GPG11, "row3", 3, S3C2410_GPG11_INP, S3C2410_GPG11_OUTP, S3C2410_GPG11_EINT19}, };

基于Linux内核的键盘模拟实现

基于Linux内核的键盘模拟实现 摘摘要:当前,由于Linux资源完全公开,使得Linux 的发展日益广泛快速。基于Linux的各种应用已逐渐深入日常生活的方方面面,尤其是在嵌入式领域,由于内核可裁减定制,因此可随意地根据用户需求进行整个系统的定制与重构。其中,我们可以通过对各种标准外部设备的驱动进行改造,从而实现用户对标准设备的特定需求,例如可以通过对键盘的模拟来实现操作的自动化,从而可以避免重复的键盘操作。 关键词:系统调用勾子函数键盘模拟 1Linux内核支持的外部调用接口 由于Linux内核作为系统最深层次的核心,因此外部的开发人员并不能直接对内核进行操作。然而在一些应用程序的开发过程中,又不得不使用内核的某些功能,因此就提供了一些外部接口供开发人员直接与底层内核打交道。 1.1中断 在Linux 下,硬件中断叫做IRQ(Interrupt Requests)。有两种IRQ,短类型和长类型。短IRQ需要很短的时间,在此

期间机器的其他部分被锁定,而且没有其他中断被处理。一个长IRQ需要较长的时间,在此期间可能发生其他中断(但不是发自同一个设备)。如果可能的话,最好把一个中段声明为长类型。如果CPU接到一个中断,它就会停止一切工作(除非它正在处理一个更重要的中断,在这种情况下要等到更重要的中断处理结束后才会处理这个中断),把相关的参数存储到栈里,然后调用中断处理程序。这意味着在中断处理程序本身中有些事情是不允许的,因为这时系统处在一个未知状态。解决这个问题的方法是让中断处理程序做需要马上做的事,通常是从硬件读取信息或给硬件发送信息,然后把对新信息的处理调度到以后去做。 实现的方法是在接到相关的IRQ(在Intel平台上有16个IRQ)时调用中断处理程序。这个函数接到IRQ号码、函数名、标志、一个/proc/interrupts的名字和传给中断处理程序的一个参数。标志中可以包括SA_SHIRQ来表明你希望和其他处理程序共享此IRQ(通常很多设备公用一个IRQ),或者一个SA_INTERRUPT表明这是一个紧急中断。这个函数仅在此IRQ 没有其他处理程序或需要共享所有处理程序时才会成功运行。 1.2系统调用 系统调用发生在用户进程,通过一些特殊的函数来请求

Linux平台驱动试卷 (答案)

湖南科技学院二○ 一四 年 下 学期期末考试 电信、电科 专业 2011 年级 Linux 平台驱动 试题 考试类型:闭卷 试卷类型: A 卷 考试时量: 120 分钟 一、选择题(每题3分,共30分) 1) 嵌入式系统,是以(B )为中心,以计算机为基础,并且软硬件可定制,适用于各种应用场合,对功能、可靠性、成本、体积、功耗有严格要求的专用计算机系统 A.Linux B.应用 C.数据处理 D.产品 2) 嵌入式系统的四大组成部分,分别是:嵌入式微处理器、外围硬件设备、( D )、用户应用程序 A.嵌入式底层驱动 B.嵌入式系统调用 C.嵌入式根文件系统 D.嵌入式操作系统 3) 目前人们所指的嵌入式微处理器一般是指( D )位 A.4bit B.8bit C.16bit D.32bit 4) Linux 系统中,内核以(D )区分设备。 A.设备节点名 B :设备设备节点号 C.设备名称 D 。设备号 5) 对交叉编译描述正确的是(B ) A.在同一平台完成编译和运行 B.在一种平台上能编译出不同平台上运行的程序

C.使用同一交叉编译器编译出来的可执行文件是跨平台运行的 D.动态库是跨平台的,不需要交叉编译 6) s5pv210上电首先执行的代码来自于那里 ( A) A.iROM B.iRAM C.NAND flash D.SD卡 7)将C源程序编译成目标文件(*.o),而不进行链接的编译选项是(D) A.-o B.-E -o C.-S -o D.-c -o 8)通常情况下,kmalloc函数能分配的最大内存是(C) A.4K B.64K C.128K D.4M 9)Linux系统启动后,一般将设备文件放在以下那个目录( B) A . /etc B . /dev C. /sys D. /var 10)对于嵌入式C程序描述正确的是?(C ) A. 必须以_start作为程序入口 B. 必须以main函数作为程序入口 C. 必须设置堆栈 D. 裸机可执行程序是ELF格式的 二、填空题(本题共5小题,每空1分共10分) 1)Linux系统驱动设备分为字符设备、块设备和网络设备三大类。 2)嵌入式BootLoader的开发建立,依赖CPU体系结构、微处理器芯片、开发 板外设和内核镜像格式 3)u-boot传递给内核的参数“root=/dev/mtdblock4 rootfstype=yaffs2 init=/linuxrc console=ttySAC0”的意义是root指的是文件系统在内核中的位置、rootfstype指的是根文件系统的类型、init指的是内核启动后的第一个用户程序、console指定打印信息采用那一个串口作为控制台

操作系统课程设计 键盘驱动

一、实验选题 (1) 二、模块整体功能介绍及主要目标 (1) 三、头文件的分析 (2) 四、数据结构的分析 (2) 1、数组tty_table[] (2) 2、tty_struct 数据结构 (2) 3、tty 等待队列数据结构 (3) 4、各个数据结构间的关系图 (3) 五、函数的分析 (4) 1、采用中断驱动的I / O设备键盘的循环周期 (4) 2、键盘中断处理程序 (5) 3、ctrl和alt键的处理 (7) 4、caps、scroll、num键的处理 (8) 5、数字小键盘的处理 (11) 6、减号键的处理 (13) 7、功能键的处理 (14) 8、do_self的处理 (15) 9、左,右shift键的处理 (16) 六、分析体会及亮点说明 (16) 七、参考文献 (20)

一、实验选题 实验题目是:Linux0.11字符设备驱动中的键盘驱动程序源代码分析,这部分涉及到操作系统的中断、I/O应用接口、I/O子系统等相关知识,程序源代码参考Linux0.11中kernel目录下的keyboard.s文件。 二、模块整体功能介绍及主要目标 该模块键盘中断处理程序 keyboard.s 主要用于读入用户键入的字符并放入read_q 缓冲队列中。其具体实现机制是:当用户在键盘上键入了一个字符时,会引起键盘中断响应(中断请求信号IRQ1,对应中断号INT 33),此时键盘中断处理程序就会从键盘控制器读入对应的键盘扫描码,然后根据使用的键盘扫描码映射表译成相应字符,放入tty 读队列read_q 中。然后调用中断处理程序的C函数do_tty_interrupt(),它又直接调用行规则函数copy_to_cooked()对该字符进行过滤处理,并放入tty 辅助队列secondary 中,同时把该字符放入tty 写队列write_q 中,并调用写控制台函数 con_write()。此时如果该终端的回显(echo)属性是设置的,则该字符会显示到屏幕上。do_tty_interrupt()和copy_to_cooked () 函数在tty_io.c 中实现。用图描述如下:

按键驱动改写成input驱动

1、建立文件夹InputKey 2、在文件夹InputKey下建立驱动程序inputDev.c。 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MODULE_AUTHOR("wjb"); MODULE_LICENSE("GPL"); struct input_dev* button_devp; struct button_irq_desc{ int irq; int pin; int number; char *name; }; static struct button_irq_desc button_irqs[] = { {IRQ_EINT8, S3C2410_GPG(0), 0, "KEY0"}, {IRQ_EINT11, S3C2410_GPG(3), 1, "KEY1"}, {IRQ_EINT13, S3C2410_GPG(5), 2, "KEY2"}, {IRQ_EINT15, S3C2410_GPG(6), 3, "KEY3"}, {IRQ_EINT14, S3C2410_GPG(7), 4, "KEY4"}, {IRQ_EINT19, S3C2410_GPG(11), 5, "KEY5"}, }; static irqreturn_t button_interrupt(int irq, void* dev_id) { struct button_irq_desc *button_irqs = (struct button_irq_desc*)dev_id; int down;

Linux+USB+鼠标驱动程序详解

USB 总线引出两个重要的链表! 一个USB 总线引出两个重要的链表,一个为USB 设备链表,一个为USB 驱动链表。设备链表包含各种系统中的USB 设备以及这些设备的所有接口,驱动链表包含USB 设备驱动程序(usb device driver)和USB 驱动程序(usb driver)。 USB 设备驱动程序(usb device driver)和USB 驱动程序(usb driver)的区别是什么? USB 设备驱动程序包含USB 设备的一些通用特性,将与所有USB 设备相匹配。在USB core 定义了:struct usb_device_driver usb_generic_driver。usb_generic_driver 是USB 子系统中唯一的一个设备驱动程序对象。而USB 驱动程序则是与接口相匹配,接口是一个完成特定功能的端点的集合。 设备是如何添加到设备链表上去的? 在设备插入USB 控制器之后,USB core 即会将设备在系统中注册,添加到USB 设备链表上去。 USB 设备驱动程序(usb device driver)是如何添加到驱动链表上去的? 在系统启动注册USB core 时,USB 设备驱动程序即将被注册,也就添加到驱动链表上去了。 接口是如何添加到设备链表上去的? 在USB 设备驱动程序和USB 设备的匹配之后,USB core 会对设备进行配置,分析设备的结构之后会将设备所有接口都添加到设备链表上去。比如鼠标设备中有一个接口,USB core 对鼠标设备配置后,会将这个接口添加到设备链表上去。 USB 驱动程序(usb driver)是如何添加到驱动链表上去的? 在每个USB 驱动程序的被注册时,USB 驱动程序即会添加到驱动链表上去。比如鼠标驱动程序,usb_mouse_init 函数将通过usb_register(&usb_mouse_driver) 将鼠标驱动程序注册到USB core 中,然后就添加到驱动链表中去了。其中usb_mouse_driver 是描述鼠标驱动程序的结构体。 已配置状态(configured status)之后话 当鼠标的设备、接口都添加到设备链表,并且鼠标驱动程序也添加到驱动链表上去了,系统就进入一种叫做已配置(configured)的状态。要达到已配置状态,将经历复杂的过程,USB core 为USB 设备奉献着无怨无悔。在这个过程中,系统将会建立起该设备的的设备、配置、接口、设置、端点的描述信息,它们分别被usb_device、usb_configuration、usb_interface、usb_host_interface、usb_host_endpoint 结构体描述。 设备达到已配置状态后,首先当然就要进行USB 驱动程序和相应接口的配对,对于鼠标设备来说则是鼠标驱动程序和鼠标中的接口的配对。USB core 会调用usb_device_match 函数,通过比较设备中的接口信息和USB 驱动程序中的id_table,来初步决定该USB 驱动程序是不是跟相应接口相匹配。通过这一道关卡后,USB core 会认为这个设备应该由这个驱动程序负责。 然而,仅仅这一步是不够的,接着,将会调用USB 驱动程序中的probe 函数

基于ARM的矩阵键盘设计及其linux驱动实现

1.引言 ARM微处理器已广泛应用于工业控制、消费类电子产品、通信系统等领域。矩阵键盘是一种常用的键盘形式,它将按键设计成M行N列,这样共需M+N根信号线,却可驱动M×N个按键,大大节约了I/O资源。本文介绍了一种利用TQ2440开发板的GPIO口扩展5×4矩阵键盘的方法,并将所有按键重新布局成手持终端的键盘形式,方便操作。 2.硬件设计 本设计扩展5行4列的矩阵键盘,如图1所示。其中行线ROW1-ROW5连接S3C2440的中断引脚EINT8,EINT9,EINT11,EINT13,EINT14[1]。这些中断引脚本身连有10kΩ的上拉电阻,把中断引脚电平拉高,确保按键空闲时不会触发中断。列线COL1-COL4连接S3C2440的普通I/O口GPF3,GPF4,GPG7,GPG10.这里需要注意的问题是:确保行线所用的中断在Linux的其他设备中均未使用到,否则会引起该驱动程序或其他驱动程序初始化失败。 考虑到手持终端设备按键的常用性与操作的方便性,只取矩阵键盘的前18键,并将它们重新布局为图2的形式。其中Ent键具有二重功能,即确认功能(短按)和开关机功能(长按),此功能将在驱动程序中实现。

3.矩阵键盘的Linux驱动程序设计 3.1 键盘驱动总体概述 驱动程序是操作系统内核和硬件设备之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,使应用程序可以像操作普通文件一样操作硬件设备[2]。驱动程序没有main函数,它以一个模块初始化函数作为入口,并且它完成初始化之后不再运行,等待系统调用。 驱动程序是linux内核的一部分,所以在程序编写上要采用linux的表达方式。首先将列I/O端口定义为数组:col_table []={ S3C2410_GPF3,S3C2410_GPF4,…},行I/O端口定义为结构型: button_irqs []={ {IRQ_EINT8,S3C2410_GPG0,S3C2410_GPG0_EINT8,0,“R1″}, {IRQ_EINT9,S3C2410_GPG1,S3C2410_GPG1_EINT9,1,”R2″}, …}。//中断号(irq),引脚(pin),引脚设置,序号,名称 矩阵键盘是作为Linux的一个字符设备注册到系统中的。我们首先向系统注册矩阵键盘

相关文档
最新文档