- 论坛徽章:
- 0
|
驱动程序设计:
- linux操作系统的驱动与bootloader的驱动区别:
要考虑与应用层的接口;
考虑多用户;
考虑其他协议;
设备驱动的作用:读数据,写数据;
初始化设备,读写设备; 将设备的数据分配给应用; 将应用的数据分配给设备;
操作系统中驱动和设备的关系是一一对应的;
应用和驱动的关系是一对多的;
内核的主要功能:进程管理, 内存管理, 文件系统, 设备控制, 网络;
linux驱动的分类:字符设备, 块设备, 网络设备;
大部分情况:主编号标识相应的驱动程序(现代linux允许多个驱动程序共享主编号), 次设备号标识哪个设备;
设备文件的cp:$ sudo cp -a /dev/mouse /tmp/ (此时是fopen打开设备文件)
$ sudo cp /dev/mouse /tmp/ (此时是open打开设备)
linux设备驱动信息的查看:
/proc/devices 查看系统支持的字符设备和块设备驱动;
/proc/pci 查看系统的PCI设备;
/proc/ioports 查看设备的IO端口;
/proc/interrupts 查看正在使用的中断号,中断次数;
/proc/net/dev 查看网络硬件设备,包括被down的网卡;
/proc/kallsyms 查看模块符号;
/proc/jitimer 查看定时器;
dmesg 查看系统的启动信息,可以看到系统支持的一些驱动的打印信息;
lspci
lsusb -v
uname -a
ifconfig -a 查看所有网卡
模块不全是驱动,但大多数模块都是驱动;
那些函数可以在模块中使用,关于kernel的API,可以查看http://kernelbook.sf.net
模块的重新编译:
在/usr/src/linux下解压linux源码包;
拷贝配置文件:cp /boot/config-2.6.20-16.generic /usr/src/linux/.config;
重新编译内核:sudo make
在模块的工程目录下编译模块:make
模块的参数传递:
module_param(name, type, perm);
static int count;
module_param(count,int,0);
#insmod driver.ko count=10
#lsmod
#rmmod driver
模块的交叉编译(arm开发板):
重新编译2.6.17.14内核,把zImage传给开发板;
将module工程目录拷贝到rootfs/usr/module下;
将module里的Makefile的源码路径变成2.6.17.14内核所在路径;
重新编译sudo make;
应用层--->TELNET,FTP,EMAIL
运输层--->TCP,UDP
网络层--->IP,ICMP,IGMP
链路层--->设备驱动程序及接口卡
USB设备驱动:
一些重要网站:
linux驱动的相关知识:http://www.xml.com/ldd/chapter/book下载Linux Device Drivers,2nd Edition
USB的相关资料:http://www.bode.cs.tum.edu/Par/arch/usb/usbdoc
http://www.usbman.com/developer.htm
http://www.usb.org
usb1.1规范: http://www.usb.org/developer/docs/usbspec.zip
ohci协议: ftp://ftp.compaq.com/pub/supportinformation/papers/hcir1_0a.pdf
uhci协议: http://developer.inter.com/technology/usb/UHCI11D.pdf
lsusb -v 查看USB设备信息;
Vendor:Product =1241:1111 这是USB设备的ID号需要向USB.ORG申请获得;
NumConfigurations = 1 表明配置描述符有1个;
bEndpointAddress = 81(in) 意思是1000 0001,最高位1是读, 后面1是端点号;
bmAttributes = 03(interrupt) 表明是中断类型的传送;因此有bInterval = 08(8ms) 表明间隔时间8ms;
工作过程:
USB主机控制器通过DMA方式访问所有设备;
对设备的读写是通过设备的端点来实现的;
USB主机通过协议链表来轮询这些端点,每个端点想要正常工作就要填充好端点格式,并放到协议链表中;
控制,实时,中断,大量传输需要不同的方式来填充协议链表;
当硬件读写完成通过中断方式来告诉CPU,并由CPU来处理剩下的工作;
字符设备C 块设备B 网络设备(无设备文件)
设备文件有文件节点, 但没有真正的内容;
主设备号标识与设备相连的驱动, 次设备号用来决定引用那个设备(一般如此, 非绝对);
设备号的内核类型dev_t
MAJOR( dev_t dev); MINOR( dev_t dev);
MKDEV( int major, int minor);
sudo cp -a /dev/input/mice /tmp/ #fopen 拷贝文件
sudo cp /dev/input/mice /tmp/ #open 打开设备
cat /proc/devices pci ioports interrupts
lspci //lsusb -v //cpuinfo partitions //dmesg 可查看模块输出信息
kallsyms 模块加载位置???
ln -s sda/c/ cc 建符号连接
sudo aptitude install linux-source-2.6.20
模块的写法 头文件 参数的使用 延时参数的使用 用户空间与kernel空间的数据互传;
copy_to_user/copy_from_user put_user/get_user
第一个linuxkernel模块实验:
uname -a //查看当前版本
查看/user/src/ 下是否有相应的linux source, 若无, 下载安装linux-source-2.6.20
sudo cp /boot/config-2.6.20-15.generic /usr/src/linux-2.6.20/.config
sudo make
在module的编写目录下, make
再使用insmod rmmod lsmod
dmesg查看模块进出信息;
com2设置:
ucon1L(v) B(x)???发 URXH1->L(v) B(x)收;
对物理地址的读写, 有两种方法:
1. #define UCON1 (*((volatile unsigned *)ioremap(0x500c4004, 4)))
2. include
#define iobase S3C24XX_VA_UART1
#define UCON1 (iobase + 0x04)
__raw_writel( 5, UCON1);
state = __raw_readb( UTRSTAT1);
\n换行\r回车 ~/.trash回收站 function(void) void定义时不可少;
需包含一些
实验主要流程:
将linux2.6.17.14代码解压到~/.目录下, 重新make menuconfig设置arm, 增加module support;
重新编译后, 下载内核zimage到2410板子上,
在driver编辑目录, 将makefile的src路径变为~/.linux2.6.17.14;
make, 获得driver. ko文件, 将他拷贝到rootfs/usr/driver/下
开发板用NFS方式启动, 在minicom中, 运行insmod driver.ko ,lsmod ,rmmod driver 观察结果;
SCULL设备驱动:
在编写设备驱动时遇到了以下问题:
1. 收发相同->buf[]指向了一个固定的字符串, 需要收发分开数组;
2. 发可以, 收不到->在驱动中收发用不同数组, 写可以动态申请, 收用数组是成功的???
3. 收发用数组指针如*buf++, 结果已经被移动, 用buf[tmp++]即可;
4. 在count经count--后, 却用在copy_to_user(buf, kbuf, cout)中, count已经为0了;
5. recieve信息在终端显示被char release打断, 两种处理方式可行: close之前sleep(1); release中不打印信息;
6. tmp++后, return tmp正好是所读个数, 而不是tmp+1;
sudo -s /su username
字符设备驱动, GPIO驱动:
一些概念:
dev_t为32位设备号(12+20); scull_dev结构, cdev结构
老注册方法: register_chrdev(major, &name, &fops)
unregister_chrdev(major, &name)
新注册方法: regist_chrdev_region(dev_t, count, &name);
alloc_chrdev_region(&dev, firstminor, count, &name);
major = MAJOR(dev);
cdev_init(&cdev, &fops); cdev. owner=THIS_MODULE; cdev.ops=&fops;
cdev_add(&cdev, devno, 1); cdev_del(&cdev);
unregister_chrdev_region( first, count);
关于中断:
处理器管理设备的方式, 轮询, 中断+DMA;
S3C2410支持56个中断设备, 32个中断号; SRCPND, INTPND, INTMSK 写1清0;
request_irq(irq, &handler, flags, &dev_name, &dev_id); free_irq(irq, &dev_id);
GPIO实验:
注意这些目录: asm/arch-s3c2410/regs-irq.h asm/arc-s3c2410/regs-serial.h
寄存器名称: S3C2410_EINTPEND
寄存器读写函数: __raw_writel() __raw_writeb() __raw_readl() __raw_readb()
寄存器SRCPND, INTPND, EINTPENT均写1清0;
irq_return_t 是中断服务函数的返回类型;
static struct semaphore key_sem;
up ( &key_sem); down_interruptible ( &key_sem);
open时开中断, release时关中断, rmmod时free(irq);
set_irq_type 设置中断类型;
. bashrc: +PS1='$' 可改变shell提示符的显示内容;
推荐书籍: linux内核设计与实现==陈莉君, linux驱动 倪继利
网卡驱动:
网卡: 实模式, 286, 1M;/保护模式, 386, 4G
BootRom: 启动novell网, IPX协议, 内存上虚拟一个盘;
MAC协议层+PHY&传输层,物理层
MAC向IEEE申请6个16进制, 后6个16进制公司自配置; 00.xx.xx. yy.yy.yy
DEVICE ID标识厂家, 型号; 保存在设备列表中, 靠PCI, USB等协议维护;
网线, 4线, 8线有一组备用;
LCD, TVout, 若各自用单独振源, 将导致冲突;
网卡的调试方法: 硬件(电源, 晶振. . .); 软件(. . .);
将arm开发板的网卡去除后, 通过串口传程序的方法:
1. 启动pc端minicom, 启动开发板
2. 进入linux, cd /tmp
3. rx文件名; C + A, S, 选择xmodem;
4. 选文件(双空格->进目录; 空格+回车);
PC端若不工作, 安装Lrzsz.
定义类型的几种情形: typedef, struct, #define等; 查找方法: grep str key$, key{, key空{ 等方法;
S3C2410_IRQREG(x) ->C(x) + S3C24XX_VA_IRQ)
Soket系统调用来操作网络设备, 而不是open一个设备文件;
看网卡硬件的方法, 确定有几个网卡; cat /proc/net/dev 或ifconfig -a
看本机ip的一个方法, ping 一个无法联通的ip; (在没有ifconfig);
ifconfig up-->open ifconfig down-->close;
register_netdev时会初始化net_device, 并调用init函数;
net_device的主要成员: init, open(request_irq), stop(free_irq), hard_start_xmit, net_stats;
收发数据后, netif_rx把接收的数据交给协议层, netif-start/stop/wake-queue
#define SMDK2410_ETH_IRQ IRQEINT8
SMDK2410存在于四个目录: include / asm ( arm-arm)/arch (arch-s3c2410);
双索引寄存器的操作, 可扩展存储空间;
lxr & source insight 两种方便用于源代码查看的工具;
网卡实验:
两个抓包工具: tcpdump -i eth1 // wire shark
主要步骤:
1. 启动无网络的linux;
2. driver8900.ko, server, client下载到板子;
3. mknod /dev/mynet c 242 0
4. insmod driver8900.ko
5. . /server or . /client
硬件部分1015:
AGND-----L----DGND
存储模式, 带缓存 IO模式, 不带缓存;
Nandflash D[7: 0 ] 数据/命令/地址复用
RAM用了6个管, SDRAM用了一个管子和一个电容;
candence兼并了orcad, 工具好用;
网卡实验:
1. write(pp_txtmd), write( pp_txlength) read(pp_busst); 若顺序反, 无法写成功;
2. 收到的ping包有64字节, 最后4字节有可能是CRC校验码;
3. 可以将buf={ 0x11, 0x12 . . .}放入头文件, 程序引用, 作为数据发送;
4. open若用RDONLY会无法写成功;
可查看cat /proc/ioports/ 观察IO空间;
EINT8->0XF0000000+36
USB1.1, USB2.0/主, 从, OTG设备(5芯)
USB缺点: 不稳定, 线"ello";
if(defined(x))可以为变量; ifdef x 只能是宏;
2.0/3.0输出结果不同于2/3, 前者是float数据;
dpkg -L nfs-kernel-server 显示安装目录
通常服务器配置问题可以通过拷贝正确的配置文件解决;
编程中用些宏定义, 条件编译, 注释说明等;
驱动的一些例程:
#driver makefile
ifneq ($(KERNELRELEASE),)
# kbuild part of makefile
obj-m :=driver.o
else
KERNELSRC:=/home/username/linux-2.6.17.14
modules:
make -C $(KERNELSRC) SUBDIRS=$(PWD) $@
clean:
具体源码请看原出处
http://blog.chinaunix.net/u1/53151/showart_423232.html
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/97214/showart_2033168.html |
|