文档库 最新最全的文档下载
当前位置:文档库 › linux驱动学习笔记Camif

linux驱动学习笔记Camif

linux驱动学习笔记Camif
linux驱动学习笔记Camif

触摸屏驱动学习:

\drivers\media\video\s3c2440camif.c

\drivers\media\video\s3c2440_ov9650.c

\drivers\media\video\sccb.c

硬件连接

I2C总线连接

I2CSCL ——GPE14

I2CSDA——GPE15

Sccb.h

#define SIO_C S3C2410_GPE14

#define SIO_D S3C2410_GPE15

#define State(x) s3c2410_gpio_getpin(x)

#define High(x) do{s3c2410_gpio_setpin(x,1); smp_mb();}while(0)

#define Low(x) do{s3c2410_gpio_setpin(x,0); smp_mb();}while(0)

#define WAIT_STABLE() do{udelay(10);}while(0)

#define WAIT_CYCLE() do{udelay(90);}while(0)

#define CFG_READ(x) do{s3c2410_gpio_cfgpin(x,S3C2410_GPIO_INPUT);smp_mb();}while(0) #define CFG_WRITE(x) d o{s3c2410_gpio_cfgpin(x,S3C2410_GPIO_OUTPUT);smp_mb();}while(0) void sccb_write(u8 IdAddr, u8 SubAddr, u8 data);

u8 sccb_read(u8 IdAddr, u8 SubAddr);

CFG_WRITE(x)把GPIO设置为输出

CFG_READ(x)把GPIO设置为输入

High(x) 把GPIO设置为高电平

Low(x) 把GPIO设置为低电平

把SCL和Data都拉高,即为默认初始化状态电平

int sccb_init(void)

{

CFG_WRITE(SIO_C);

CFG_WRITE(SIO_D);

High(SIO_C);

High(SIO_D);

WAIT_STABLE();

return 0;

}

由上面的图可以看出,CLK高电平时,DATA拉低,即为START

static void __inline__ sccb_start(void)

{

CFG_WRITE(SIO_D);

Low(SIO_D);

WAIT_STABLE();

}

使用到一个信号量

static DECLARE_MUTEX(bus_lock);

void sccb_write(u8 IdAddr, u8 SubAddr, u8 data)

{

down(&bus_lock);

sccb_start();

sccb_write_byte(IdAddr);

sccb_write_byte(SubAddr);

sccb_write_byte(data);

sccb_stop();

up (&bus_lock);

}

首先把信号量数值降低,表示自己使用,如果此时信号量不大于0,表示bus正在使用,驱动会在此等待,知道信号量大于0,然后,将其减1,此时bus对外界不可用。最后再把信号量加1,表示bus

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

摄像头接口初始化:

/*

* camif_init()

*/

static int __init camif_init(void)

{

配置CAMIF的GPIO接口功能

/* set gpio-j to camera mode. */

s3c2410_gpio_cfgpin(S3C2440_GPJ0, S3C2440_GPJ0_CAMDATA0);

s3c2410_gpio_cfgpin(S3C2440_GPJ1, S3C2440_GPJ1_CAMDATA1);

s3c2410_gpio_cfgpin(S3C2440_GPJ2, S3C2440_GPJ2_CAMDATA2);

s3c2410_gpio_cfgpin(S3C2440_GPJ3, S3C2440_GPJ3_CAMDATA3);

s3c2410_gpio_cfgpin(S3C2440_GPJ4, S3C2440_GPJ4_CAMDATA4);

s3c2410_gpio_cfgpin(S3C2440_GPJ5, S3C2440_GPJ5_CAMDATA5);

s3c2410_gpio_cfgpin(S3C2440_GPJ6, S3C2440_GPJ6_CAMDATA6);

s3c2410_gpio_cfgpin(S3C2440_GPJ7, S3C2440_GPJ7_CAMDATA7);

s3c2410_gpio_cfgpin(S3C2440_GPJ8, S3C2440_GPJ8_CAMPCLK);

s3c2410_gpio_cfgpin(S3C2440_GPJ9, S3C2440_GPJ9_CAMVSYNC);

s3c2410_gpio_cfgpin(S3C2440_GPJ10, S3C2440_GPJ10_CAMHREF);

s3c2410_gpio_cfgpin(S3C2440_GPJ11, S3C2440_GPJ11_CAMCLKOUT);

s3c2410_gpio_cfgpin(S3C2440_GPJ12, S3C2440_GPJ12_CAMRESET);

申请CAMIF的寄存器区域,由于OS的系统统一管理,所以,需要确定,该寄存器区域没有被别的进程获取,所以要申请。

/* init camera's virtual memory. */

if (!request_mem_region((unsigned long)S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF, CARD_NAME))

{

ret = -EBUSY;

goto error1;

}

申请到了寄存器区域,相当于物理地址可用,然后,再将该物理地址映射到虚拟地址。

/* remap the virtual memory. */

camif_base_addr = (unsigned long)ioremap_nocache((unsigned long)S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF);

if (camif_base_addr == (unsigned long)NULL)

{

ret = -EBUSY;

goto error2;

}

获取CAMIF的时钟,使用24M

/* init camera clock. */

pdev->clk = clk_get(NULL, "camif");

if (IS_ERR(pdev->clk))

{

ret = -ENOENT;

goto error3;

}

clk_enable(pdev->clk);

camif_upll_clk = clk_get(NULL, "camif-upll");

clk_set_rate(camif_upll_clk, 24000000);

mdelay(100);

初始化CAMIF的状态

/* init camif state and its lock. */

pdev->state = CAMIF_STATE_FREE;

CAMIF DEV的状态:

/* for s3c2440camif_dev->state field. */

enum

{

CAMIF_STATE_FREE = 0, // not openned

CAMIF_STATE_READY = 1, // openned, but standby

CAMIF_STATE_PREVIEWING = 2, // in previewing

CAMIF_STATE_CODECING = 3 // in capturing

};

注册杂项设备:

/* register to videodev layer. */

if (misc_register(&misc) < 0)

{

ret = -EBUSY;

goto error4;

}

printk(KERN_ALERT"s3c2440 camif init done\n");

初始化SCCB接口,Serial Camera Control Bus,其实是I2C接口sccb_init();

硬件复位CAMIF

hw_reset_camif();

其实是软件复位,对CIGCTRL寄存器配置软件复位

/* software reset camera interface. */

static void __inline__ hw_reset_camif(void)

{

u32 cigctrl;

cigctrl = (1<<30)|(1<<29);

iowrite32(cigctrl, S3C244X_CIGCTRL);

mdelay(10);

cigctrl = (1<<29);

iowrite32(cigctrl, S3C244X_CIGCTRL);

mdelay(10);

}

检测是否存在OV9650,GPG4连的是LCD_PWR,不知道为什么?

has_ov9650 = s3c2440_ov9650_init() >= 0;

s3c2410_gpio_setpin(S3C2410_GPG4, 1);

OV9650的初始化:

int s3c2440_ov9650_init(void)

{

printk(KERN_ALERT"Loading OV9650 driver.........\n");

/* power on. */

ov9650_poweron();

mdelay(100);

/* check device. */

if (ov9650_check() == 0 && ov9650_check() == 0)

{

printk(KERN_ERR"No OV9650 found!!!\n");

return -ENODEV;

}

show_ov9650_product_id();

ov9650_init_regs();

printk("ov9650 init done!\n");

return 0;

}

OV9650上电,这里对GPG12设置为输出,这里使用的虽然是中断引脚,但似乎没

有用中断,这是一个电源控制引脚,PWDN,0:power on,1:power down

static void __inline__ ov9650_poweron(void)

{

s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);

s3c2410_gpio_setpin(S3C2410_GPG12, 0);

mdelay(20);

}

OV9650检测,读取OV9650的Manu ID

static int __inline__ ov9650_check(void)

{

u32 mid;

mid = sccb_read(OV9650_SCCB_ADDR, 0x1c)<<8;

mid |= sccb_read(OV9650_SCCB_ADDR, 0x1d);

printk("SCCB address 0x%02X, manufacture ID 0x%04X, expect 0x%04X\n", OV9650_SCCB_ADDR, mid, OV9650_MANUFACT_ID);

return (mid==OV9650_MANUFACT_ID)?1:0;

}

#define OV9650_SCCB_ADDR 0x60

#define OV9650_MANUFACT_ID 0x7FA2

#define OV9650_PRODUCT_ID 0x9650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

摄像头接口打开:

/*

* camif_open()

*/

static int camif_open(struct inode *inode, struct file *file)

{

首先判断是否存在OV9650 camera是文件开始的一个static变量。

struct s3c2440camif_dev *pdev;

struct s3c2440camif_fh *fh;

int ret;

if (!has_ov9650) {

return -ENODEV;

}

pdev = &camera;

为file handle分配内存

fh = kzalloc(sizeof(*fh),GFP_KERNEL); // alloc memory for filehandle

设置设备状态为open and standby,初始化CAMIF的配置。

pdev->state = CAMIF_STATE_READY;

init_camif_config(fh);

对CAMIF进行配置,最后更新一下配置

/* config camif when master-open camera.*/

static void init_camif_config(struct s3c2440camif_fh * fh)

{

struct s3c2440camif_dev * pdev;

pdev = fh->dev;

pdev->input = 0; // FIXME, the default input image format, see inputs[] for detail.

/* the source image size (input from external camera). */

pdev->srcHsize = 1280; // FIXME, the OV9650's horizontal output pixels.

pdev->srcVsize = 1024; // FIXME, the OV9650's verical output pixels.

/* the windowed image size. */

pdev->wndHsize = 1280;

pdev->wndVsize = 1024;

/* codec-path target(output) image size. */

pdev->coTargetHsize = pdev->wndHsize;

pdev->coTargetVsize = pdev->wndVsize;

/* preview-path target(preview) image size. */

pdev->preTargetHsize = 640;

pdev->preTargetVsize = 512;

update_camif_config(fh, CAMIF_CMD_STOP);

}

由于设备状态是CAMIF_STATE_READY所以,直接更新寄存器。

/* update camera interface with the new config. */

static void update_camif_config (struct s3c2440camif_fh * fh, u32 cmdcode)

{

struct s3c2440camif_dev * pdev;

pdev = fh->dev;

switch (pdev->state)

{

case CAMIF_STATE_READY:

update_camif_regs(fh->dev); // config the regs directly.

break;

case CAMIF_STATE_PREVIEWING:

/* camif is previewing image. */

disable_irq(IRQ_S3C2440_CAM_P); // disable cam-preview irq.

/* source image format. */

if (cmdcode & CAMIF_CMD_SFMT)

{

// ignore it, nothing to do now.

}

/* target image format. */

if (cmdcode & CAMIF_CMD_TFMT)

{

/* change target image format only. */

pdev->cmdcode |= CAMIF_CMD_TFMT;

}

不知为什么要等待VSYNC为L?然后对寄存器进行配置。

/* update camif registers, called only when camif ready, or ISR. */

static void __inline__ update_camif_regs(struct s3c2440camif_dev * pdev)

{

if (!in_irq())

{

while(1) // wait until VSYNC is 'L'

{

barrier();

if ((ioread32(S3C244X_CICOSTATUS)&(1<<28)) == 0)

break;

}

}

/* WARNING: don't change the statement sort below!!! */

update_source_fmt_regs(pdev);

update_target_wnd_regs(pdev);

update_target_fmt_regs(pdev);

update_target_zoom_regs(pdev);

}

初始化CAMIF的DMA内存。

ret = init_image_buffer(); // init image buffer.

这里为DMA分配内存,按页分配,内存管理的知识需要学习?

/* init image buffer (only when the camif is first open). */

static int __inline__ init_image_buffer(void)

{

int size1, size2;

unsigned long size;

unsigned int order;

/* size1 is the max image size of codec path. */

size1 = MAX_C_WIDTH * MAX_C_HEIGHT * 16 / 8;

/* size2 is the max image size of preview path. */

size2 = MAX_P_WIDTH * MAX_P_HEIGHT * 16 / 8;

size = (size1 > size2)?size1:size2;

order = get_order(size); //获取需要分配字节的2的阶数,内存按页分配

img_buff[0].order = order;

img_buff[0].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[0].order);

if (img_buff[0].virt_base == (unsigned long)NULL)

{

goto error0;

}

img_buff[0].phy_base = img_buff[0].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address.

申请中断,分别为Codec的中断和Preview的中断

request_irq(IRQ_S3C2440_CAM_C, on_camif_irq_c, IRQF_DISABLED, "CAM_C", pdev);

request_irq(IRQ_S3C2440_CAM_P, on_camif_irq_p, IRQF_DISABLED, "CAM_P", pdev);

使能时钟,软件复位,更新CAMIF的配置。

clk_enable(pdev->clk); // and enable camif clock.

soft_reset_camif();

file->private_data = fh;

fh->dev = pdev;

update_camif_config(fh, 0); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

摄像头接口读取函数:

static ssize_t camif_read(struct file *file, char __user *data, size_t count, loff_t *ppos)

{

int i;

struct s3c2440camif_fh * fh;

struct s3c2440camif_dev * pdev;

fh = file->private_data;

pdev = fh->dev;

if (start_capture(pdev, 0) != 0) //此处是捕获一张图片,所以会阻塞在此,直至中断发生。

{

return -ERESTARTSYS;

}

//中断已经发生,数据已经更新。

disable_irq(IRQ_S3C2440_CAM_C);

disable_irq(IRQ_S3C2440_CAM_P);

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

{

if (img_buff[i].state != CAMIF_BUFF_INV ALID) //如果数据已经更新,移动数据

{

copy_to_user(data, (void *)img_buff[i].virt_base, count);

img_buff[i].state = CAMIF_BUFF_INV ALID; //设置数据无效

}

}

enable_irq(IRQ_S3C2440_CAM_P); //重新使能中断

enable_irq(IRQ_S3C2440_CAM_C);

return count;

}

开始捕获函数,设置window offset

/* start image capture.

*

* param 'stream' means capture pictures streamly or capture only one picture.

*/

static int start_capture(struct s3c2440camif_dev * pdev, int stream)

{

int ret;

u32 ciwdofst;

u32 ciprscctrl;

u32 ciimgcpt;

ciwdofst = ioread32(S3C244X_CIWDOFST); //window offset

ciwdofst |= (1<<30) // Clear the overflow indication flag of input CODEC FIFO Y

|(1<<15) // Clear the overflow indication flag of input CODEC FIFO Cb

|(1<<14) // Clear the overflow indication flag of input CODEC FIFO Cr

|(1<<13) // Clear the overflow indication flag of input PREVIEW FIFO Cb

|(1<<12); // Clear the overflow indication flag of input PREVIEW FIFO Cr

iowrite32(ciwdofst, S3C244X_CIWDOFST);

ciprscctrl = ioread32(S3C244X_CIPRSCCTRL); //Preview main scale control开始prev

ciprscctrl |= 1<<15; // preview scaler start

iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);

pdev->state = CAMIF_STATE_PREVIEWING;

ciimgcpt = (1<<31) // camera interface global capture enable

|(1<<29); // capture enable for preview scaler.

iowrite32(ciimgcpt, S3C244X_CIIMGCPT); //Image capture enable开始捕获

//如果是捕获视频的话,会一直循环这样,只是数据到什么地方了呢?

ret = 0;

if (stream == 0)

{

pdev->cmdcode = CAMIF_CMD_STOP;

//如果是捕获图片的话,那么只会中断一次,然后STOP,在此阻塞,等待中断发生ret = wait_event_interruptible(pdev->cmdqueue, pdev->cmdcode == CAMIF_CMD_NONE);

}

return ret;

} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

摄像头接口中断服务P path函数:

/*

* ISR: service for P-path interrupt.

*/

static irqreturn_t on_camif_irq_p(int irq, void * dev)

{

u32 ciprstatus;

u32 frame;

struct s3c2440camif_dev * pdev;

ciprstatus = ioread32(S3C244X_CIPRSTATUS); 检查状态

if ((ciprstatus & (1<<21))== 0)

{

return IRQ_RETV AL(IRQ_NONE);

}

pdev = (struct s3c2440camif_dev *)dev;

/* valid img_buff[x] just DMAed. */

frame = (ciprstatus&(3<<26))>>26; 计算帧数?

frame = (frame+4-1)%4;

img_buff[frame].state = CAMIF_BUFF_RGB565;

if (pdev->cmdcode & CAMIF_CMD_STOP) 查看有没有CMD

{

stop_capture(pdev);

pdev->state = CAMIF_STATE_READY;

}

else

{

if (pdev->cmdcode & CAMIF_CMD_P2C)

{

camif_c2p(pdev);

}

if (pdev->cmdcode & CAMIF_CMD_WND)

{

update_target_wnd_regs(pdev);

}

if (pdev->cmdcode & CAMIF_CMD_TFMT)

{

update_target_fmt_regs(pdev);

}

if (pdev->cmdcode & CAMIF_CMD_ZOOM)

{

update_target_zoom_regs(pdev);

}

invalid_image_buffer();

}

pdev->cmdcode = CAMIF_CMD_NONE; 最后将CMD置为NONE,然后唤醒Read中的queue wake_up(&pdev->cmdqueue);

return IRQ_RETV AL(IRQ_HANDLED);

}

配置目标格式寄存器

/* update registers:

* PREVIEW path:

* CIPRCLRSA1 ~ CIPRCLRSA4

* CIPRTRGFMT

* CIPRCTRL

* CIPRSCCTRL

* CIPRTAREA

* CODEC path:

* CICOYSA1 ~ CICOYSA4

* CICOCBSA1 ~ CICOCBSA4

* CICOCRSA1 ~ CICOCRSA4

* CICOTRGFMT

* CICOCTRL

* CICOTAREA

*/

static void __inline__ update_target_fmt_regs(struct s3c2440camif_dev * pdev)

{

u32 ciprtrgfmt;

u32 ciprctrl;

u32 ciprscctrl;

u32 mainBurstSize, remainedBurstSize;

/* CIPRCLRSA1 ~ CIPRCLRSA4. */

iowrite32(img_buff[0].phy_base, S3C244X_CIPRCLRSA1); DMA的地址

iowrite32(img_buff[1].phy_base, S3C244X_CIPRCLRSA2);

iowrite32(img_buff[2].phy_base, S3C244X_CIPRCLRSA3);

iowrite32(img_buff[3].phy_base, S3C244X_CIPRCLRSA4);

/* CIPRTRGFMT. */

ciprtrgfmt = (pdev->preTargetHsize<<16) // horizontal pixel number of target image |(0<<14) // don't mirror or rotation.

|(pdev->preTargetVsize<<0); // vertical pixel number of target image iowrite32(ciprtrgfmt, S3C244X_CIPRTRGFMT);

/* CIPRCTRL. */

calc_burst_size(2, pdev->preTargetHsize, &mainBurstSize, &remainedBurstSize);

ciprctrl = (mainBurstSize<<19)|(remainedBurstSize<<14);

iowrite32(ciprctrl, S3C244X_CIPRCTRL);

/* CIPRSCCTRL. */

ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);

ciprscctrl &= 1<<15; // clear all other info except 'preview scaler start'.

ciprscctrl |= 0<<30; // 16-bits RGB

iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); // 16-bit RGB

/* CIPRTAREA. */

iowrite32(pdev->preTargetHsize * pdev->preTargetVsize, S3C244X_CIPRTAREA); }

Linux设备驱动程序举例

Linux设备驱动程序设计实例2007-03-03 23:09 Linux系统中,设备驱动程序是操作系统内核的重要组成部分,在与硬件设备之间 建立了标准的抽象接口。通过这个接口,用户可以像处理普通文件一样,对硬件设 备进行打开(open)、关闭(close)、读写(read/write)等操作。通过分析和设计设 备驱动程序,可以深入理解Linux系统和进行系统开发。本文通过一个简单的例子 来说明设备驱动程序的设计。 1、程序清单 //MyDev.c 2000年2月7日编写 #ifndef __KERNEL__ #define __KERNEL__//按内核模块编译 #endif #ifndef MODULE #define MODULE//设备驱动程序模块编译 #endif #define DEVICE_NAME "MyDev" #define OPENSPK 1 #define CLOSESPK 2 //必要的头文件 #include //同kernel.h,最基本的内核模块头文件 #include //同module.h,最基本的内核模块头文件 #include //这里包含了进行正确性检查的宏 #include //文件系统所必需的头文件 #include //这里包含了内核空间与用户空间进行数据交换时的函数宏 #include //I/O访问 int my_major=0; //主设备号 static int Device_Open=0; static char Message[]="This is from device driver"; char *Message_Ptr; int my_open(struct inode *inode, struct file *file) {//每当应用程序用open打开设备时,此函数被调用 printk ("\ndevice_open(%p,%p)\n", inode, file); if (Device_Open) return -EBUSY;//同时只能由一个应用程序打开 Device_Open++; MOD_INC_USE_COUNT;//设备打开期间禁止卸载 return 0; } static void my_release(struct inode *inode, struct file *file)

Linux操作系统学习心得

Linux操作系统学习心得 这学期有幸学习了《嵌入式系统设计》这门课,在胡佳文老师的教导下深入了解了有关于嵌入式系统,ARM9,Linux系统等很多方面的知识,获益良多,在学习过程中自己也遇到了很多问题,同时受到了很大的启发,现在就本学期的学习谈谈自己的学习心得体会。 Linux操作系统这个名词记得在很早以前就听过,知道这是一个开放性很大的系统,源代码是直接公布在互联网上,很多计算机高手可以根据自己的需求来修改这个程序,同时它比较不易死机,在自己的印象中一直是一种高大上的系统,但是更深入的了解确是零,对于这个学期选这门公共选修课,很大一部分原因是怀着一颗要了解一种早就想知道的东西的心选的.当然我平时也喜欢玩点电脑什么的,只是停留在用别人设计好的现成的东西。 经过一个学期linux操作系统的学习,在老师在课堂对linux系统的介绍及通过网络的了解下,知道了linux原来是一种和windows差不多的电脑操作系统,windows是图形界面的,linux类似以前的DOS,是文本界面的,如果你运行了图形界面程序X-WINDOWS后,linux也能显示图形界面,也有开始菜单、桌面、图标等。Windows有MS-DOS方式,在该方式下通过输入DOS命令来操作电脑;而linux与windows类似,也有命令方式,linux 启动后如果不执行X-WINDOWS,就会处于命令方式下,必须发命令才能操作电脑。另外linux上也有很多的应用软件,安装运行了这些软件后,你就可以在linux上编辑文档、图片,玩游戏、上网、播放多媒体文件等。 当然我们对linux的学习首先是通过对它的产生,发展,到今天仍然在不断完善开始的。它的产生和需要花钱买得windows系统形成了对比,因为 linux 的核心是免费的,自由使用的,核心源代码是开放的.任何人都可以根据自己的喜好来编辑创作适合自己的操作系统,linux是抢占式多任务多用户操作系统,Linux最大的优点在于其作为服务器的强大功能,同时支持多种应用程序及开发工具,所以linux操作系统有着广泛的应用空间。 而且在课上随着老师的讲解和自己动手查资料,慢慢的学习到了更深入的知识,知道了linux的安装:硬盘安装及光盘安装,清楚了解安装Linux应注意的有关问题。学习了linux系统的进入,关闭和重启。掌握了linux系统的硬件配置,如显卡,声卡,网卡等,并且通过对linux系统基本命令的学习,尤其是shell命令语言(亦称命令解释器),熟悉了系统的基本操作。当然在学习中发现英文学得好也是学好linux的关键。同时还了解了linux对应下的一些常用软件及这些软件的安装。因为linux在服务器中广泛的应用,于是我们进一步学习了linux下接入internet的WEB服务器的安装与配置方法。之后还了解了linux的网络安全,系统的安全,用户的安全等。 眼看这个学期Linux的课程已经告一段落了,在这段时间的学习如果要问我在这门课中学到了什么,我觉得是一种为学的方法,使我受益非浅。 首先每学一部分内容前必定有很多疑问,想要独立解开疑问,从网络上找资

一个简单的演示用的Linux字符设备驱动程序.

实现如下的功能: --字符设备驱动程序的结构及驱动程序需要实现的系统调用 --可以使用cat命令或者自编的readtest命令读出"设备"里的内容 --以8139网卡为例,演示了I/O端口和I/O内存的使用 本文中的大部分内容在Linux Device Driver这本书中都可以找到, 这本书是Linux驱动开发者的唯一圣经。 ================================================== ===== 先来看看整个驱动程序的入口,是char8139_init(这个函数 如果不指定MODULE_LICENSE("GPL", 在模块插入内核的 时候会出错,因为将非"GPL"的模块插入内核就沾污了内核的 "GPL"属性。 module_init(char8139_init; module_exit(char8139_exit; MODULE_LICENSE("GPL"; MODULE_AUTHOR("ypixunil"; MODULE_DESCRIPTION("Wierd char device driver for Realtek 8139 NIC"; 接着往下看char8139_init( static int __init char8139_init(void {

int result; PDBG("hello. init.\n"; /* register our char device */ result=register_chrdev(char8139_major, "char8139", &char8139_fops; if(result<0 { PDBG("Cannot allocate major device number!\n"; return result; } /* register_chrdev( will assign a major device number and return if it called * with "major" parameter set to 0 */ if(char8139_major == 0 char8139_major=result; /* allocate some kernel memory we need */ buffer=(unsigned char*(kmalloc(CHAR8139_BUFFER_SIZE, GFP_KERNEL; if(!buffer { PDBG("Cannot allocate memory!\n"; result= -ENOMEM;

linux学习笔记

Linux 一、Linux文件及文件夹命名规则 1)除了/之外,所有的字符都合法。因为/是系统的根目录名 2)有些字符最好不要用,如空格、制表符、退格符和@#$&-等字符。因为Linux命令以空格、-进行分开的;而#表示管理员命令行,$表示用户命令行等 3)避免使用.作为普通文件名的第一个字符。因为Linux系统以.开头的文件是隐藏文件4)Linux系统对英文字符大小写敏感 建议:不要把windows使用习惯带到Linux系统使用上 二、Linux操作命令 2.1、命令格式 命令格式:命令-选项参数 示例:ls –la /etc,参数是命令操作的对象 说明:1)当有多个选项时,可以写在一起。 2)两个特殊的目录.和..,分别代表当前目录和当前目录的父目录 2.2、命令种类及用法 Linux系统里命令按权限分为:1、只有管理员即root才能使用的命令,这些命令位置在/sbin 和/usr/sbin目录;2、管理员和所有用户都能使用的命令,这些命令的位置在/bin和/usr/bin 目录。bin是二进制文件夹binary缩写,usr是user的缩写,sbin是super binary缩写;3、Linux系统里内核处理任务文件都需要一个数字标识(inode-i节点),因为Linux只认i节点不认字符的,一个i节点可以对应多个文件 2.2.1、文件处理命令 2.2.1.1、ls命令-查看 1)命令名称:ls 2)命令英文原意:list 3)命令所在路径:/bin/ls 4)执行权限:所有用户

5)命令作用:查看目录下的文件和文件夹 6)命令语法:ls 选项[-ald] [文件或目录] 7)用法示例:#ls –ald /etc 选项说明:-a all缩写,显示所有文件,包括隐藏文件 -l long缩写,显示文件和文件夹详细信息显示 -d 查看目录属性 -i 查看文件的inode(i节点:一个数字标识) 文件和文件夹详细信息说明: 1、第一部分如:drwxr-xr-x、-rwxr-xr-x、lrwxr-xr-x这部分分成4个部分, 其各个字符说明: d 第一个字符d表示目录directory - 如果是第一个字符表示二进制文件,其它表示无权限 l 第一个字符l表示软链接文件link r 读权限read w 写权限write x 执行权限execute 第一部分:即第一个字符,表示文件类型 第二部分:第2-10个字符,表示三种用户对该文件的权限 第2-4个字符,表示所有者u-user对该文件的权限 第5-7个字符,表示所属组g-group对该文件的权限 第8-10个字符,表示其它人o-others对该文件的权限 2、第二部分如:2,表示该文件硬链接数 3、第三部分如:root,表示该文件所有者权限 4、第四部分如:root,表示该文件所属组权限 5、第五部分如:4096,表示该文件大小;以数据块block表示最小存储数 据单位,每个数据块为512字节 6、第六部分如:12-01 20:52,表示该文件创建时间或最后修改时间 7、第七部分如:bin,表示该文件的名 2.2.1.2、cd命令-切换 1)命令名称:cd 2)命令英文原意:change directory 3)命令所在路径:shell内置命令 4)执行权限:所有用户 5)命令作用:切换目录 6)命令语法:cd [目录] 7)用法示例:#cd / 切换到根目录 注:这个命令一般配合pwd命令使用

Linux 操作系统shell学习笔记 (linux系统)

Linux 操作系统shell学习笔记(linux系统) linux软件开发 No.001 文件安全与权限 1. umask 决定了新建文件的权限 2. 软链接(符号链接) ln -s source_path target_path No.002 find和xargs 1. find pathname -options [-print -exec -ok] 其中exec参数的命令格式:'command-' {} \; 注意必须包含【{} \;】 -perm 按权限来查找ex. find . -perm 755 -print -mtime 按修改时间来查找ex. find / -mtime -5 -print 更改时间5天以内 find / -mtime +5 -print 更改时间5天以前 2. xargs与-exec和-ok类似,但是限制更少,也更快 3种参数的命令:find . -name "*.c" -exec wc -l {} \; find . -name "*.c" -ok wc -l {} \; 每次执行命令前有提示 find . -name "*.c" | xargs wc -l No.003 后台执行命令 1. [crontab] [at] [&] [nohup]四种

No.004 文件名置换 1. 列出隐藏文件ex. ls .* No.005 shell输入与输出 1. echo输出时加上-n 参数不换行,ex. echo -n "aaaa" 2. tee 命令可以同时输出到屏幕和文件中ex. ls | tee file.out 3. 标准输入0 标准输出1 标准错误2 4. 将标准输出和标准错误输入到一个文件ex. command >file.out 2>&1 No.006 命令执行顺序 1. 命令1 && 命令2 命令1执行成功后才会执行命令2 2. 命令1 || 命令2 命令1执行失败后才会执行命令2 No.007 正则表达式 1. 正则表达式元字符及含义 ^ 只匹配行首 $ 只匹配行尾

一篇非常好的linux学习笔记分享(Linux入门绝佳)

作者:佚名字体:[增加减小] 来源:互联网时间:03-06 21:54:44我要评论 一篇非常好的linux学习笔记分享,对于常用命令整理的比较详细,推荐使用。 linux目录架构 / 根目录 /bin 常用的命令binary file 的目錄 /boot 存放系统启动时必须读取的档案,包括核心(kernel) 在内 /boot/grub/menu.lst GRUB设置 /boot/vmlinuz 内核 /boot/initrd 核心解壓縮所需RAM Disk /dev 系统周边设备 /etc 系统相关设定文件 /etc/DIR_COLORS 设定颜色 /etc/HOSTNAME 设定用户的节点名 /etc/NETWORKING 只有YES标明网络存在 /etc/host.conf 文件说明用户的系统如何查询节点名 /etc/hosts 设定用户自已的IP与名字的对应表 /etc/hosts.allow 设置允许使用inetd的机器使用 /etc/hosts.deny 设置不允许使用inetd的机器使用 /etc/hosts.equiv 设置远端机不用密码 /etc/inetd.conf 设定系统网络守护进程inetd的配置 /etc/gateways 设定路由器 /etc/protocols 设定系统支持的协议 /etc/named.boot 设定本机为名字服务器的配置文件 /etc/sysconfig/network-scripts/ifcfg-eth0 设置IP /etc/resolv.conf 设置DNS /etc/X11 X Window的配置文件,xorg.conf 或XF86Config 這兩個X Server 的設定檔/etc/fstab 记录开机要mount的文件系统 /etc/inittab 设定系统启动时init进程将把系统设置成什么样的runlevel /etc/issue 记录用户登录前显示的信息 /etc/group 设定用户的组名与相关信息 /etc/passwd 帐号信息 /etc/shadow 密码信息 /etc/sudoers 可以sudo命令的配置文件 /etc/securetty 设定哪些终端可以让root登录 /etc/login.defs 所有用户登录时的缺省配置

linux驱动程序的编写

linux驱动程序的编写 一、实验目的 1.掌握linux驱动程序的编写方法 2.掌握驱动程序动态模块的调试方法 3.掌握驱动程序填加到内核的方法 二、实验内容 1. 学习linux驱动程序的编写流程 2. 学习驱动程序动态模块的调试方法 3. 学习驱动程序填加到内核的流程 三、实验设备 PentiumII以上的PC机,LINUX操作系统,EL-ARM860实验箱 四、linux的驱动程序的编写 嵌入式应用对成本和实时性比较敏感,而对linux的应用主要体现在对硬件的驱动程序的编写和上层应用程序的开发上。 嵌入式linux驱动程序的基本结构和标准Linux的结构基本一致,也支持模块化模式,所以,大部分驱动程序编成模块化形式,而且,要求可以在不同的体系结构上安装。linux是可以支持模块化模式的,但由于嵌入式应用是针对具体的应用,所以,一般不采用该模式,而是把驱动程序直接编译进内核之中。但是这种模式是调试驱动模块的极佳方法。 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。同时,设备驱动程序是内核的一部分,它完成以下的功能:对设备初始化和释放;把数据从内核传送到硬件和从硬件读取数据;读取应用程序传送给设备文件的数据和回送应用程序请求的数据;检测和处理设备出现的错误。在linux操作系统下有字符设备和块设备,网络设备三类主要的设备文件类型。 字符设备和块设备的主要区别是:在对字符设备发出读写请求时,实际的硬件I/O一般就紧接着发生了;块设备利用一块系统内存作为缓冲区,当用户进程对设备请求满足用户要求时,就返回请求的数据。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。 1 字符设备驱动结构 Linux字符设备驱动的关键数据结构是cdev和file_operations结构体。

一个简单字符设备驱动实例

如何编写Linux设备驱动程序 Linux是Unix操作系统的一种变种,在Linux下编写驱动程序的原理和思想完全类似于其他的Unix系统,但它dos或window环境下的驱动程序有很大的区别。在Linux环境下设计驱动程序,思想简洁,操作方便,功能也很强大,但是支持函数少,只能依赖kernel中的函数,有些常用的操作要自己来编写,而且调试也不方便。本文是在编写一块多媒体卡编制的驱动程序后的总结,获得了一些经验,愿与Linux fans共享,有不当之处,请予指正。 以下的一些文字主要来源于khg,johnsonm的Write linux device driver,Brennan's Guide to Inline Assembly,The Linux A-Z,还有清华BBS上的有关device driver的一些资料. 这些资料有的已经过时,有的还有一些错误,我依据自己的试验结果进行了修正. 一、Linux device driver 的概念 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它完成以下的功能: 1)对设备初始化和释放; 2)把数据从内核传送到硬件和从硬件读取数据; 3)读取应用程序传送给设备文件的数据和回送应用程序请求的数据; 4)检测和处理设备出现的错误。 在Linux操作系统下有两类主要的设备文件类型,一种是字符设备,另一种是块设备。字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待. 已经提到,用户进程是通过设备文件来与实际的硬件打交道。每个设备文件都都有其文件属性(c/b),表示是字符设备还是块设备。另外每个文件都有两个设备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分他们。设备文件的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问到驱动程序. 最后必须提到的是,在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度。也就是说,系统必须在你的驱动程序的子函数返回后才能进行其他的工作。如果你的驱动程序陷入死循环,不幸的是你只有重新启动机器了,然后就是漫长的fsck。 二、实例剖析 我们来写一个最简单的字符设备驱动程序。虽然它什么也不做,但是通过它可以了解Linux的设备驱动程序的工作原理.把下面的C代码输入机器,你就会获得一个真正的设备

Linux学习笔记之第二章文本编辑器

修改主机名: 修改静态ip: vi /etc/hostname 1vi /etc/sysconfig/network-scripts/ifcfg-ens32 BOOTPROTO=static 静态IPADDR=地址NETMASK=子网掩码:255.255.255.0GATEWAY= 网关DNS1=域名服务器1 2 3 4 5 6 7

–color=auto:将找到的关键字部分加上颜色显示学习目标 1、vi/vim文本编辑器 2、用户管理 3、文件基本属性 4、常用命令 学习内容 1、vi/vim文本编辑器 常用操作: dd:删除光标所在的整行 ndd:删除光标之后的的n行 yy:复制整行 nyy:复制n行 p: 光标位置向下粘贴 P:光标占位置向上粘贴 u:撤销 ctrl+r:重做上一个动作(还原撤销的操作) :set nu 显示行号 :set nonu 取消行号 查找替换: /word :查找,n:向下查找,N:向上查找

重要文件: 保存用户信息的文件:/etc/passwd 保存密码的文件:/etc/shadow 保存用户组的文件:/etc/group 保存用户组密码的文件:/etc/gshadow 用户配置文件:/etc/default/useradd 配置文件分析: /etc/passwd 用户名:密码:用户ID:用户组ID:用户描述:用户的主目录:shell 命令root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync 1 2 3 4 5 6 7 登录名:加密口令:最后一次修改时间:最小时间间隔:最大时间间隔:警告时间:不活动时间:失效时间:标 志 1

linux简单的gpio驱动实例

今天完成了嵌入式linux的第一个驱动的编写和测试,虽然是个简单的程序,但是麻雀虽小,五脏俱全,希望可以给刚开始接触驱动编写的人一些提示,共同进步。 源代码: 分析如下: 下面是我的驱动程序: #include //配置头文件 #include /*内核头文件,作为系统核心的一部分,设备驱动程序在申请和释放内存时,不是调用malloc和free,而是调用kmalloc和 kfree*/ #include //调度,进程睡眠,唤醒,中断申请,中断释放 #include //时钟头文件 #include //用户定义模块初始函数名需引用的头文件 #include //模块加载的头文件 #include #include //这个是2440的寄存器头文件,asm/srch只是个链接 //实际根据自己的情况查找,一般 是../../linux2.*.*/include/asm/arch-s3c2440里编译器 //自己会查询链接,以前不知道,找了半天 // GPIO_LED DEVICE MAJOR #define GPIO_LED_MAJOR 97 //定义主设备号 //define LED STATUS 我的板子 LED在GPB0 与GPB1 处大家根据自己情况改 #define LED_ON 0 //定义LED灯的状态开 #define LED_OFF 1 // // ------------------- READ ------------------------ 这个前面要加static 否则警告 static ssize_t GPIO_LED_read (struct file * file ,char * buf, size_t count, loff_t * f_ops) {

linux基本命令学习笔记

一、常用系统工作命令 1.echo 用于在终端输出字符串或者变量提取后的值 2.date 用于显示系统的时间或者日期 date "+%Y-%m-%d %H:%M:%S" 指定格式查看当前系统时间 date -s "20180901 8:53:00" 设置系统当前时间 date "+%j" 3.reboot 4.poweroff 5.wget(暂时了解即可) 6.ps 查看系统中的进程状态ps aux -a 显示所有进程 -u 用户以及其他详细信息 -x 显示没有控制终端的进程 //linux系统中有长短格式之分长长不能合并,长短不能合并,短短可以合并; 合并后保留一个- 号、ps命令允许参数不加减号(-),因此直接写成ps aux ·五种常见进程状态: R (运行)S(中断)D(不可中断)Z(僵死)T(停止) 7.top 动态的监视进程活动与系统负载等信息“Linux中的强化班的Windows任务管理器” 8.pidof 用于查询某个指定服务进程的PID值,格式为“pidof[参数][服务名称]” 9.kill 终止某个指定的PID的服务进程。 10.killall 用于终止某个指定名称的服务所对应的全部进程、killall[参数][进程名称] 如果我们在系统终端中执行一个命令后想立即停止它,可同时按下Ctrl+C组合键,这样将立即终止该命令的进程。或者有些命令在执行时不断的在屏幕上输出信息,影响后续命令的输入,则可以在执行命令时在末尾加上一个&符号,这样命令将进入系统后台来执行。 二、系统状态检测命令 1.ifconfig 查看本机当前网卡配置与网络状态的信息 主要查看网卡名称inet参数后面的ip地址ether参数后面的网卡物理地址(MAC 地址)以及RX TX的接受数据包和发送数据包的个数及累计流量 2.uname 用于查看系统内核与系统版本等信息 uname -a 若要查看当前系统版本的详细信息,则需要查看redhat-release文件 cat /etc/redhat-release 3.uptime 用于查系统的负载信息 显示当前系统时间系统已运行时间启用终端数量以及平均负载值 平均负载值:系统在最近一分钟五分钟十五分钟内的压力情况 4.free用于显示当前系统的内存使用量信息free -h 5.who 用于查看当前登入主机的用户终端信息 https://www.wendangku.net/doc/597067559.html,st 用于查看所有系统的登录记录。(日志文件形式保存在系统中,因此黑客很容易对其进行篡改,不要用该命令的输出信息判断系统有无被恶意入侵) 7.history 显示历史执行过的命令(1000条)如果不够,可自定义/etc/profile文件中的HISTSIZE变量值。使用-c参数会清除所有命令历史记录。还可以使用“!编码数字”的方式重复执行某一次命令。

Linux操作系统学习心得

Linux操作系统学习心得 Linux操作系统这个名词记得在很早以前就听过,但具体是什么样的系统却真的不知道,甚至都不知道它是手机系统还是电脑系统,知道的只是它好像比较不易死机,。对于这个学期选这门公共选修课,很大一部分原因是怀着一颗要了解一种早就想知道的东西的心选的.当然我平时也喜欢玩点电脑什么的,只是停留在用别人设计好的现成的东西。 经过一个学期linux操作系统的学习,在老师在课堂对linux系统的介绍及通过网络的了解下,知道了linux原来是一种和windows差不多的电脑操作系统,windows是图形界面的,linux类似以前的DOS,是文本界面的,如果你运行了图形界面程序X-WINDOWS后,linux 也能显示图形界面,也有开始菜单、桌面、图标等。Windows有MS-DOS 方式,在该方式下通过输入DOS命令来操作电脑;而linux与windows 类似,也有命令方式,linux 启动后如果不执行X-WINDOWS,就会处于命令方式下,必须发命令才能操作电脑。另外linux上也有很多的应用软件,安装运行了这些软件后,你就可以在linux上编辑文档、图片,玩游戏、上网、播放多媒体文件等。 当然我们对linux的学习首先是通过对它的产生,发展,到今天仍然在不断完善开始的。它的产生和需要花钱买得windows系统形成了对比,因为linux的核心是免费的,自由使用的,核心源代码是开放的.任何人都可以根据自己的喜好来编辑创作适合自己的操作系统,linux是抢占式多任务多用户操作系统,Linux最大的优点在于其作为服务器的强大功能,同时支持多种应用程序及开发工具,所以linux 操作系统有着广泛的应用空间。 而且在课上随着老师的讲解和自己动手查资料,慢慢的学习到了更深入的知识,知道了linux的安装:硬盘安装及光盘安装,清楚了解安装Linux应注意的有关问题。学习了linux系统的进入,关闭和重启。掌握了linux系统的硬件配置,如显卡,声卡,网卡等,并且通过对linux 系统基本命令的学习,尤其是shell命令语言(亦称命令解释器),熟悉了系统的基本操作。当然在学习中发现英文学得好也是学好linux 的关键。同时还了解了linux对应下的一些常用软件及这些软件的安装。因为linux在服务器中广泛的应用,于是我们进一步学习了linux 下接入internet的WEB服务器的安装与配置方法。之后还了解了linux 的网络安全,系统的安全,用户的安全等。 眼看这个学期Linux的课程已经告一段落了,在这段时间的学习如

Linux驱动框架及驱动加载

本讲主要概述Linux设备驱动框架、驱动程序的配置文件及常用的加载驱动程序的方法;并且介绍Red Hat Linux安装程序是如何加载驱动的,通过了解这个过程,我们可以自己将驱动程序放到引导盘中;安装完系统后,使用kudzu自动配置硬件程序。 Linux设备驱动概述 1. 内核和驱动模块 操作系统是通过各种驱动程序来驾驭硬件设备,它为用户屏蔽了各种各样的设备,驱动硬件是操作系统最基本的功能,并且提供统一的操作方式。正如我们查看屏幕上的文档时,不用去管到底使用nVIDIA芯片,还是ATI芯片的显示卡,只需知道输入命令后,需要的文字就显示在屏幕上。硬件驱动程序是操作系统最基本的组成部分,在Linux内核源程序中也占有较高的比例。 Linux内核中采用可加载的模块化设计(LKMs ,Loadable Kernel Modules),一般情况下编译的Linux内核是支持可插入式模块的,也就是将最基本的核心代码编译在内核中,其它的代码可以选择是在内核中,或者编译为内核的模块文件。 如果需要某种功能,比如需要访问一个NTFS分区,就加载相应的NTFS模块。这种设计可以使内核文件不至于太大,但是又可以支持很多的功能,必要时动态地加载。这是一种跟微内核设计不太一样,但却是切实可行的内核设计方案。 我们常见的驱动程序就是作为内核模块动态加载的,比如声卡驱动和网卡驱动等,而Linux最基础的驱动,如CPU、PCI总线、TCP/IP协议、APM(高级电源管理)、VFS等驱动程序则编译在内核文件中。有时也把内核模块就叫做驱动程序,只不过驱动的内容不一定是硬件罢了,比如ext3文件系统的驱动。 理解这一点很重要。因此,加载驱动时就是加载内核模块。下面来看一下有关模块的命令,在加载驱动程序要用到它们:lsmod、modprob、insmod、rmmod、modinfo。 lsmod

linux简单gpio驱动实例

Led test 今天完成了嵌入式linux的第一个驱动的编写和测试,虽然是个简单的程序, 但是麻雀虽小,五脏俱全,希望可以给刚开始接触驱动编写的人一些提示,共 同进步。 源代码: 分析如下: 下面是我的驱动程序: #include //配置头文件 #include /*内核头文件,作为系统核心的一部分,设备驱动程序在申请和释放内存时,不是调用malloc和free,而是调用kmalloc和 kfree*/ #include //调度,进程睡眠,唤醒,中断申请,中断释放 #include //时钟头文件 #include //用户定义模块初始函数名需引用的头文件 #include //模块加载的头文件 #include #include //这个是2440的寄存器头文件,asm/srch只是个链接 //实际根据自己的情况查找,一般 是../../linux2.*.*/include/asm/arch-s3c2440里编译器 //自己会查询链接,以前不知道,找了半天 // GPIO_LED DEVICE MAJOR #define GPIO_LED_MAJOR 97 //定义主设备号 //define LED STATUS 我的板子 LED在GPB0 与GPB1 处大家根据自己情况改 #define LED_ON 0 //定义LED灯的状态开 #define LED_OFF 1 // // ------------------- READ ------------------------ 这个前面要加static 否则警告 static ssize_t GPIO_LED_read (struct file * file ,char * buf, size_t count, loff_t * f_ops) {

基于Linux系统的HHARM9电机驱动程序设计

收稿日期:2005-09-22 作者简介:朱华生(1965-),男,江西临川人,副教授. 文章编号:1006-4869(2005)04-0051-03 基于Linux 系统的HHARM9电机驱动程序设计 朱华生,胡凯利 (南昌工程学院计算机科学与技术系,江西南昌330099) 摘 要:对嵌入式Linux 操作系统驱动程序的组成进行分析,讨论了驱动程序的基本框架,以HHARM9电机控制为实例,详细论述了电机驱动程序的实现过程. 关键词:嵌入式;Linux;驱动程序 中图分类号:TP316 文献标识码:A Linux System -Based Design of HHARM 9Electromotor Driver ZHU Hua -sheng,HU Ka-i li (Department of Computer and Science,Nanchang Institute of Technology,Nanchang 330099,China) Abstract:The paper analyses the composition of driver in embedded linux system,disuses its basic frame of driver,and illustrales the process of driver design of HHARM9electromotor in detail. Key words:Embedded;Linux; driver 嵌入式Linux 操作系统因具有免费、开放源代码、强大的网络功能等 特点,在嵌入式产品中得到越来越广泛的应用.基于Linux 操作系统的嵌入 式产品结构[1]如图1所示.本文主要探讨嵌入式系统驱动程序的设计. 1 嵌入式Linux 操作系统驱动程序简介 1)驱动程序和应用程序的区别 驱动程序的设计和应用程序的设计有很大的区别[2].首先,驱动程序 的设计要对硬件的结构、信号的工作流程十分清楚,而在应用程序的设计 中,一般不需要了解这些.其次,应用程序一般有一个main 函数,从头到尾 执行一个任务;驱动程序却不同,它没有main 函数,通过使用宏module _init(初始化函数名),将初始化函数加入内核全局初始化函数列表中,在内核初始化时执行驱动的初始化函数,从而完成驱动的初始化和注册,之后驱动便停止等待被应用软件调用.应用程序可以和GLIB C 库连接,因此可以包含标准的头文件,比如等;在驱动程序中,不能使用标准C 库,因此不能调用所有的C 库函数,比如输出打印函数只能使用内核的printk 函数,包含的头文件只能是内核的头文件,比如. 2)Linux 系统设备文件 为了方便应用程序的开发,在Linux 操作系统中,使用了设备文件这一概念来管理硬件设备.Linux 操 第24卷 第4期 2005年12月南昌工程学院学报Journal of Nanchang Institute of Technology Vol.24No.4Dec.2005

linux 驱动程序开发

1 什么是驱动 a)裸板驱动 b)有系统驱动linux 将驱动封装了一套框架(每个驱动) c)大量和硬件无关的代码已写好只需要编程实现和硬件相关的代码 d)难点:框架的理解代码的理解 e)需要三方面的知识: i.硬件相关的知识 1.电路原理图 2.芯片的数据手册 3.总线协议rs232 i2c等 ii.内核的知识 1.内核驱动属于内核的一部分,它运行在内核态需要对内核知识有了解 2.内存管理 3.解决竞争状态(如上锁) 4.。。。 iii.驱动框架的知识 1.内核中已经实现了大量硬件驱动完成了驱动的框架编程只需要根据硬 件进行添加 2 搭建linux驱动开发工具 a)安装交叉编译环境 i.arm-linux-gcc uboot PATH b)移植uboot c)移植内核 d)制作根文件系统然后通过nfs方式让开发板可以加载 3 内核驱动开发的基本知识 a)如何学驱动编程? i.最好的老师就是内核源码(没有man 功能) 1.要是用某个函数就去查看某个函数的定义注释 2.查看内核中其他模块儿时如何使用该函数的 3.专业书籍: a)内核开发:linux内核的设计与实现机械工程出版社 b)驱动开发:圣经级别的-LDD3:LINUX DEVICE c)操作性别叫强的:精通linux设备驱动程序开发

关于linux内核: 1)linux内核中所使用的函数都是自身实现的它肯定不会调用c库中的函数 2)linux中代码绝大多数代码时gun c语言完成的不是标准c语言可以理解为标c的扩展版和少部分汇编 需要注意的问题: 1)内核态不能做浮点数运算 2)用户空间的每个进程都有独立的0-3G的虚拟空间 多个进程共享同一个内核 内核使用的地址空间为3G-4G 3)每个线程有独立的栈空间 4 写一个最简单的内核模块儿(因为驱动时内核的一个模块套路都一样) a)几个宏 i.__FUNCTION__:展开为所在函数的名称 ii.__LINE__:展开为printk所在的行号 iii.__DATE__:展开为编译程序的日期 b)通用头文件 i.#include ii.#include c)没有main函数 然后写一个makefile 其中:obj -m +=helloworld.o -m表示生成模块儿 make -C 内核路径编译对象路径modules(固定表示模块儿) 例子:make -C /home/changjian/dirver/kernel M=$(PWD) modules 报错:如taints kernel(污染内核)因为写的驱动没有声明license 因为linux为开源所以写的驱动也必须声明为开源可以在程序里加入:MODULE_LICENSE(“GPL”);声明为开源 模块儿驱动开发 1、模块儿参数 a)内核中安装模块时也可以传递参数 i.insmod xx.ko var=123 b)模块参数的使用方法 i.首先在模块中定义全局变量 ii.然后使用module_param 或者module_param_array来修饰该变量 这样一个普通的全局变量就变成可以安装模块时传递参数的模块参数 module_param(name,type,perm) name:变量名称 type: name的类型(不包括数组) perm:权限类型rwxr-x 等类型内核做了相关的宏定义形如efine S_IRWXG 表示r w x g(同组) module_param_array(name,type,nump,perm)将某个数组声明为模块 参数

linux系统学习笔记

==============================智能娱乐系统=================== 硬件:中控:UI,音视频数据处理能力 操作:显卡,声卡、LED、游戏机、触控屏 ARM :cortex - A 软件:开发环境:vmware + linux(ubuntu) 程序开发:linux C 程序移植:交叉开发 效果:自动处理程序 一、Linux 命令 linux : 图形简陋---> 追求效率高 移植性强,开源性 linux :命令行形式进行交互 ls: 查看全部文件名/ --->根目录 pwd: 打印当前的路径/home/gec 等于~ ---> 家目录 cd : 直接回到/home/gec cd / : 回到根目录/ cd ..: 回到上一级的目录 ls -l 类型权限链接数创建者工作组大小日期目录名d rwxrwxr-x 2 gec gec 4096 Jul 2 2013 Desktop d:目录(第一个字母:-:普通文件d:目录) rwxrwxr-x:文件的权限r:读权限w:写权限x:执行权限 用户权限:rwx(创建者的权限)rwx(同组人)r-x(其他人) clear: 清除屏幕信息 touch 创建文件 touch xxxx ----> 因为身份是gec,所以必须在/home/gec中创建 rm 删除文件/目录 rm xxxx(文件名) ----> 因为身份是gec,所以必须在/home/gec中删除rm xxxx(目录名) -rf

gedit 编辑文件 gedit xxxx cat 查看文件内容 cat xxxx mkdir 创建目录 mkdir xxxx ----> 因为身份是gec,所以必须在/home/gec中创建 cp 拷贝命令 cp 文件名目录名---> cp abc.c 123/ chmod 修改文件的权限 -rw-rw-r-- 1 gec gec 20 Apr 14 19:43 abc.c 421421421 6 6 4 希望三个人都是可读可写可执行7 7 7 chmod 777 xxxx chmod 777 abc.c -rwxrwxrwx 1 gec gec 20 Apr 14 19:43 abc.c 二、linux与windows间的共享目录 1,在windows系统中的D:\创建一个名字为share的目录 2, "虚拟机" --- "设置" ---- "选项" --- "共享文件夹" --- "总是启用" ---"确定" 3,在linux系统输入以下命令来进入共享目录 cd /mnt/hgfs/share/ 4,在linux与windows分别创建目录和文件,观察两个系统的变化 =====================开发板的使用========================= 一、核心板

相关文档