linux 设备输入子系统---源代码示例。自动捕获键盘鼠标等外设消息
Linux信号捕捉、任务计划、系统裁剪、日志系统syslog、系统裁剪之为系统添加ssh服务
Linux信号捕捉、任务计划、系统裁剪、⽇志系统syslog、系统裁剪之为系统添加ssh服务cross compile:交叉编译x86, 32bit,ARM交叉编译:如何实现部分编译:1、只编译某⼦⽬录下的相关代码:make dir/make arch/make drivers/net/2、只编译部分模块make M=drivers/net/3、只编译某⼀模块make drivers/net/pcnet32.ko4、将编译完成的结果放置于别的⽬录中make O=/tmp/kernel5、交叉编译make ARCH=脚本编程知识点:1、变量中字符的长度:${#VARNAME}2、变量赋值等:${parameter:-word}:如果parameter为空或未定义,则变量展开为"word";否则,展开为parameter的值;${parameter:+word}:如果parameter为空或未定义,不做任何操作;否则,则展开为"word"值;${parameter:=word}:如果parameter为空或未定义,则变量展开为"word",并将展开后的值赋值给parameter;${parameter:?word}:如果parameter为空或未定义,则显⽰为错误,错误信息是后⾯给的"word"值;截取⼦⽚:做字符串切⽚;${parameter:offset}:取字符串,从offset处的后⼀个字符开始,取剩余所有⼦串;${parameter:offset:length}:取⼦串,从offset处的后⼀个字符开始,取lenth长的⼦串;3、脚本配置⽂件/etc/rc.d/init.d/服务脚本服务脚本⽀持配置⽂件:/etc/sysconfig/服务脚本同名的配置⽂件4、局部变量local VAR_NAME=:它只在局部范围内有效,只要变量加上local关键字,它就只在局部范围内有效;a=1test() { a=$[3+4]}for I in `seq $a 10`; do echo $Idone5、命令mktemp创建临时⽂件或⽬录mktemp /tmp/file.XX:为了创建的临时⽂件和别⼈创建的名称不会相同,使⽤file.XX,XX代表随机字符,XX可以有多个;-d: 创建为⽬录这种临时⽂件放到/tmp⽬录下,就算没有删这个⽂件,它们也会定期被清理的,/tmp⽬录⼀般来讲每隔30天会做⼀次清理,30天再也没有被访问过的都会被清理掉;6、信号:进程间通信的⼀种⽅式,⼀个进程向另⼀个进程发送短⼩的信息,能够实现控制另外进程的运作机制;kill -SIGNAL PID:-SIGNAL信号,PID进程号; 1: HUP:让⼀个进程不⽤重启,就可以重读其配置⽂件,并让新的配置信息⽣效; 2: INT:Ctrl+C,中断⼀个进程; 9: KILL:杀死⼀个进程,强制杀死; 15: TERM:终⽌⼀个进程,默认信号;脚本中,能实现信号捕捉,但9和15⽆法捕捉Ctrl+c: SIGINT 中断⼀个进程;trap命令:bash内件命令,可以实现信号捕捉; trap 'COMMAND' 信号列表7、⼀⾏执⾏多个语句,语句间⽤分号分隔(使⽤tarp实现捕捉信号,多个信号列表使⽤分号隔开)[root@Smoke ~]# read -p "Your file:" FILEYour file:提⽰:写⼀个脚本,使⽤read期望⽤户提供⼀个值,如果⽤户没有给,没有输⼊任何信息,直接敲回车了,这时变量从键盘读取⽤户输⼊的数据就为空;[root@Smoke ~]# echo $FILE(显⽰FILE变量中的值)[root@Smoke ~]# stty -F /dev/console size(查看tty终端窗⼝⼤⼩)25 80[root@Smoke ~]# A=3(声明变量A,并赋值为3)[root@Smoke ~]# echo ${A:-30}(如果A变量不空,那就使⽤A⾃⾝的值,否则就使⽤30)3[root@Smoke ~]# unset A(撤销变量A中的赋值)[root@Smoke ~]# echo ${A:-30}(如果A变量不空,那就使⽤A⾃⾝的值,否则就使⽤30)30[root@Smoke ~]# echo $A(显⽰变量A的值)提⽰:变量A的值为空,所以它不会改变变量A⾃⾝的值,但是却把整个表达式展开为后⾯给的字符串;[root@Smoke ~]# A=${A:-30}(如果A不空,把A的值赋予A变量,A等于⾃⾝,如果A的值为空,就把30赋值给A变量)[root@Smoke ~]# echo $A(显⽰变量A的值)30[root@Smoke ~]# unset A(撤销变量A的值)[root@Smoke ~]# echo ${A:-30}(如果A变量不空,就使⽤A⾃⾝的值,否则使⽤30)30[root@Smoke ~]# echo ${A:+30}(如果A变量为空,不做任何操作,如果不空就使⽤30)[root@Smoke ~]# echo ${A:=30}(如果A变量不空,那就使⽤A⾃⾝的值,否则就使⽤30,并且把30赋值给A)30[root@Smoke ~]# echo $A(显⽰A变量的值)30[root@Smoke ~]# ${B:=30}(如果B变量不空,那就使⽤B⾃⾝的值,否则就使⽤30,并且把30赋值给B)-bash: 30: command not found提⽰:不能直接执⾏;[root@Smoke ~]# B=${B:-30}(如果B变量不空,就使⽤B⾃⾝的值,否则使⽤30)[root@Smoke ~]# A='hello world'(定义变量A,并赋值为hello world)如果期望取出来hello world,从第三个开始往后取三个字符;让脚本使⽤配置⽂件:[root@Smoke ~]# vim a.sh(编辑a.sh脚本)#!/bin/bash#[ -n "$TEST" ] && echo $TEST(如果变量TEST的值不空,就显⽰出来)[root@Smoke ~]# chmod +x a.sh(给a.sh脚本执⾏权限)[root@Smoke ~]# ./a.sh(当前⽬录执⾏a.sh脚本)[root@Smoke ~]# vim a.conf(编辑a.conf配置⽂件)TEST='hello world'[root@Smoke ~]# ./a.sh(当前⽬录执⾏a.sh脚本)让脚本获取配置⽂件:[root@Smoke ~]# vim a.sh(编辑a.sh脚本)#!/bin/bash#. /root/a.conf(读取a.conf⽂件内容到当前脚本)[ -n "$TEST" ] && echo $TEST(如果变量TEST的值不空,就显⽰出来)[root@Smoke ~]# ./a.sh(当前⽬录执⾏a.sh脚本)hello world[root@Smoke ~]# vim a.sh(编辑a.sh脚本)#!/bin/bash#. /root/a.conf(读取a.conf⽂件内容到当前脚本)TEST={$TEST:-info}(如果变量TEST没有值,就使⽤info字符串)[ -n "$TEST" ] && echo $TEST[root@Smoke ~]# ./a.sh(当前⽬录执⾏a.sh脚本)hello world[root@Smoke ~]# vim a.conf(编辑a.conf⽂件)TEST=提⽰:TEST变量没有赋值;[root@Smoke ~]# ./a.sh(当前⽬录执⾏a.sh脚本)info[root@Smoke ~]# vim a.conf(编辑a.conf⽂件)TEST='haha'[root@Smoke ~]# ./a.sh(当前⽬录执⾏a.sh脚本)haha[root@Smoke ~]# vim b.sh(编辑b.sh脚本)#!/bin/bash#a=1test() {a=$[3+4]}testfor I in `seq $a 10`; doecho $Idone[root@Smoke ~]# chmod +x b.sh(给b.sh脚本执⾏权限)[root@Smoke ~]# ./b.sh(当前⽬录执⾏b.sh脚本)78910提⽰:test中a变量只和test函数有关系,但是它影响到整个程序,这就是变量的作⽤域,我们在函数中的变量,它也影响到了全局使⽤,变量类型有本地变量、环境变量、位置变量和特殊变量,还有⼀个叫做局部变量,它只在局部范围内有效,只要变量加上local关键字,它就只在局部范围内有效;[root@Smoke ~]# vim b.sh(编辑b.sh脚本)#!/bin/bash#a=1test() {local a=$[3+4] (关键字local代表局部变量,只在函数内有效)}testfor I in `seq $a 10`; doecho $Idone[root@Smoke ~]# ./b.sh(当前⽬录执⾏b.sh脚本)12345678910[root@Smoke ~]# mktemp /tmp/file.XX(创建临时⽂件file.XX,X代表随机字符)/tmp/file.83[root@Smoke ~]# mktemp /tmp/file.XX(创建临时⽂件file.XX,X代表随机字符)/tmp/file.84[root@Smoke ~]# mktemp /tmp/file.XXXXXX(创建临时⽂件file.XXXXXX,X代表随机字符)/tmp/file.f13103[root@Smoke ~]# FILE=`mktemp /tmp/file.XXXXXX`(命令引⽤将mktep /tmp/file.XXXXXX命令执⾏结果保存到FILE变量)[root@Smoke ~]# echo $FILE(显⽰FILE变量的内容)[root@Smoke ~]# mktemp -d /tmp/file.XXXXXX(创建临时⽬录file.XXXXXX,X代表随机字符)/tmp/file.z13141[root@Smoke ~]# ll /tmp/(查看/tmp⽬录⽂件及⼦⽬录详细信息)total 60drwxr-xr-x 12 root root 4096 Dec 4 14:34 busybox-rw------- 1 root root 0 Dec 5 21:35 file.83-rw------- 1 root root 0 Dec 5 21:35 file.84-rw------- 1 root root 0 Dec 5 21:35 file.87-rw------- 1 root root 0 Dec 5 21:37 file.f13103-rw------- 1 root root 0 Dec 5 21:39 file.j13107drwx------ 2 root root 4096 Dec 5 21:41 file.z13141drwx------ 2 root root 4096 Dec 3 08:19 gconfd-rootsrwxr-xr-x 1 root root 0 Dec 3 08:14 mapping-rootsrwxrwxr-x 1 Smoke Smoke 0 Nov 22 01:40 mapping-Smokesrw------- 1 root root 0 Dec 3 08:14 scim-panel-socket:0-rootsrw------- 1 Smoke Smoke 0 Nov 22 01:40 scim-panel-socket:0-Smoke写⼀个脚本,每隔两秒钟显⽰⼀次当前时间:[root@Smoke ~]# vim showdate.sh(编辑showdate.sh脚本)#!/bin/bash#while :;do(死循环,任何条件都循环)datesleep 2done[root@Smoke ~]# chmod +x showdate.sh(给showdate.sh执⾏权限)[root@Smoke ~]# ./showdate.sh(当前⽬录执⾏showdate.sh脚本)Fri Dec 5 22:04:56 CST 2014Fri Dec 5 22:04:58 CST 2014Fri Dec 5 22:05:00 CST 2014Fri Dec 5 22:05:02 CST 2014Fri Dec 5 22:05:04 CST 2014提⽰:脚本会⼀直执⾏,到天荒地⽼,可以使⽤CTRL+C中⽌;[root@Smoke ~]# vim showdate.sh(编辑showdate.sh脚本)#!/bin/bash#trap 'echo "You go..."' INT (捕捉信号,CTRL+C,INT中⽌⼀个进程,如果有⼈发出INT信号,就显⽰You go...)while :;dodatesleep 2done[root@Smoke ~]# ./showdate.sh(当前⽬录执⾏showdate.sh脚本)Fri Dec 5 22:14:16 CST 2014You go...Fri Dec 5 22:14:17 CST 2014You go...Fri Dec 5 22:14:18 CST 2014You go...Fri Dec 5 22:14:19 CST 2014You go...[1]+ Stopped ./showdate.sh提⽰:当执⾏CTRL+C,INT信号中⽌进程,信号被捕捉,⽆法中⽌,可以使⽤CTRL+Z把正在前台的作业送往后台,默认送Stop信号;[root@Smoke ~]# kill -l(查看信号列表)1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR213) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT17) SIGCHLD 18) SIGCONT(bg信号,后台执⾏) 19) SIGSTOP(CTRL+Z把正在前台的作业送往后台,默认送Stop信号) 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+439) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+843) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+1247) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-1451) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-1055) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-659) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-263) SIGRTMAX-1 64) SIGRTMAX[root@Smoke ~]# kill %1(终⽌某作业,需要带百分号,⽤于区分作业号还是进程号)[root@Smoke ~]# vim ping.sh(编辑ping.sh脚本)#!/bin/bash#NET=192.168.0for I in {200..254};doif ping -c 1 -W 1 $NET.$I &> /dev/null;thenecho "$NET.$I is up."elseecho "$NET.$I is down."fidone[root@Smoke ~]# chmod +x ping.sh(给ping.sh脚本执⾏权限)[root@Smoke ~]# chmod +x ping.sh[root@Smoke ~]# ./ping.sh(当前⽬录执⾏ping.sh脚本)192.168.0.200 is down.192.168.0.207 is down.提⽰:通过CTRL+C INT信号⽆法中⽌脚本,因为CTRL+C信号被ping命令捕捉到了,默认被ping命令接收,⽽没有被脚本bash接收,所以CTRL+C只不过当前ping命令不进⾏⽽已,只是当前的ping命令就是处理CTRL+C信号的;让脚本捕捉CTRL+C INT信号:[root@Smoke ~]# vim ping.sh(编辑ping.sh脚本)#!/bin/bash#NET=192.168.0trap 'echo "quit."' INT(捕捉INT信号,显⽰quit)for I in {200..254};doif ping -c 1 -W 1 $NET.$I &> /dev/null;thenecho "$NET.$I is up."elseecho "$NET.$I is down."fidone[root@Smoke ~]# ./ping.sh(当前⽬录执⾏ping.sh脚本)quit.192.168.0.200 is down.quit.192.168.0.201 is down.quit.192.168.0.202 is down.提⽰:虽然捕捉到了CTRL+C INT信号,但是没有退出,退出脚本exit;#!/bin/bash#NET=192.168.0trap 'echo "quit.";exit 1' INT(捕捉INT信号,并显⽰quit和退出脚本)for I in {200..254};doif ping -c 1 -W 1 $NET.$I &> /dev/null;thenecho "$NET.$I is up."elseecho "$NET.$I is down."fidone[root@Smoke ~]# ./ping.sh(当前⽬录执⾏ping.sh脚本)192.168.0.200 is down.192.168.0.201 is down.quit.提⽰:捕捉CTRL+C INT信号,退出脚本,并显⽰quit;我们捕捉信号中间执⾏的命令可能会很多,我们不能这么简单的停⽌,⽐如如果⼀个脚本中写了创建临时⽂件,还声明了很多变量,它在没有执⾏结束之前,突然CTRL+C INT信号,这时候这些创建的临时⽂件应该删除,⾄少要把脚本执⾏过程中产⽣的垃圾清理掉,这⾥执⾏的操作就多了,可以通过定义函数来使⽤:[root@Smoke ~]# vim ping.sh(编辑ping.sh脚本)#!/bin/bash#NET=192.168.0clearup() { (定义函数clearup)echo "quit..."exit 1}trap 'clearup' INT (捕捉信号CTRL+C INT,并执⾏clearup函数)for I in {200..254};doif ping -c 1 -W 1 $NET.$I &> /dev/null;thenecho "$NET.$I is up."elseecho "$NET.$I is down."fidone[root@Smoke ~]# ./ping.sh(当前⽬录执⾏ping.sh脚本)192.168.0.200 is down.quit...提⽰:捕捉CTRL+C INT信号,退出脚本,并显⽰quit;如何清理现场:[root@Smoke ~]# vim ping.sh(编辑ping.sh脚本)#!/bin/bash#NET=192.168.0FILE=`mktemp /tmp/file.XXXXXX`(定义变量FILE,并将mktemp创建临时⽂件结果赋予FILE变量)clearup() {echo "quit..."exit 1}trap 'clearup' INTfor I in {200..254};doif ping -c 1 -W 1 $NET.$I &> /dev/null;thenecho "$NET.$I is up." | tee >> $FILE(tee从标准输⼊读取数据,并且发送⾄标准输出和⽂件,可以实现将⼀个数据即保存到⽂件中⼜能够输出到显⽰器)elseecho "$NET.$I is down."fidone[root@Smoke ~]# ./ping.sh(当前⽬录执⾏ping.sh脚本)quit...提⽰:捕获CTRL+C INT信号,退出脚本,并显⽰quit,但是临时⽂件不会删除;#!/bin/bash#NET=192.168.0FILE=`mktemp /tmp/file.XXXXXX`clearup() {echo "quit..."rm -f $FILE(删除临时⽂件)exit 1}trap 'clearup' INTfor I in {200..254};doif ping -c 1 -W 1 $NET.$I &> /dev/null;thenecho "$NET.$I is up." | tee >> $FILEelseecho "$NET.$I is down."fidone[root@Smoke ~]# rm -rf /tmp/file.*(删除/tmp⽬录下所有file开头任何长度任意字符结尾的临时⽂件)[root@Smoke ~]# ./ping.sh(当前⽬录执⾏ping.sh脚本)192.168.0.200 is down.192.168.0.201 is down.192.168.0.202 is down.192.168.0.203 is down.提⽰:让脚本运⾏,同时通过新的tty终端查看/tmp⽬录创建的临时⽂件;[root@Smoke ~]# ls /tmp/busybox file.H14378 gconfd-root mapping-root mapping-Smoke scim-panel-socket:0-root scim-panel-socket:0-Smoke[root@Smoke ~]# tail -f /tmp/file.H14378(查看file.H14378⽂件后10⾏内容,-f查看⽂件尾部,不退出,等待显⽰后续追加⾄此⽂件的新内容)192.168.0.202 is up192.168.0.203 is up192.168.0.204 is up192.168.0.206 is up192.168.0.208 is up[root@Smoke ~]# ./ping.sh(当前⽬录执⾏ping.sh脚本)192.168.0.200 is down.192.168.0.201 is down.192.168.0.202 is down.192.168.0.203 is down.quit...提⽰:这是使⽤CTRL+C INT捕捉信号,退出脚本,并显⽰quit,再查看临时⽂件是否存在;[root@Smoke ~]# ls /tmp/(查看/tmp⽬录⽂件及⼦⽬录)busybox gconfd-root mapping-root mapping-Smoke scim-panel-socket:0-root scim-panel-socket:0-Smoke提⽰:通过CTRL+C信号,临时⽂件被清理掉;任务计划:很多时候我们将系统执⾏的任务写成了脚本,但是并不期望这个脚本⽴即就执⾏,⽽是安排到未来的某个时间运⾏的话,这种机制就叫任务计划(⼀定是未来的时间);1、在未来的某个时间点执⾏⼀次某任务; at -l:查看作业; batch:不需要指定时间,但是也只是执⾏⼀次,特性:在系统⽐较空闲的时候执⾏任务,其他格式和at相同; at 时间(时间点) at> COMMAND(at>提⽰符,COMMAND输⼊期望要执⾏的命令,可以写多个,使⽤回车继续;) at> Ctrl+d(提交任务任务) 指定时间: 绝对时间:HH:MM, DD.MM.YY MM/DD/YY 相对时间:now+#(从现在开始往后3分钟) 单位:minutes, hours, days, weeks 模糊时间:noon(上午12点), midnight(晚上12点), teatime(下午4点,喝茶时间) 命令的执⾏结果:将以邮件的形式发送给安排任务的⽤户可以定义让谁使⽤at或batch创建任务计划:如果at.deny和at.allow⽂件都存在,只允许at.allow中⽤户使⽤at或batch创建任务计划,如果两个都不存在只允许root⽤户使⽤at或batch创建任务计划;/etc/at.deny:⿊名单,拒绝那些⽤户使⽤任务计划/etc/at.allow:⽩名单,允许那些⽤户使⽤任务计划;2、周期性地执⾏某任务; cron:⾃⾝是⼀个不间断运⾏的服务 anacron: cron的补充,能够实现让cron因为各种原因在过去的时间该执⾏⽽未执⾏的任务在恢复正常执⾏⼀次,默认不启动; cron: 系统cron任务: /etc/crontab 分钟⼩时天⽉周⽤户任务 ⽤户cron任务: /var/spool/cron/USERNAME 分钟⼩时天⽉周任务 时间的有效取值: 分钟:0-59 ⼩时:0-23 天:1-31 ⽉:1-12 周:0-7,0和7都表⽰周⽇ 时间通配表⽰: *: 对应时间的所有有效取值 3 * * * *:每个⼩时的第3分钟; 3 * * * 7:每周⽇的每个⼩时的第3分钟; 13 12 6 7 *:每年的7⽉6号13点13分; ,: 离散时间点: 10,40 02 * * 2,5:每周2和周5的2点10分和2点40分; -:连续时间点: 10 02 * * 1-5:每周1到周5的2点10分; /#: 对应取值范围内每多久⼀次,#频率; */3 * * * *:每3分钟执⾏⼀次; 每两⼩时执⾏⼀次: * */2 * * *:每两⼩时的每分钟执⾏⼀次; 08 */2 * * *:每两⼩时执⾏⼀次; 每两天执⾏⼀次: * * */2 * *:每两天的每分钟都执⾏⼀次; 10 04 */2 * *:每两天执⾏⼀次;当指定某个每时间点的时候⽐它⼩的时间点⼀定要加上具体值; cron执⾏结果将以邮件形式发送给管理员: cron的环境变量:cron执⾏所有命令都去PATH环境变量指定的路径下去找,(注意:既然是任务计划,执⾏的时候很可能是没有登录的,所以没有PATH环境变量,所以⽆法找到命令,⼀般在cron当中使⽤的命令都应该写绝对路径) PATH(cron PATH只包含的PATH环境变量路径) /bin:/sbin:/usr/bin:/usr/sbin如果在cron中使⽤脚本(每个命令都要写绝对路径⽐较⿇烦):可以在脚本中定义PATH环境变量,这样脚本就使⽤⾃⾝的环境变量,就不再使⽤其他的环境变量;#!/bin/bashPATH= ⽤户任务的管理: crontab -l: 列出当前⽤户的所有cron任务 -e: 编辑 -r: 移除所有任务,移除cron⽂件; -u USERNAME: 管理其⽤户的cron任务 anacron:anacron如果cron任务不幸略过,可以代替cron在系统启动以后执⾏这个任务,所以它是cron的补充,替代不了cron;rond和anacron服务:service crond status:使⽤cron任务⼀定要确保cron服务是启动的;service anacron status:使⽤anacron任务⼀定要确保anacron服务是启动的,默认是关闭的;[root@Smoke tmp]# man at(查看at命令man帮助⽂档)[root@Smoke tmp]# at now+3(在3后执⾏任务)syntax error. Last token seen: 3Garbled time提⽰:syntax error,语法错误[root@Smoke tmp]# at now+3minutes(在3分钟后执⾏任务,以提交任务开始)at> ls /varat> cat /etc/fstabat> <EOT>(CTRL+D提交任务)job 1 at 2014-12-06 00:10(第1个作业在2014-12-06 00:10)[root@Smoke tmp]# at now+10minutes(在10分钟后执⾏任务,以提交任务开始)at> cat /etc/issueat> <EOT>(CTRL+D提交任务)job 2 at 2014-12-06 00:19(第2各作业在2014-12-06 00:19)[root@Smoke tmp]# at -l(显⽰作业列表)2(第2个作业) 2014-12-06 00:19(执⾏时间) a(队列) root(⽤户)1 2014-12-06 00:10 a root[root@Smoke ~]# at -d 2(删除2号作业)[root@Smoke ~]# at -l(查看作业列表)[root@Smoke ~]# at now+1minutes(在1分钟后执⾏任务,以提交任务开始)at> cat /etcfstabat> <EOT>(CTRL+D提交任务)job 3 at 2014-12-06 01:01[root@Smoke ~]# service sendmail restart(重启sendmail服务)Shutting down sm-client: [ OK ]Shutting down sendmail: [ OK ]Starting sendmail: [ OK ]Starting sm-client: [ OK ][root@Smoke ~]# mail(查看⽤户邮件)Mail version 8.1 6/6/93. Type ? for help."/var/spool/mail/root": 3 messages 1 new 3 unreadU 1 root@ Sat Dec 6 00:10 44/1206 "Output from your job 1"U 2 root@ Sat Dec 6 00:19 18/639 "Output from your job 2"& 1(选择数字读取那个邮件)& q(退出邮件)[root@Smoke ~]# ls /etc/at.deny(查看at或batch⿊名单⽂件)[root@Smoke ~]# vim /etc/crontab(查看系统cron配置⽂件)SHELL=/bin/bash(以那⼀个作为解析命令的解释器)PATH=/sbin:/bin:/usr/sbin:/usr/bin(环境变量)MAILTO=root(邮件发给谁)HOME=/# run-parts01 * * * * root run-parts /etc/cron.hourly(每⼩时执⾏⼀次,以root⽤户⾝份,执⾏run-parts参数/etc/cron.hourly,run-parts是红帽提供的脚本,能够实现运⾏/etc/cron.hourly下的每⼀个脚本或命令)02 4 * * * root run-parts /etc/cron.daily(每天任务)22 4 * * 0 root run-parts /etc/cron.weekly(每周⽇任务)42 4 1 * * root run-parts /etc/cron.monthly(每⽉任务)[root@Smoke ~]# ls /etc/cron.daily/(查看没天任务的⽂件夹)[root@Smoke cron]# vim root(编辑root⽤户cron)提⽰:⽤户cron需要在/var/spool/cron/⽬录下定义和⽤户同名的⽂件,不会检查语法;[root@Smoke ~]# crontab -l(列出当前⽤户cron任务)no crontab for root[root@Smoke ~]# crontab -e(定义当前⽤户cron任务)*/3 * * * * /bin/echo "how are ya?"(每3分钟执⾏⼀次)crontab: installing new crontab(安排新的cron任务)[root@Smoke ~]# crontab -e*/3 * * * * /bin/echo "how are ya?"*/5 * * * /bin/echo "how are ya?"(少些⼀段时间表⽰)crontab: installing new crontab"/tmp/crontab.XXXXzS1tQE":2: bad day-of-weekerrors in crontab file, can't install.(错误的cron⽂件,不能安排)Do you want to retry the same edit? y(需要重新编辑吗,y编辑)*/3 * * * * /bin/echo "how are ya?"*/5 * * * * /bin/echo "how are ya?"提⽰:crontab -e可以检查语法错误,如果收到在/var/spool/cron⽬录编辑⽤户cron不会检查语法;[root@Smoke ~]# ls /var/spool/cron/(查看⽤户cron⽂件)root[root@Smoke ~]# crontab -r(移除所以cron任务,会删除cron⽂件)[root@Smoke ~]# ls /var/spool/cron/(查看⽤户cron⽂件)[root@Smoke ~]# id hadoop(查看hadoop⽤户信息)uid=501(hadoop) gid=501(hadoop) groups=501(hadoop) context=root:system_r:unconfined_t:SystemLow-SystemHigh[root@Smoke ~]# crontab -u hadoop -e(给hadoop⽤户编辑cron任务)*/3 * * * * /bin/echo "How are ya!"(每3分钟执⾏⼀次)[root@Smoke ~]# ls /var/spool/cron/(查看⽤户cron任务⽂件)hadoop[root@Smoke ~]# su - hadoop(切换到hadoop⽤户)[hadoop@Smoke ~]$ crontab -l(列出当前⽤户cron任务)*/3 * * * * /bin/echo "How are ya!"[root@Smoke ~]# cat /etc/anacrontab(查看anacrontab⽂件)# /etc/anacrontab: configuration file for anacron# See anacron(8) and anacrontab(5) for details.SHELL=/bin/shPATH=/sbin:/bin:/usr/sbin:/usr/binMAILTO=root1(过去已经有1天没执⾏,每天任务,每分钟任务,⼩于1天的任务,在过去应该执⾏⼀次的,但它⼀天没有执⾏了) 65(如果有⼩于1天的任务,在⼀天没有执⾏,在开机以后的第65分钟执⾏) cron.daily run-parts /etc/cron.daily7(已经有7天没执⾏) 70(开机以后第70分钟) cron.weekly run-parts /etc/cron.weekly30(已经有1个⽉没执⾏) 75(开机以后第75分钟) cron.monthly run-parts /etc/cron.monthly提⽰:anacrontab⽂件语法格式,这个⽂件⼀共有4个段,前两个段是指时间的,第三个段是注释信息,第四个段是要执⾏的任务,anacrontab最⼩操作单位是天,cron是分钟,但是anacrontab最多只能监控到天,过去⼀天已经没有执⾏了,如果是过去5分钟是管不了的,只能监控到每天、每周、每⽉;[root@Smoke ~]# service crond status(查看crond服务状态)crond (pid 3603) is running...提⽰:cron⼀定要确保crond服务启动,只有crond服务运⾏,cron任务才能运⾏;[root@Smoke ~]# service anacron status(查看anacron服务状态)anacron is stopped提⽰:anacron⼀定要确保anacron服务是启动的,默认是关闭的;[root@Smoke ~]# chkconfig --list crond(查看crond服务在不同级别下运⾏情况)crond 0:off 1:off 2:on 3:on 4:on 5:on 6:off提⽰:crond服务也是chkconfig控制的;问题:配置本机每隔两台在凌成3点20备份⼀次/etc⽬录,备份⽂件存放⾄/backup/etc⽬录,⽂件形如:etc-2012-06-20.tar.bz2;Linux内核及编译Linux系统安装和kickstart故障排除Kernel + initrd(busybox制作,提供ext3⽂件系统模块) + ROOTFS (busybox制作)make arch/:只编译对应⽬录下的所有内容; arch/x86/boot/bzImage:编译后x86内核⽬录,bzImage是使⽤bz⽅式压缩之后的内核映像⽂件; 硬件驱动:initrd initrd: 仅需要提供内核访问真正的根⽂件系统所在设备需要的驱动 存储设备和⽂件系统相关的模块 系统初始化rc.sysinit: 初始其它硬件的驱动程序; ROOTFS: busybox, init不⽀持运⾏级别(如果要使⽤运⾏级别可以移植,还需要更改/etc/inittab⽂件格式) /etc/inittab: 格式也不尽相同内核编译: make SUBDIR=arch/ make arch/x86//boot/vmlinuz (ext3, IDE):系统⾃⼰的内核不带ext3模块,但是默认⽀持IDE的硬盘驱动,因此不再需要提供硬件设备驱动,只需要提供⽂件系统;/mnt/boot: /dev/hda1/mnt/sysroot: /dev/hda2制作完整的⼩Linux系统:[root@Smoke ~]# ls(查看当前⽬录⽂件及⼦⽬录)linux-2.6.38.5.tar.bz2提⽰:下载linux内核为linux-2.6.38.5.tar.bz2,将内核⽂件解压到/usr/src⽬录;[root@Smoke ~]# tar xf linux-2.6.38.5.tar.bz2 -C /usr/src/(解压linux-2.6.38.5.tar.bz2,-C更改解压⽬录为/usr/src)[root@Smoke ~]# cd /usr/src/(切换到/usr/src)[root@Smoke src]# ls(查看当前⽬录⽂件及⼦⽬录)debug kernels linux-2.6.38.5 redhat[root@Smoke src]# ln -sv linux-2.6.38.5/ linux(给linux-2.6.38.5创建软连接linux,并显⽰创建过程)create symbolic link `linux' to `linux-2.6.38.5/'[root@Smoke src]# cd linux(切换到linux⽬录)[root@Smoke linux]# ls(查看当前⽬录⽂件及⼦⽬录)arch COPYING crypto drivers fs init Kbuild kernel MAINTAINERS mm README samples security tools virtblock CREDITS Documentation firmware include ipc Kconfig lib Makefile net REPORTING-BUGS scripts sound usr[root@Smoke linux]# ls -a(查看当前⽬录所有⽂件及⼦⽬录). block crypto firmware include Kbuild lib Makefile README scripts tools.. COPYING Documentation fs init Kconfig .mailmap mm REPORTING-BUGS security usrarch CREDITS drivers .gitignore ipc kernel MAINTAINERS net samples sound virt提⽰:要配置内核,要提供.config⽂件,但是要完全从头配置⽐较困难,以前是直接复制当前系统的.config⽂件,但是当前系统的.config⽂件并不适合我们制作微型⼩Linux使⽤;[root@Smoke linux]# lftp 172.160.1(连接ftp服务器)lftp 172.160.1:~> cd pub/Sources/kernel(切换到pub/Sources/kernel⽬录)lftp 172.160.1:/pub/Sources/kernel~> get kernel-2.6.38.1-i686.cfg(下载.configure配置⽂件)71568 bytes transferredlftp 172.160.1:/pub/Sources/kernel~> bye(退出0[root@Smoke linux]# ls(查看当前⽬录⽂件及⼦⽬录)arch CREDITS drivers include Kbuild kernel-2.6.38.5-i686.cfg Makefile README scripts toolsblock crypto firmware init Kconfig lib mm REPORTING-BUGS security usrCOPYING Documentation fs ipc kernel MAINTAINERS net samples sound virt提⽰:下载的kernel-2.6.38.5-i686.cfg⽂件;[root@Smoke linux]# mv kernel-2.6.38.5-i686.cfg .config(重命名kernel-2.6.38.5-i686.cfg为.config)提⽰:以.config⽂件作为蓝本来进⾏修改;[root@Smoke linux]# make menuconfig(配置内核)提⽰:⼀定要在内核⽬录下;打开内核编译字符图形界⾯,需要将终端窗⼝放⼤不然会报错,提⽰窗⼝⾄少要能容纳19⾏,容纳80列;提⽰:选择General setup --->选项,进⼊⼦菜单;提⽰:选择Local version - append to kernel release(更改内核版本号),点击回车,更改版本为-1.mlinux,点击OK;提⽰:选择Cross-compiler tool prefix(交叉编译)提⽰:双击ESC返回主菜单,选择Device Drivers --->(设备驱动),点击回车;提⽰:选择SCSI device support --->(⽀持SCSI设备),点击回车,选择SCSI tape support(SCSI磁带⽀持)通过空格键关闭;提⽰:通过双击ESC键返回上级菜单,选择Serial ATA and parallel ATA drivers --->(串⾏ATA和并⾏ATA设备),都要能够⽀持;提⽰:通过双击ESC键返回上级菜单,要在VMware使⽤SCSI需要编译Fusion MPT device support --->(融合MPT设备⽀持),SCSI Transports --->(SCSI传输)需要⽀持,SCSI low-level drivers --->(SCSI低级别设备)需要⽀持;提⽰:SCSI Transports --->(SCSI传输)需要⽀持,SCSI low-level drivers --->(SCSI低级别设备)需要⽀持,选择SCSI device support --->(SCSI设备⽀持)点击回车;提⽰:我们这⾥内核提供的样本是不⽀持SCSI设备的,所以不进⾏更改,双击ESC返回到主菜单,选择Device Drivers ---(设备驱动),选择Network device support --->(⽹络设备⽀持),点击回车;提⽰:关闭Eternet (1000 Mbit) --->(千兆⽹卡)、关闭Eternet (10000 Mbit) --->(万兆⽹卡)、关闭Wireless LAN --->(⽆线⽹卡)、关闭PCMCIA network device support --->;提⽰:将ext2⽂件系统⽀持通过空格选择做进内核、将ext3⽂件系统⽀持通过空格选择做进内核、将ext4通过空格关闭⽀持,Reiserfssupport(reiserfs⽂件系统⽀持)在我们⽂件系统⽤不着通过空格关闭、JFS filesystem support(JFS⽂件系统⽀持)通过空格关闭,XFS filesystem support(XFS⽂件系统⽀持)通过空格关闭,这样把ext3⽂件系统直接做进内核,这样就不需要在initrd中给它提供模块了,否则就必须要⼿动给它提供模块;提⽰:双击ESC返回上级菜单,找到Network device support --->(⽹络设备⽀持),点击回车;提⽰:选择Eternet (10 or 100Mbit) --->点击回车,关闭3COM cards、将AMD PCnet32 PCI support(AMD PCnet32 PCI⽀持)做进模块,关闭Micrel KSZ8841/2 PCI、关闭Broadcom 440x/47xx ethernet support(蓝⽛⽀持)、关闭nForce Ethernet support、关闭CS89x0 support、关闭Inter(R) PRO/100+ support、关闭Mylex EISA LNE390A/B support (EXPERIMENTAL)、关闭Myson MTD-8xx PCI Ethernet supoort、关闭National Semiconductor DP8381x series PCI Ethernet supoort、关闭PCI NE2000 and clones support (see help)、关闭RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERMENTAL)、关闭RealTek RTL-8129/8130/8139 PCI fast Ethernet Adapter support、关闭RDCR6040 Fast Ethernet Adapter support、关闭Sis 900/7016 PCI Fast Ethernet Adapter support、关闭SMC Etherpower II、关闭SMSC LAN9420 PCI ethernet adapter support、关闭Sundance Alta supoort、关闭TI ThunderLAN support、关闭Micrel KS8851 MLL、关闭VIA Rhine support;提⽰:双击ESC返回到主菜单,保存退出,选择Yes;[root@Smoke linux]# cp .config /root/config-2.6.38.5-i686.cfg(赋值.config⽂件到/root⽬录叫config-2.6.38.5-i686.cfg)[root@Smoke linux]# make drivers/net/pcnet32.ko(编译⽹卡模块pcnet32.ko)提⽰:将pcnet32.c写成pcnet32.ko进⾏编译;[root@Smoke linux]# modinfo drivers/net/pcnet32.ko(查看pcnet32.ko模块信息)filename: drivers/net/pcnet32.kolicense: GPLdescription: Driver for PCnet32 and PCnetPCI based ethercardsauthor: Thomas Bogendoerferalias: pci:v00001023d00002000sv*sd*bc02sc00i*alias: pci:v00001022d00002000sv*sd*bc*sc*i*alias: pci:v00001022d00002001sv*sd*bc*sc*i*depends:vermagic: 2.6.38.5-1.mlinux SMP preempt mod_unload 686parm: debug:pcnet32 debug level (int)parm: max_interrupt_work:pcnet32 maximum events handled per interrupt (int)parm: rx_copybreak:pcnet32 copy breakpoint for copy-only-tiny-frames (int)parm: tx_start_pt:pcnet32 transmit start point (0-3) (int)parm: pcnet32vlb:pcnet32 Vesa local bus (VLB) support (0/1) (int)parm: options:pcnet32 initial option setting(s) (0-15) (array of int)parm: full_duplex:pcnet32 full duplex setting(s) (1) (array of int)parm: homepna:pcnet32 mode for 79C978 cards (1 for HomePNA, 0 for Ethernet, default Ethernet (array of int)提⽰:查看依赖那些模块,⾃⼰编译的pcnet32.ko模块不再依赖mii.ko模块;[root@Smoke linux]# make drivers/net/(编译drivers/net/⽬录下所有模块)提⽰:编译drivers/net/⽬录下所有已经选择的⽹卡都会被编译;[root@Smoke linux]# make arch/(编译对应⼦⽬录下的内容)提⽰:只编译核⼼make arch/,或者make arch/x86/编译x86平台核⼼,不指定它会根据当前系统操作系统平台版本进⾏选择,所以我们执⾏make arch/就可以了,为了让这个过程不会端⼝可以打开screen;[root@Smoke linux]# screen(打开screen)提⽰:在编译内核时候最好不要使⽤远程连接,万⼀远程连接断开了,内核编译过程也就中断了,你要再重新执⾏⼜要重头开始,可以使⽤screen⼯具,能够在当前远程窗⼝中模拟好⼏个窗⼝;[root@Smoke linux]# make arch/x86/(编译x86平台核⼼)先使⽤操作系统提供的内核,等新内核编译好了再切换到新内核:(/boot/vmlinuz (ext3, IDE):系统⾃⼰的内核不带ext3模块,但是默认⽀持IDE的硬盘驱动,因此不再需要提供硬件设备驱动,只需要提供⽂件系统;)提供boot⽬录和sysroot⽬录:在现有linux虚拟机增加⼀块20G的IDE硬盘,为系统上的新硬盘建⽴分区,这⾥根据需要先建⽴⼀个⼤⼩为100M的主分区作为新建系统的boot分区和⼀个512M的分区作为⽬标系统(即正在构建的新系统,后⾯将沿⽤此名称)的根分区;100M的分区格式化后将其挂载⾄/mnt/boot⽬录下;512M的分区格式化后将挂载⾄/mnt/sysroot⽬录;[root@localhost ~]# fdisk -l(查看系统上磁盘及分区情况)Disk /dev/hda: 21.4 GB, 21474836480 bytes15 heads, 63 sectors/track, 44384 cylindersUnits = cylinders of 945 * 512 = 483840 bytesDisk /dev/hda doesn't contain a valid partition tableDisk /dev/sda: 53.6 GB, 53687091200 bytes255 heads, 63 sectors/track, 6527 cylindersUnits = cylinders of 16065 * 512 = 8225280 bytesDevice Boot Start End Blocks Id System/dev/sda1 * 1 13 104391 83 Linux/dev/sda2 14 2624 20972857+ 83 Linux/dev/sda3 2625 2755 1052257+ 82 Linux swap / Solaris[root@localhost ~]# fdisk /dev/hda(管理磁盘分区,进⼊交互式模式)The number of cylinders for this disk is set to 44384.There is nothing wrong with that, but this is larger than 1024,and could in certain setups cause problems with:1) software that runs at boot time (e.g., old versions of LILO)2) booting and partitioning software from other OSs(e.g., DOS FDISK, OS/2 FDISK)Command (m for help): n(创建分区)Command actione extendedp primary partition (1-4)p(主分区)Partition number (1-4): 1(分区号)First cylinder (1-44384, default 1):Using default value 1Last cylinder or +size or +sizeM or +sizeK (1-44384, default 44384): +100M(创建100M分区)Command (m for help): n(创建分区)Command actione extendedp primary partition (1-4)p(驻俄分区)Partition number (1-4): 2(分区号)First cylinder (209-44384, default 209):Using default value 209Last cylinder or +size or +sizeM or +sizeK (209-44384, default 44384): +512M(创建512M分区)Command (m for help): w(保存退出)The partition table has been altered!Calling ioctl() to re-read partition table.Syncing disks.[root@localhost ~]# partprobe /dev/hda(让内核重新扫描分区表)[root@localhost ~]# fdisk -l /dev/hda(查看/dev/hda分区情况)Disk /dev/hda: 21.4 GB, 21474836480 bytes15 heads, 63 sectors/track, 44384 cylindersUnits = cylinders of 945 * 512 = 483840 bytesDevice Boot Start End Blocks Id System/dev/hda1 1 208 98248+ 83 Linux/dev/hda2 209 1267 500377+ 83 Linux[root@localhost ~]# mke2fs -j /dev/hda1(将/dev/hda1创建为带⽇志的⽂件系统,即ext3⽂件系统)mke2fs 1.39 (29-May-2006)Filesystem label=OS type: LinuxBlock size=1024 (log=0)Fragment size=1024 (log=0)24576 inodes, 98248 blocks4912 blocks (5.00%) reserved for the super userFirst data block=1Maximum filesystem blocks=6737100812 block groups8192 blocks per group, 8192 fragments per group2048 inodes per groupSuperblock backups stored on blocks:8193, 24577, 40961, 57345, 73729Writing inode tables: doneCreating journal (4096 blocks): doneWriting superblocks and filesystem accounting information: doneThis filesystem will be automatically checked every 20 mounts or180 days, whichever comes first. Use tune2fs -c or -i to override.[root@localhost ~]# mke2fs -j /dev/hda2(将/dev/hda2创建为带⽇志的⽂件系统,即ext3⽂件系统)mke2fs 1.39 (29-May-2006)Filesystem label=OS type: LinuxBlock size=1024 (log=0)Fragment size=1024 (log=0)125488 inodes, 500376 blocks25018 blocks (5.00%) reserved for the super userFirst data block=1Maximum filesystem blocks=6763315262 block groups8192 blocks per group, 8192 fragments per group2024 inodes per groupSuperblock backups stored on blocks:8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409Writing inode tables: doneCreating journal (8192 blocks): doneWriting superblocks and filesystem accounting information: doneThis filesystem will be automatically checked every 35 mounts or180 days, whichever comes first. Use tune2fs -c or -i to override.[root@localhost ~]# mkdir /mnt/{boot,sysroot}(创建/mnt/boot⽬录和/mnt/sysroot⽬录,花括号{}展开) [root@localhost ~]# mount /dev/hda1 /mnt/boot/(将/dev/hda1挂载到/mnt/boot/⽬录)[root@localhost ~]# mount /dev/hda2 /mnt/sysroot/(将/dev/hda2挂载到/mnt/boot/⽬录)[root@localhost ~]# mount(查看系统所有挂载的⽂件系统)/dev/sda2 on / type ext3 (rw)proc on /proc type proc (rw)sysfs on /sys type sysfs (rw)devpts on /dev/pts type devpts (rw,gid=5,mode=620)/dev/sda1 on /boot type ext3 (rw)tmpfs on /dev/shm type tmpfs (rw)none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)/dev/hda1 on /mnt/boot type ext3 (rw)/dev/hda2 on /mnt/sysroot type ext3 (rw)安装GRUB:[root@Smoke ~]# grub-install --root-directory=/mnt /dev/hda(安装GRUB,根⽬录/mnt,设备/dev/hda)Probing devices to guess BIOS drives. This may take a long time.Installation finished. No error reported.This is the contents of the device map /mnt/boot/grub/device.map.Check if this is correct or not. If any of the lines is incorrect,fix it and re-run the script `grub-install'.(fd0) /dev/fd0(hd0) /dev/hda(hd1) /dev/sda[root@Smoke ~]# ls /mnt/boot/(查看安装的grub)。
1@@linux内核input子系统解析2
input_handler 2、input_handler 结构体 以 evdev.c 中的 evdev_handler 为例: static struct input_handler evdev_handler = {
.event = evdev_event, //向系统报告 input 事件,系统通过 read 方法读取 .connect = evdev_connect, //和 input_dev 匹配后调用 connect 构建 .disconnect = evdev_disconnect, .fops = &evdev_fops, //event 设备文件的操作方法 .minor = EVDEV_MINOR_BASE, //次设备号基准值 .name = "evdev", .id_table = evdev_ids, //匹配规则 }; input 3、input 字符设备注册过程 drivers/input/input.c 中: static int __init input_init(void) { int err; err = class_register(&input_class); …… err = register_chrdev(INPUT_MAJOR, "input", &input_fops); …… } input_fops 定义: static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file, }; Input_dev 和 input_handler 匹配后调用 input_handler 的 connect。以 evdev_handler 为例: static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id) { struct evdev *evdev; struct class_device *cdev; dev_t devt; int minor; int error; for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); if (minor == EVDEV_MINORS) { printk(KERN_ERR "evdev: no more free evdev devices\n"); return -ENFILE; } evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);//为每个匹配 evdev_handler 的设备
输入子系统
输入子系统内核自带的说明文档。
Input-programming.txt (documentation\input)1、申请核心结构struct input_dev *devp;devp = input_allocate_device();2、填充核心结构#define EV_SYN 0x00 //表示设备支持所有事件#define EV_KEY 0x01 //键盘或者按键,表示一个键码#define EV_REL 0x02 //鼠标设备,表示一个相对的光标位置结果#define EV_ABS 0x03 //手写板产生的值,其是一个绝对整数值devp->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY); //填充核心结构的事件set_bit(KEY_0, devp->keybit); //将KEY_0的值填到结构体中的keybit数组中。
3、注册核心结构(早期的注册方式)input_register_device(devp) //devp是一个指针4、上报事件(按键,相对坐标,绝对坐标,同步事件(必不可少,用来标识一次事件已经上报完毕))上报按键事件(一般写在中断中)input_report_key(devp, KEY_0, k ? 1 : 0);上报同步事件:input_sync(devp);上报按键事件:static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)上报相对坐标事件:static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)上报绝对坐标事件:static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)上报力反馈事件static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)上报同步事件:static inline void input_sync(struct input_dev *dev)上报同步事件(电容屏会使用到这个函数):static inline void input_mt_sync(struct input_dev *dev)以上函数都是通过调用input_event函数来实现,所以我们也可以直接使用以下函数来上报事件。
【IT专家】Linux输入子系统
本文由我司收集整编,推荐下载,如有疑问,请与我司联系
Linux输入子系统
2017/02/20 0 前面章节讲解了按键设备驱动,实际上,在Linux系统中,为了实现这类驱动程序,一种更得推荐的方法是利用input子系统。
Linux系统提供了input子系统,按键、触摸屏、鼠标等输入型设备都可以用input接口函数来实现设备驱动。
体系结构:输入子系统由驱动层,输入子系统核心层(InputCore)和事件处理层(EventHandler)三部分组成。
一个输入事件,如鼠标移动,键盘按键按下,通过Driver- InputCore-Eventhandler- userspace的顺序到达用户空间的应用程序。
驱动层:将底层的硬件输入转化为统一事件形式,向输入核心(InputCore)汇报。
输入核心层:为驱动层提供输入设备注册与操作接口,如:
input_register_device;通知事件处理层对事件进行处理;在/PROC下产生相应的设备信息。
事件处理层:主要作用是和用户空间进行交互,我们知道Linux在用户空间将所有设备当成文件来处理,在一般的驱动程序中都有提供fops接口,以及在/dev下生成相应的设备文件nod,而在输入子系统中,这些工作都是由事件处理层来完成的。
设备描述:在Linux内核中,input设备用input_dev结构体描述,使用input子系统实现输入设备驱动的时候,驱动的核心工作是向系统报告按键、触摸屏、键盘、鼠标等输入事件(event,通过input_event结构体来描述),不需要再关心文件操作接口,因为input子系统已经完成了文件操作接口,驱动报告的事件经过InputCore和Eventhandler最终到达用户空间。
Linux输入子系统:事件的编码
Linux输入子系统:事件的编码输入系统协议用类型types和编码codecs来表示输入设备的值并用此来通知用户空间的应用程序。
这篇文档对这些类型和编码进行了说明并且指出什么时候和如何使用这些类型和编码。
一个单一的硬件事件可以产生多个输入事件,每个输入事件包含一个单一数据项的新的数据值。
EV_SYN是一个特别的事件类型,它用来把同一时刻产生的多个输入数据分割为多个数据包。
在下面的描述中,术语事件(event)是指一个涵盖类型,编码和参数值的单一输入事件。
input协议是一个基于状态的协议,只有当相应事件编码对应的参数值发生变化时才会发送该事件。
不过,状态是由Linux的输入子系统进行维护,驱动程序无需维护输入的状态,就算参数值没有变化时向输入子系统发出事件也不会有问题。
用户空间可以用linux/input.h 中定义的EVIOCG*ioctls来获得当前事件编码和参数的状态。
设备的所支持的上报事件种类也可以通过sysfs的class/input/event*/device/capabilities/来获取,设备的特性和可以通过class/input/event*/device/properties来获取。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本文由DroidPhone 翻译:/droidphone Kernel版本:V3.4.10~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Event types:===========types对应于一个相同逻辑输入结构的一组Codes。
每个type都有一组可用的codes用于产生输入事件。
每个type可用的codes的详细信息请参考Codes一节的内容。
inux 混杂设备外部中断和输入子系统
Linux 混杂设备、外部中断和输入子系统Linux驱动开发2010-08-14 10:59:59 阅读22 评论0字号:大中小混杂设备也是一种字符设备,主设备号固定为10。
相对于普通字符设备驱动,它不需要自己去生成设备文件。
1、声明使用的头文件#include <linux/miscdevice.h>2、定义一个混杂设备:static struct miscdevice miscDevice = {.minor = MISC_DYNAMIC_MINOR, //自动分配从设备号.name = "设备名称",.fops = &dev_fops, //设备文件操作指针};3、注册混杂设备:misc_register(&miscDevice) //成功返回04、注销混杂设备:misc_deregister(&miscDevice);在驱动中使用外部中断1、声明头文件#include <linux/interrupt.h>#include <mach/irqs.h>2、申明中断处理程序static irqreturn_t handler(int irq,void *dev_ID){... ....return IRQ_RETV AL(IRQ_HANDLED);}中断处理程序不能用户空间发送或接收数据,以及使用引起阻塞或调度的函数。
在中断处理函数中分配内存要使用GFP_ATOMIC标志,避免中断处理函数进入睡眠。
3、注册中断request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void*dev) //成功返回返回0irq:中断号handler:中断处理程序flags:与中断相关的标志IRQF_TRIGGER_RISING:上升沿触发IRQF_TRIGGER_FALLING:下降沿触发IRQF_TRIGGER_HIGH:高电平触发IRQF_TRIGGER_LOW:低电平触发IRQF_SAMPLE_RANDOM:为系统随机发生器提供支持IRQF_SHARED:中断可在设备间共享IRQF_DISABLED:是否快速中断name:中断名称dev:主要用于共享中断,可通过该参数向中断处理程序传递设备号或其它参数4、注销中断:free_irq(unsigned int irq)5、其它:disable_irq(unsigned int irq)enable_irq(unsigned int irq)输入子系统input子系统:1、头文件:#include <asm/bitops.h>#include <linux/input.h>2、申明static struct input_dev *input_Dev3、初始化input_Dev = input_allocate_device();input_Dev->name = "名称";input_Dev->id.bustype = BUS_HOST; //总线类型BUS_PCIBUS_ISAPNPBUS_USBBUS_HILBUS_BLUETOOTHBUS_VIRTUALBUS_ISABUS_I8042BUS_XTKBDBUS_RS232BUS_GAMEPORTBUS_PARPORTBUS_AMIGABUS_ADBBUS_I2CBUS_HOSTBUS_GSCBUS_ATARIinput_Dev->id.vendor = 供应商代码;input_Dev->id.version = 版本;set_bit(EV_KEY,input_Dev->evbit); //支持按键事件类型EV_KEY :按键EV_REL :相对坐标EV_ABS:绝对坐标EV_SND:声音EV_FF:力反馈... ...set_bit(KEY_A,input_Button->keybit); //设置支持按键A4、注册输入设备input_register_device(struct input_dev *dev);5、报告输入事件input_report_key(struct input_dev *dev, unsigned int code, int value) code:事件代码,可在input.h中查询相关值value:事件值,如果是按键类型,按下为1,松开为0事件同步,告知input core,驱动已发出一次完整的报告。
Linux系统调用详细全过程
6
系统命令、内核函数
系统调用与系统命令
系统命令相对API来说,更高一层。每个系统命令
都是一个执行程序,如ls命令等。这些命令的实现
调用了系统调用。
系统调用与内核函数
系统调用是用户进入内核的接口层,它本身并非内
核函数,但是它由内核函数实现。
进入内核后,不同的系统调用会找到各自对应的内
常,CPU便被切换到内核态执行内核函
数,转到了系统调用处理程序的入口:
system_call()。
int $0x80指令将用户态的执行模式转变为内
核态,并将控制权交给系统调用过程的起点
system_call()处理函数。
4
system_call()函数
system_cal()检查系统调用号,该号码告诉内核
SYMBOL_NAME(sys_exit)
.long
.longSYMBOL_NAME(sys_read)
SYMBOL_NAME(sys_fork)
.long
.longSYMBOL_NAME(sys_write)
SYMBOL_NAME(sys_read)
.long
.longSYMBOL_NAME(sys_open)
SYMBOL_NAME(sys_write)
.long
.long
…… SYMBOL_NAME(sys_open)
……
……
……
.long
SYMBOL_NAME(sys_getuid)
.long SYMBOL_NAME(sys_getuid)
* 4
+
21
系统调用的返回
当服务例程结束时,system_call( ) 从eax
Linux输入子系统:多点触控协议
Linux输入子系统:多点触控协议Multi-touch (MT) Protocol-------------------------Copyright(C) 2009-2010 Henrik Rydberg<*******************>简介------------为了发挥新近的多点触摸和多用户设备的强大功能,为多点触摸定义一种上报详细数据的方法(比如有多个物体直接接触到设备的表面),是非常有必要的。
这篇文档描述了多点触摸协议(multi-touch,MT),是的内核驱动可以对多个随意数量的触控事件上报详细的数据信息。
基于硬件的能力,该协议被分为两种类型。
对于只能处理匿名接触(type A)的设备,该协议描述了如何把所有的原始触摸数据发送给接收者。
对于那些有能力跟踪并识别每个触摸点的设备(type B),该协议描述了如何把每个触摸点的单独更新通过事件slots发送给接受者。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本文由DroidPhone 翻译:/droidphoneKernel版本:V3.7~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~协议的使用--------------详细的触控信息被按顺序地分割为多个ABS_MT事件数据包进行发送。
只有ABS_MT事件信息被识别为触控数据包的一部分,因为这些事件在当前的单点触控(single-touch,ST)应用中是被忽略掉的,我们可以在现有的驱动中基于ST协议之上来实现MT协议。
对于type A设备的驱动,在每个数据包的结尾用input_mt_sync()对多个触控包进行分割,这将会产生一个SYN_MT_REPORT事件,它通知接收者接受当前的触控信息并准备接收下一个信息。
linux输入子系统详解
1.1 重要的数据结构
在输入子系统的设备驱动中,最重要的数据结构是struct input_dev,
如程序清单 1.1所示。需要完成的大部分工作都是围绕着它来的,它是驱动
的主体。每个struct input_dev代表一个输入设备。
/*最后一次同步后没有新的事件置1*/
int sync;
/* 当前各个坐标的值*/
/* 获取扫描码的键值,可选*/
int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
struct ff_device *ff;
/* 最近一次按键值,用于连击 */
/* led*/
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
/* beep*/
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
/* 支持的按键值的个数*/
unsigned int keycodemax;
/* include/linux/input.h */
struct input_event {
/* 时间戳 */
struct timeval time;
/* 事件类型 */
__u16 type;
/* 事件代码 */
linux输入输出重定向及案例
linux输⼊输出重定向及案例重定向什么是重定向?将原本要输出在屏幕中的内容,重新定向输出到指定的⽂件或设备中。
** 为什么要使⽤重定向?**1.备份时,我们需要知道备份的结果2.屏幕上输出信息,⽐较重要的时候,我们想要保存下来3.定时任务,我们需要知道结果4.执⾏命令时,明知道会报错,我们会使⽤重定向,将结果放⼊ /dev/null5.执⾏命令时,正确结果和错误结果会同时输出,将正确结果输出到常规⽇志,将错误结果输出到错误⽇志重定向的分类标准输⼊标准输出名称⽂件描述符作⽤标准输⼊(stdin)0通常键盘(其他输⼊命令的终端设备)标准输出(stdout)1默认输出到屏幕错误输出(stderr)2默认输出到屏幕⽂件名(filename)3+-[root@localhost ~]# ll /dev/std*lrwxrwxrwx 1 root root 15 3⽉ 25 10:36 /dev/stderr -> /proc/self/fd/2lrwxrwxrwx 1 root root 15 3⽉ 25 10:36 /dev/stdin -> /proc/self/fd/0lrwxrwxrwx 1 root root 15 3⽉ 25 10:36 /dev/stdout -> /proc/self/fd/1[root@localhost ~]# ll /proc/121169/fd/总⽤量 0lrwx------ 1 root root 64 4⽉ 7 11:28 0 -> /dev/pts/3lrwx------ 1 root root 64 4⽉ 7 11:28 1 -> /dev/pts/3lrwx------ 1 root root 64 4⽉ 7 11:27 2 -> /dev/pts/3lr-x------ 1 root root 64 4⽉ 7 11:28 3 -> /var/log/messages输出重定向/dev/null/dev/pts/0/dev/pts/1/tmp/zls.txt/root/1.txt类型符号⽤途备注标准覆盖输出重定向1>将命令执⾏的正确结果默认输出的位置,修改为指定的⽂件或者终端(覆盖原有内容)通常'>'即可,1可以不写,默认就是1标准追加输出重定向>>将命令执⾏的正确结果,输出到指定⽂件的末尾(不覆盖原有内容)-错误覆盖输出重定向2>将命令执⾏的错误结果默认输出的位置,修改为指定的⽂件或者终端(覆盖原有内容)-错误追加输出重定向2>>将命令执⾏的错误结果,输出到指定⽂件的末尾(不覆盖原有内容)-标准输⼊重定向0<将命令中接收输⼊内容由默认的键盘,改为命令或者⽂件通常'<'即可0可以写也可以不写,默认0标准输⼊追加重定向0<<将命令中接收输⼊内容由默认的键盘,改为命令或者⽂件-# 标准覆盖输出重定向[root@localhost ~]# echo wxx>/tmp/1.txt[root@localhost ~]# cat /tmp/1.txtwxx[root@localhost ~]# echo 321>/tmp/2.txt[root@localhost ~]# cat /tmp/2.txt[root@localhost ~]# echo wxx1>/tmp/3.txt[root@localhost ~]# cat /tmp/3.txtwxx1**标准追加输出重定向**标准追加输出重定向[root@localhost ~]# echo 456 >> /var/log/messages[root@localhost ~]# echo 123 >> /var/log/messages**错误输出重定向**错误输出重定向[cdx@localhost ~]$ find /etc/ -type d**将标准输出和错误输出都输出到相同的⽂件中**将标准输出和错误输出都输出到相同的⽂件中[cdx@localhost ~]$ find /etc/ -type d > /tmp/100.txt 2>&1[cdx@localhost ~]$ find /etc/ -type d &> /tmp/101.txt**将错误输出,重定向到⿊洞**将错误输出,重定向到⿊洞[root@localhost ~]# ls / /ooo 2>/dev/null**脚本中使⽤重定向**脚本中使⽤重定向!/bin/bash. /etc/init.d/functionsread -p "请输⼊要检测的IP:" IPping -c1 -W1 $IP &>/dev/nullif [ ? -eq 0 ];then action "IP" /bin/true >> /tmp/IP_OK.txtelseaction "$IP" /bin/false >> /tmp/IP_FAILD.txtfi输⼊重定向[root@localhost ~]# mail -s "$(date +%F-%T)_test" 11111@ < /etc/passwd[root@localhost opt]# echo -e "111\n222\n333" > file1.txt[root@localhost opt]# cat file1.txt111222333[root@localhost opt]# echo '1111222233334444' > file2.txt[root@localhost opt]# cat >> 1.txt <<EOF> aaa> bbb> ccc> ddd> EOF[root@localhost opt]# cat >> 2.txt111222333444Ctrl + d 结束cat <<EOF+--------------------------+| vmware manager |+--------------------------+| by wxx |+--------------------------+| 1. Install KVM || 2. Install or Reset C6.5 || 3. Install or Reset C7.4 || 5. Instqll or Reset W7 || 6. Remove all || q. quit |+--------------------------+EOF[root@localhost opt]# cat <<EOF> 1.install mysql> 2.install nginx> 3.intsall php> 4.install tomcat> 5.install redis> EOF1.install mysql2.install nginx3.intsall php4.install tomcat5.install redis# 两条命令同时重定向[root@localhost opt]# (ls ; date) > 1.txt(while :; do date; sleep 2; done) &>date.txt &#如果不希望某些命令的执⾏对当前 shell 环境产⽣影响,请在subshell中执⾏[root@localhost ~]# (cd /boot; ls)管道技术管道操作符号:|,叫做管道符作⽤:将管道符左边命令的标准输出,交给管道符右边命令的标准输⼊来处理⽤法:cmd1|cmd2|cmd3| cmd4...# 取出passwd⽂件中,uid最⼤的前五个[root@localhost ~]# sort -nr -k 3 -t ':' /etc/passwd|head -5# 统计出passwd⽂件中,所有⽤户的shell种类[root@localhost ~]# awk -F: '{print $7}' /etc/passwd|sort |uniq|wc -l6[root@localhost ~]# hostname -I10.0.0.200[root@localhost ~]# ifconfig |awk 'NR==2{print $2}'10.0.0.200sedawkgrep组合:sed awkgrep awk10种⽅法,取IP# 取出磁盘已使⽤百分⽐[root@localhost ~]# df -h|awk '{print $5}'|awk -F '%' '{print $1}'已⽤912451# tee 和重定向的区别tee会将输出结果显⽰在屏幕上[root@zls ~]# date > date.txt[root@zls ~]# date |tee date.txt#xargs:将管道前⾯的结果当成管道后⾯命令的参数[root@localhost opt]# find /etc/ -name '*.conf'|xargs cp -t /tmp/⼗种⽅式取ip⼗种⽅法取ip[root@wzh ~]# ifconfig|awk 'NR==2 {print $2}'10.0.0.200[root@wzh ~]# ifconfig|sed -nr '2s#.*et (.*) ne.*#\1#gp'10.0.0.200[root@wzh ~]# ifconfig|grep -w 'broadcast'|cut -d ' ' -f1010.0.0.200[root@wzh ~]# ifconfig|sed -n '2p'|awk '{print $2}'10.0.0.200[root@wzh ~]# ifconfig|grep -w 'broadcast'|sed -r 's#.*et (.*) ne.*#\1#g'10.0.0.200[root@wzh ~]# ifconfig |head -2|tail -1|cut -d ' ' -f1010.0.0.200[root@wzh ~]# ifconfig|grep -w 'broadcast'|cut -c 14-2410.0.0.200[root@wzh ~]# ifconfig|awk 'NR==2'|cut -d 't' -f2|cut -d 'n' -f110.0.0.200[root@wzh ~]# ifconfig|sed -n '2p'|grep -o '[0.-9]*'|head -110.0.0.200[root@wzh ~]# ifconfig|sed -n '2p'|cut -d ' ' -f1010.0.0.200练习题01.复制/etc/passwd⽂件到当前⽬录下,把⽂件中的:替换成#,不能使⽤sed和vim命令。
Linux输入子系统(Input Subsystem)
Linux输入子系统(Input Subsystem)Linux 的输入子系统不仅支持鼠标、键盘等常规输入设备,而且还支持蜂鸣器、触摸屏等设备。
本章将对Linux 输入子系统进行详细的分析。
一前言输入子系统又叫input 子系统。
其构建非常灵活,只需要调用一些简单的函数,就可以将一个输入设备的功能呈现给应用程序。
二设备驱动层本节将讲述一个简单的输入设备驱动实例。
这个输入设备只有一个按键,按键被连接到一条中断线上,当按键被按下时,将产生一个中断,内核将检测到这个中断,并对其进行处理。
该实例的代码如下:#include <asm/irq.h>#include <asm/io.h>static struct input_dev *button_dev; /*输入设备结构体*/static irqreturn_t button_interrupt(int irq, void *dummy) /*中断处理函数*/ {input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1); /*向输入子系统报告产生按键事件*/input_sync(button_dev); /*通知接收者,一个报告发送完毕*/return IRQ_HANDLED;}static int __init button_init(void) /*加载函数*/{int error;if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) /*申请中断,绑定中断处理函数*/{printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);return -EBUSY;}button_dev =input_allocate_device(); /*分配一个设备结构体*///input_allocate_device()函数在内存中为输入设备结构体分配一个空间,并对其主要的成员进行了初始化.if (!button_dev){printk(KERN_ERR "button.c: Not enough memory\n");error = -ENOMEM;goto err_free_irq;}button_dev->evbit[0] = BIT_MASK(EV_KEY); /*设置按键信息*/button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);//分别用来设置设备所产生的事件以及上报的按键值。
基于Linux内核输入子系统的驱动研究
基于Linux内核输入子系统的驱动研究刘少平【摘要】Linux is popular with its complete open characteristic and fine performance. After issuing its kernel subsystem, it makes more benefits for driver design in embedded area. The foundation of the device driver with Linux is introduced and detailed expatiates how to process the device driver based of the Linux kernel subsystem. Exampling of the touch screen, the paper analyzes and studies the driver processing. Using the input subsystem interface function, we will be more convenient to realize the device driver.%Linux因其完全开放的特性和稳定优良的性能深受欢迎,当推出了内核输入子系统后,更方便了嵌入式领域的驱动开放。
介绍了Linux的设备驱动基础。
详细阐述了基于Linux内核输入子系统下的设备驱动实现流程和构架。
并以触摸屏为例,对驱动过程进行了分析研究。
利用输入子系统的接口函数,将更方便的实现设备驱动。
【期刊名称】《电子设计工程》【年(卷),期】2012(020)017【总页数】3页(P29-31)【关键词】Linux;子系统;驱动;触摸屏【作者】刘少平【作者单位】陕西烽火电子股份有限公司,陕西宝鸡721006【正文语种】中文【中图分类】TP302嵌入式技术在工业和日常生活中变得越来越普及,Linux作为是目前最流行的操作系统之一,在桌面系统、服务器领域都有大量用户,在嵌入式领域也备受青睐。
linux输入子系统的认识
struct pm_dev *pm_dev;
int state;
int sync;
int abs[ABS_MAX + 1];
int rep[REP_MAX + 1];
unsigned long key[NBITS(KEY_MAX)];
3.驱动通常提供底层硬件的接口,例如 USB, PCI memory或者 I/O regions,或者 serial port I/O regions。
除了管理驱动和 handlers, input core也导出了一些有用的 /proc文件系统接口,用于查看当前活动的设备和事件 handlers。下面是查看 usb鼠标的例子 (cat /proc/bus/input/devices):
struct file *file);
int (*flush)(struct input_dev *dev,
struct file *file);
int (*event)(struct input_dev *dev,
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="Example 1 device"
P: Phys=A/Fake/Path
H: Handlers=kbd event3
B: EV=3
B: KEY=10000 40000000
如果我想从设备驱动发送事件到 input core,我们需要调用 input_event()或者更便利的封装函数,例如 input_report_key()/input_report_abs(),在 include/linux/input.h里定义。示例 listing 3使用了这些函数。
详细解读Linux的输入子系统
详细解读Linux的输入子系统
1. 简介
这时一组驱动的集合,它们可以用于所有的基于linux的输入设备,虽然目前它只是用于USB输入设备,将来(2.5、2.6版本)它们将会被扩展并替换掉现存的多数输入系统,这就是为什么它们被放在drivers/input/目录下,而不是drivers/usb/。
输入设备驱动的核心是input模块,它需要在其他输入模块之前被加载--它是输入系统其它两个模块之间通讯的桥梁:
1.1 设备驱动(Device drivers)
这些模块负责和实际的硬件打交道(例如通过USB),给input模块提供相应的事件(按键,鼠标移动)
1.2 事件处理模块(Event handlers)
这些模块从input模块获得事件信息,并根据需要通过不同的接口传递这些事件--往kernel 传递按键事件,或者通过模拟的PS/2接口给GPM和X传递鼠标移动事件,等等。
2. 一个简单的例子
通常,对于大多数配置来说,系统有一个USB鼠标和一个USB键盘,你需要加载以下几个模块(或者把它们编译到内核中):
input
mousedev
keybdev
usbcore
uhci_hcdor ohci_hcd or ehci_hcd
usbhid
在这之后,USB键盘直接就可以工作了,USB鼠标会作为一个字符设备,主次设备号分别为13和63:
crw-r--r-- 1 root root 13, 63 Mar 28 22:45 mice
你需要主动创建该鼠标设备节点,创建的命令如下:
cd/dev。
Linux输入子系统:怎样使用输入设备编程
1.新建一个输入设备驱动程序
1.0一个最简单的例子
本文由DroidPhone翻译:http://blog.csdn/droidphoneKernel版本:V3.4.10
以下是一个非常简单的输入设备驱动程序。该设备只有一个按键,它通过BUTTON_PORT这一i/o端口访问,当按下或释放该按键,会发生BUTTON_IRQ中断,驱动程序看起来就像这样:
error = -ENOMEM;
goto err_free_irq;
}
button_dev->evbit[0] = BIT_MASK(EV_KEY);
button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
error = input_register_device(button_dev);
printk(KERN_ERR "button.c: Cant allocate irq %d\n", button_irq);
return -EBUSY;
}
button_dev = input_allocate_device();
if (!button_dev) {
printk(KERN_ERR "button.c: Not enough memory\n");
input_register_device(
这会把button_dev结构添加到input driver的全局链表中,调用device handler模块中的_connect函数来通知他一个新的设备出现了。input_register_device()可能会休眠,所以他不能在中断或者持有一个spinlock的情况下被使用。
Linux下USB 输入子系统的学习(以鼠标驱动为例)
Linux下USB 输入子系统的学习(以鼠标驱动为例)Linux下USB 输入子系统的学习(以鼠标驱动为例)usb 1-1.2: new low speed USB device using musb_hdrc and address 3usb 1-1.2: Product: USB Optical Mouseinput: USB HID v1.11 Mouse [USB Optical Mouse] on usb-musb_hdrc-1.2//drivers/usb/input/hid-core.c>hid_probe(){printk(“: USB HID v%x.%02x %s [%s] on %s\n”,hid->version >> 8, hid->version & 0xff, c, hid->name, path);}//drivers/input/mouse/sermouse.c---->sermouse_connect()printk(KERN_INFO “input: %s on %s\n”, sermouse_protocols[sermouse->type], serio->phys);/proc/bus/input # cat devicesI: Bus=0003 Vendor=0461 Product=4d15 Version=0200N: Name=“USB Optical Mouse”P: Phys=usb-musb_hdrc-1.1/input0H: Handlers=mouse1B: EV=fB: KEY=70000 0 0 0 0 0 0 0 0B: REL=103B: ABS=100 0驱动层负责和底层的硬件设备打交道,将底层硬件对用户输入的响应转换为标准的输入事件以后再向上发送给Input Core。
精通Linux设备驱动程序开发-第7章-输入设备驱动
第7章 输入设备驱动内核的输入子系统是为了对分散的、多种不同类别的输入设备(如键盘、鼠标、跟踪球、操纵杆、辊轮、触摸屏、加速计和手写板)进行统一处理的驱动。
输入子系统带来了如下好处:•统一了物理形态各异的相似的输入设备的处理功能。
例如,各种鼠标,不论PS/2、USB,还是蓝牙,都被同样处理。
•提供了用于分发输入报告给用户应用程序的简单的事件(event)接口。
你的驱动不必创建、管理/dev节点以及相关的访问方法。
因此它能很方便的调用输入API以发送鼠标移动、键盘按键,或触摸事件给用户空间。
X Windows这样的应用程序能够无缝地运行于输入子系统提供的event接口之上。
•抽取出了输入驱动的通用部分,简化了驱动,并提供了一致性。
例如,输入子系统提供了一个底层驱动(成为serio)的集合,支持对串口和键盘控制器等硬件输入设备的访问。
图7.1展示了输入子系统的操作。
此子系统包括一前一后运行的两类驱动:事件驱动和设备驱动。
事件驱动负责和应用程序的接口,而设备驱动负责和底层输入设备的通信。
鼠标事件产生者mousedev,是前者的实例;而PS/2鼠标驱动是后者的实例。
事件驱动和设备驱动都可以利用输入子系统的高效、可重用的核心提供的服务。
图 7.1. 输入子系统事件驱动是标准的,对所有的输入类都是可用的,所以你更可能的是实现设备驱动而不是事件驱动。
你的设备驱动可以利用一个已经存在的、合适的事件驱动通过输入核心和用户应用程序接口。
需要注意的是本章使用的名辞“设备驱动”指的是输入设备驱动,而不是输入事件驱动。
输入事件驱动输入子系统提供的事件接口已经发展成为很多图形窗口系统理解的标准。
事件驱动提供一个硬件无关的抽象,以和输入设备交互;如同帧缓冲接口(在第12章《视频设备驱动》中讨论)提供一个通用的机制以和显示设备通信一样。
事件驱动和帧缓冲驱动一起,将图形用户接口(GUI)和各种各样的底层硬件隔离开来。
Evdev接口Evdev是一个通用的输入事件驱动。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux input 子系统详解与代码示例李邦柱于杭州2014/01/09Email:helpylee@ 由于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)为鼠标中键.其它代码含义请参看include/linux/input.h文件. 如果事件的类型代码是EV_REL,code值表示轨迹的类型.如指示鼠标的X轴方向REL_X(代码为0x00),指示鼠标的Y轴方向REL_Y(代码为0x01),指示鼠标中轮子方向REL_WHEEL(代码为0x08).type:EV_KEY,键盘EV_REL,相对坐标EV_ABS,绝对坐标value:事件的值.如果事件的类型代码是EV_KEY,当按键按下时值为1,松开时值为0;如果事件的类型代码是EV_ REL,value的正数值和负数值分别代表两个不同方向的值./** Event types*/#define EV_SYN 0x00#define EV_KEY 0x01 //按键#define EV_REL 0x02 //相对坐标(轨迹球)#define EV_ABS 0x03 //绝对坐标#define EV_MSC 0x04 //其他#define EV_SW 0x05#define EV_LED 0x11 //LED#define EV_SND 0x12//声音#define EV_REP 0x14//repeat#define EV_FF 0x15#define EV_PWR 0x16#define EV_FF_STATUS 0x17#define EV_MAX 0x1f#define EV_CNT (EV_MAX+1)这里事件指的是我们对外设的操作,比如按键一次a可能就产生数个input_event数据3.代码示例:此代码可以完全正确编译运行。
把此代码拷贝到xx.c文件中,gccxx.c –o xx 后要用sudo 去执行。
Sudo ./xx此程序的功能是可以及时捕获键盘消息,鼠标消息和其他外设出发的消息。
比如可以记录键盘事件。
下图就是此程序运行后成功捕获到键盘和鼠标消息的截图。
本程序采用I/O多路复用技术。
#include<stdlib.h>#include <stdio.h>#include <sys/time.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <linux/input.h>#include<string.h>intb_cur_x = 0, b_cur_y = 0;typedefenum {BlcTermKeyDevStat_Default = 1, // 所有键值的默认状态或鼠标的坐标移动状态BlcTermKeyDevStat_Down = 2, // 所有键值的按下状态BlcTermKeyDevStat_Up = 3, // 所有键值的弹起状态BlcTermKeyDevStat_MouseWheel = 4, // 鼠标滚轮转动BlcTermKeyDevStat_ConsoleLeftAXIS = 5, // 游戏手柄左摇杆坐标操作BlcTermKeyDevStat_ConsoleRightAXIS = 6, // 游戏手柄右摇杆坐标操作BlcTermKeyDevStat_MouseDoubleClick = 7, // 鼠标左键双击}BlcTermKeyDevStat;typedefenum {BlcPlayCtl_EventID_Login = 3001,BlcPlayCtl_EventID_Logout = 3002,BlcDmxFilter_EventID_TSData = 3003,BlcKey_EventID_KeyValue = 3004,BlcPlayCtl_EventID_MwReturn = 3005,BlcRes_EventID_ResoureRequest = 3006,BlcRes_EventID_ServiceNotice = 3007,BlcPlayCtl_EventID_ConnectServer = 3008,BlcKey_EventID_KeyDevPlug = 3101, } Blc_EventID;typedefenum {BlcKeyDevPlugType_KeyboardPlugin = 1,BlcKeyDevPlugType_KeyboardPlugout = 2, BlcKeyDevPlugType_MousePlugin = 3, BlcKeyDevPlugType_MousePlugout = 4, BlcKeyDevPlugType_ConsolePlugin = 5, BlcKeyDevPlugType_ConsolePlugout = 6,} BlcKeyDevPlugType;typedefenum {BlcTermKeyDevType_Irr = 1,BlcTermKeyDevType_Keyboard = 2,BlcTermKeyDevType_Mouse = 3,BlcTermKeyDevType_Console = 4,} BlcTermKeyDevType;typedefenum {BlcMousePropertyValue_DEFAULT = 0, BlcMousePropertyValue_BUTTONLEFT = 1, BlcMousePropertyValue_BUTTONMIDDLE = 2, BlcMousePropertyValue_BUTTONRIGHT = 3, } BlcMouseKeyValue;typedefstruct {intkeydev; //键值设备类型intkeystate; // 键值状态;intkeyvalue; // 键值short x; //鼠标的x坐标short y; //鼠标的y坐标} BlcKeyValueData;structinput_eventev_temp;intfunc(intfd){BlcKeyValueDatakey_info;int count;intplug_flag = BlcKeyDevPlugType_MousePlugout;// structinput_eventev_temp;if(fd != -1) {plug_flag = BlcKeyDevPlugType_MousePlugin;}char up[] = "抬起";char down[] = "按下";//while(1)count = read(fd, &ev_temp, sizeof(structinput_event));if(count > 0){if(ev_temp.type == EV_SYN)return 1;printf("$$$$$$$$$$$$$$$: %d, %d, %d\n", ev_temp.type, ev_temp.code, ev_temp.value);printf("key:%d ", ev_temp.code);printf("%s\n", ev_temp.value?down:up);memset(&key_info, 0 , sizeof(BlcKeyValueData));if (ev_temp.type == EV_KEY){if (ev_temp.code>= 0 &&ev_temp.code<= 127){key_info.keydev = BlcTermKeyDevType_Keyboard;key_info.keyvalue = ev_temp.value;}else if (ev_temp.code>= 0x110 &&ev_temp.code<= 0x116){key_info.keydev = BlcTermKeyDevType_Mouse;if (ev_temp.code == 0x110)key_info.keyvalue = BlcMousePropertyValue_BUTTONLEFT;else if (ev_temp.code == 0x111)key_info.keyvalue = BlcMousePropertyValue_BUTTONRIGHT;else if (ev_temp.code == 0x112)key_info.keyvalue = BlcMousePropertyValue_BUTTONMIDDLE;}if (ev_temp.value == 1)key_info.keystate = BlcTermKeyDevStat_Down;else if (ev_temp.value == 0)key_info.keystate = BlcTermKeyDevStat_Up;key_info.x = -1;key_info.y = -1;}else if (ev_temp.type == EV_REL){key_info.keydev = BlcTermKeyDevType_Mouse;key_info.keystate = BlcTermKeyDevStat_Default;key_info.keyvalue = 0;if (ev_temp.code == REL_X)b_cur_x += ev_temp.value;else if (ev_temp.code == REL_Y)b_cur_y += ev_temp.value;else if (ev_temp.code == REL_WHEEL);//???//key_info.keyvalue = ev_temp.code;if (b_cur_x< 0) b_cur_x = 0;if (b_cur_x> 1280) b_cur_x = 1280;if (b_cur_y< 0) b_cur_y = 0;if (b_cur_y> 720) b_cur_y = 720;key_info.x = b_cur_x;key_info.y = 0 - b_cur_y;}printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@: %d, %d, %d\n", key_info.keydev, key_info.keyvalue, key_info.keyvalue);}else if (count == -1){if (plug_flag == BlcKeyDevPlugType_MousePlugin){close(fd);plug_flag = BlcKeyDevPlugType_MousePlugout;printf("plug out !\n");}if (fd != -1){plug_flag = BlcKeyDevPlugType_MousePlugin;printf("plug int ok !\n");}else{printf("plug int fail !\n");usleep(500);}}//}}int main(void){intfd_key,fd_ts, fd_led, fd_max, fd_0, fd_2, fd_3;structinput_eventevent_key,event_ts;intdac_value;structtimevalselect_timeout;fd_setreadfds;select__sec = 20;select__usec = 0;fd_0 = open("/dev/input/event0", O_RDWR);fd_key = open("/dev/input/event1", O_RDWR);fd_2 = open("/dev/input/event2", O_RDWR);fd_3 = open("/dev/input/event3", O_RDWR);fd_ts= open("/dev/input/event4", O_RDWR);if (fd_key>fd_ts)fd_max = fd_key;elsefd_max = fd_ts;while(1){ FD_ZERO(&readfds);FD_SET(fd_key, &readfds);FD_SET(fd_ts, &readfds);FD_SET(fd_0, &readfds);FD_SET(fd_2, &readfds);FD_SET(fd_3, &readfds);select__sec= 2;select__usec = 0;select(fd_max + 1, &readfds, NULL, NULL, &select_timeout); if(FD_ISSET(fd_0, &readfds)){printf("come from fd_0\n");func(fd_0);}if(FD_ISSET(fd_2, &readfds)){printf("come from fd_2\n");func(fd_2);}if(FD_ISSET(fd_3, &readfds)){printf("come from fd_3\n");func(fd_3);}if ( FD_ISSET(fd_key, &readfds)){printf("come from keyborad\n");func(fd_key);}else if(FD_ISSET(fd_ts, &readfds)) {printf("come from mouse\n");func(fd_ts);}printf("|\n|\n");}}。