精华内容
下载资源
问答
  • Problem Description Consider the aggregate An= { 1, 2, …, n }. For example, A1={1}, A3={1,2,3}. A subset sequence is defined as a array of a non-empty subset. Sort all the subset sequece of An in ...
  • Problem Description Beside other services, ACM helps companies to clearly state their “corporate identity”, which includes company logo but also other signs, like trademarks. One of such companies ...
  • 编写无溢出除法汇编子程序

    万次阅读 多人点赞 2013-12-21 00:15:11
    为了说明我们为什么需要自己写一个实现除法的子程序,还得从除法为什么会发生溢出说起。 在汇编中,如果要使用除法运算,我们可以使用div指令,它实现就是除法功能,但是它是一个非常容易,甚至说不可避免会...
    一、为什么除法会溢出
    看到这个标题,你可能会问汇编中不是有div指令来实现除法运算吗?为什么我们还要自己写一个子程序来实现除法?为了说明我们为什么需要自己写一个实现除法的子程序,还得从除法为什么会发生溢出说起。

    在汇编中,如果要使用除法运算,我们可以使用div指令,它实现的就是除法的功能,但是它是一个非常容易,甚至说不可避免会发生溢出的指令,下面来看看它的工作方式,我们就能知道个中源由。注:这里所说的除法溢出并不是指分母为0而发生溢出的情况。

    div的工作方式:
    (1)除数:有8位和16位两种,在一个寄存器或内存单元中
    (2)被除数:默认放在AX或DX和AX中,如果除数为8位,则被除数为16位,默认在AX中存放;如果除数为16位,被除数为32位,在DX和AX中存放,DX存放高16位,AX存放低16位
    (3)结果:如果除数为8位,则AL(AX的低8位)存储除法操作的商,AH(AX的高8位)存储除法操作的余数;如果除数为16们,则AX存储除法操作的商,DX存放除法操作的余数。

    用一个表格来表示上述的工作方式,如下表所示:
    除数
    被除数
    结果
    8位
    16位,AX
    商:AL,余数:AH
    16位
    32位,DX(高16位)+AX(低16位)
    商:AX,余数:DX

    就这么一看似乎还没有什么问题,下面我就以一个例子来说明一下种工作方式下的除法的致命缺陷。

    为了更加容易地说明,我们以除数为8位的情况来说明,假设我们的被除数为65535(16位的最大值)存储在AX中,除数为1,存储在CL中,然后执行除法指令: div CL。根据上面的说法,结果都是放在AX中的,余数为0,当然这没有问题,然而商为65535要放在AL中却是放不下的,因为AL能存放的最大值只为255,所以此时就会发生溢出。我们可以看到65535/1 = 255,这显然与我位正常的除法结果不符。

    在这里你可以认为我举了一个非常极端的例子,但是这种情况却并不是极端的情况,对于除数为8位的除法,只要商在255以上就会发生这种溢出。除数为16位的原理及情况与这里相同,只是它是当商为65535以上是就会发生溢出而已。

    二、如何解决这个溢出问题
    既然我们知道了问题的根源,要解决它就不困难了。为了统一而且不发生溢出,我们可以把所有的除法的商都用32位来保存,即所有的被除数都用32位,所有的除数都用16位,所有的商都用32位,所有的余数都用16位来保存,就可以解决这个问题,因为一个数除以一个整数后,不可能大于其之前的值。而对于8位的除法,除数和被除数的高位全用0补全即可。为了达到这个目的,我们就不能使用默认的除法指令div了,而需要我们写代码来实现我们自定义的除法。

    考虑到除法是一个常用的操作,所以我们可以编写一个子程序来实现除法,在进行除法运算时,直接调用我们自己定义的子程序来完成任务,而不直接使用div指令。

    三、如何实现这个功能
    要实现除法还得使用div指令,只是我们可以做一些特殊的处理,让我们自定义的除法不发生溢出,因为我们使用的是除数为16位的除法,也就是说,我们只要能保证除法的商不大于65535就不会发生问题。为了实现这个功能,我们首先要知道一个关于除法的公式(H表示X的高位,L表示X的低位):
    X/N = int(H/N)* 2^16 + [rem(H/N)* 2^16+L]/N

    这个公式告诉我们32位的被除数与16位的除数,可以拆分为两个除数和被除数都为16位的数的除法,然后通过加法来得到同样的结果,这个是非常重要的。因为我们可以把H和L独立起来考虑,当进行H/N时,因为H存储在DX中,我们可以先把DX中的内容复制到AX中(操作之前把AX的内容保存好),再把DX的内容置为0,这样产生的除法操作的商就一定能放在一个16位的寄存器AX中。对于公式中的其他除法运算也采用相同的操作,然后通过把除法之前产生的结果进行相加,就能产生我们的无溢出除法子程序。

    四、实现代码
    基于这个公式,我们实现的代码如下:
    ;子程序名称:divdw
    ;功能:进行不会产生溢出的除法运算,被除数为dword型
    ;	   除数为word型,结果为dword型
    ;参数:	(ax)=dword型数据的低16位
    ;		(dx)=dword型数据的高16位
    ;		(cx)=除数
    ;返回:	(dx)=结果的高16位,(ax)=结果的低16位
    ;		(cx)=余数
    ;计算公式:X/N=int(H/N)*2^16+[rem(H/N)*2^16+L]/N
    divdw:
    	jcxz divdw_return	;除数cx为0,直接返回
    	push bx			;作为一个临时存储器使用,先保存bx的值
    		
    	push ax			;保存低位
    	mov ax, dx		;把高位放在低位中
    	mov dx, 0		;把高位置0
    	div cx			;执行H/N,高位相除的余数保存在dx中
    	mov bx, ax		;把商保存在bx寄存器中
    	pop ax			;执行rem(H/N)*2^16+L
    	div cx			;执行[rem(H/N)*2^16+L]/N,商保存在ax中
    	mov cx, dx		;用cx寄存器保存余数
    	mov dx, bx		;把bx的值复制到dx,即执行int(H/N)*2^16
    						;由于[rem(H/N)*2^16+L]/N已保存于ax中,
    						;即同时完成+运算
    	pop bx			;恢复bx的值
    	divdw_return:
    	ret
    

    五、程序分析
    1、
    为了消除分母为0的情况,我们在子程序的一开始处就判断分母CX的值,若其值为0,则直接返回。

    2、在分析时一定要记住,div把DX当作高16位来看,把AX当作低16来看,我们的子程序的调用者也是如此。所以当程序解释DX的值时,其值为真实值乘以2^16,例如DX中的值为1,AX中的值也为1,则因为DX为高16位,所以被解释为1*2^16 = 65536,则AX作为低16位来处理,其值为1。所以32位的数的值为65536+1 = 65537,也就是说32位数的值为DX*2^16+AX。

      push ax ;保存低位
      mov ax, dx ;把高位放在低位中
      mov dx, 0 ;把高位置0
      div cx ;执行H/N,高位相除的余数保存在dx中
    就是前面所说的把把H和L独立起来考虑,当H/N时,先把DX中的内容(即H)复制到AX中,再把DX的内容置为0,然后再与CX相除。

    3、
      pop ax ;执行rem(H/N)*2^16+L
      div cx ;执行[rem(H/N)*2^16+L]/N,商保存在ax中
    因为前面的除法操作即H/N的余数保存在DX中,又由于在除法操作div时,DX是当高位来处理的,所以在DX中的余数的值就会相当于其原来的值乘以2^16,然后再把之前保存在栈中的X的低位L恢复到ax中来,div指令把AX当作低16位来处理,所以也就相当于DX*2^16+AX,也就是rem(H/N)*2^16+L,之后的除法就不用解释了。

    4、
      mov cx, dx ;用cx寄存器保存余数
    把前面div操作中产生的余数(保存在dx中)复制到cx中来,因为根据函数的说明,我们是用cx来保存余数的,而不是默认的dx。

    5、
      mov dx, bx
    由于bx先前保存着H/N的商,而DX又是高16位,所以把bx的值恢复到dx中就相当于int(H/N)*2^16,由于AX是低16位,而之前的操作又已经把结果(即[rem(H/N)*2^16+L]/N的商)保存在AX中,所以这步结束后,也就相当于执行完int(H/N)*2^16+[rem(H/N)*2^16+L]/N的整个操作完成了。

    可以看到,这段看来小小的代码就这样有非常巧妙的方式,利用了div指令的特性,把DX看作高16位和把AX看作低16位和余数保存在DX中,商保存在AX中的特性,从而实现了我们的无溢出除法的功能了。


    PS:本人有幸成为了CSDN博客之星的候选人之一,如果你觉得我写的博客还可以,欢迎投上你宝贵的一票,谢谢大家的支持!我的投票地址为:

    展开全文
  • 编写程序,把数据段中定义数据num(有四个数据)用十进制方式输出,输出数据用子程序实现。 DATA Segment Num dw 1234,213,9,264 Str db 100 dup(?) DATA ENDS
  • 我用python编写的cli程序,然后制作了安装程序和诸如此类东西 关于 这个项目是作为学习一些基本Python一种方式 正在安装 视窗 要在Windows上安装,建议您仅下载文件。 但是,如果您出于某种原因更喜欢下载独立...
  • 实验11 编写子程序

    2017-09-16 07:07:48
    本章知识很琐碎,原则是用哪查哪,无需记忆。...(3)用来控制CPU相关工作方式。 好了知道这三点就可以开始试验11了。 代码如下: assume cs:codesg datasg segment db "Beginner's All-purpose Symbolic

    本章知识很琐碎,原则是用哪查哪,无需记忆。

    设置标志寄存器的意义在于:

    (1)用来存储相关指令的某些执行结果;

    (2)用来为CPU执行相关指令提供行为依据;

    (3)用来控制CPU的相关工作方式。

    好了知道这三点就可以开始试验11了。

    代码如下:

    assume cs:codesg
    
    datasg segment
    	db "Beginner's All-purpose Symbolic Instruction Code.", 0
    datasg ends
    
    codesg segment
    start:	mov ax, datasg
    	mov ds, ax
    	mov si, 0
    	call letterc
    
    	mov ax, 4c00h
    	int 21h
    
    ;letterc-------------------------
    letterc:
    	push ax
    	push bx
    	push cx
    	push dx
    
    letterc_ok:
    	xor cx, cx
    	mov cl, ds:[si]
    	jcxz letterc_ret
    	cmp cx, 'a'
    	jb next
    	and byte ptr ds:[si], 11011111b
    next:	inc si
    	jmp letterc_ok
    
    letterc_ret:
    	pop dx
    	pop cx
    	pop bx
    	pop ax
    	ret
    
    	
    
    codesg ends
    end start

    实验结果:



    总结几种常用的模式:

    cmp ax, bx

    je, jne, jb, jnb, ja, jna:如果等于,不等于,小于,不小于,大于,不大于则转移


    cx

    jcxz;如果cx==0则转移,否则不转。










    展开全文
  • 在这个数组众多连续序列中,2 2 -2 -2这个连续序列积为最大。 现在小明请你帮忙算出这个最大值。 Input 第一行输入一个正整数T,表示总共有T组数据(T )。 接下来T组数据,每组数据第一行输入N...
  • 今天小周末打算编写一个简单棋游戏程序,与电脑来一场pk。 一、首先我们需要棋盘和棋子才能进行游戏。 1,在这里我们用二维数组来表示棋盘(一个简单3*3棋盘)。 2,“ x ” “ o ” “ ”(空),三个...

    今天小周末打算编写一个简单的三子棋游戏程序,与电脑来一场pk。
    一、首先我们需要棋盘和棋子才能进行游戏。
    1,在这里我们用二维数组来表示棋盘(一个简单的3*3棋盘)。
    2,“ x ” “ o ” “ ”(空),三个字符来表示棋子。
    二、核心流程
    a、初始化棋盘
    b、打印棋盘
    c、让玩家落子(采用输入坐标的方式)
    d、检查是否结束
    e、电脑落子(随机下)
    f、检查是否结束
    g、循环进行b

    A:创建一个新函数将棋盘初始化

    //初始化棋盘
    void Init(char board[Max_Row][Max_Col]){
    	for (int row = 0; row < Max_Row; ++row){
    		for (int col = 0; col < Max_Col; ++col){
    			board[row][col] = ' ';
    		}
    	}
    }
    

    B打印一个3*3棋盘

    void print(char board[Max_Row][Max_Col]){
    	printf("|---|---|---|\n");
    	for (int row = 0; row < Max_Row; ++row){
    		printf("| %c | %c | %c |\n", board[row][0], board[row][1], board[row][2]);
    		printf("|---|---|---|\n");
    	}
    }
    

    效果图如下:
    在这里插入图片描述
    C让玩家落子(采用输入坐标的方式)
    这里也采用函数的方法

    void PlayerMove(char board[Max_Row][Max_Col]){
    	while (1){
    		printf("请输入坐标,(row col)\n");
    		int row = 0;
    		int col = 0;
    		scanf("%d %d", &row, &col);
    		//需进行判定
    		if (row < 0 || row >= Max_Row || col < 0 || col >= Max_Col){
    			printf("您的输入有误,请重新输入\n");
    			continue;
    		}
    		if (board[row][col] != ' '){
    			printf("该位置有子了,请重新输入\n");
    			continue;
    		}
    		board[row][col] = 'x';//玩家落子为x
    		break;
    	}
    }
    

    D判断最终的结果
    分为4种情况游戏结束

    1. 每一行的符号相等
    2. 每一列的符号相等
    3. 对角线的符号相等(又分为左右两对角线)
    4. 棋盘满了,却无123,即为和棋

    因此创建两个函数,Isfull函数判断棋盘是否下满了棋子

    //棋盘满了返回1,没有满返回0
    int Isfull(char board[Max_Row][Max_Col]){
    	for (int row = 0; row < Max_Row; ++row){
    		for (int col = 0; col < Max_Col; ++col){
    			if (board[row][col] == ' '){
    				return 0;
    			}
    		}
    	}
    	return 1;
    }
    
    //返回值的类型是char
    //1,玩家胜利 x
    //2,电脑胜利 o
    //3,和棋     =  
    //4,未分胜负‘ ’
    char Iswin(char board[Max_Row][Max_Col]){
    	//行
    	for (int row = 0; row < Max_Row; ++row){
    		if (board[row][0] == board[row][1] && board[row][0] == board[row][2] && board[row][0] != ' '){
    			return board[row][0];
    		}
    	}
    	//列
    	for (int col = 0; col < Max_Col; ++col){
    		if (board[0][col] == board[1][col] && board[0][col] == board[2][col] && board[0][col] != ' '){
    			return board[0][col];
    		}
    	}
    	//对角线
    	if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != ' '){
    		return board[0][0];
    	}
    	if (board[0][2] == board[1][1] && board[0][0] == board[2][0] && board[0][2] != ' '){
    		return board[0][2];
    	}
    	//棋盘是否下满棋子
    	if (Isfull(board)){
    		return '=';
    	}
    	else{
    		//胜负未分
    		return ' ';
    	}
    }
    

    E电脑落子(随机下)

    void ComputerMove(char board[Max_Row][Max_Col]){
    	//随机落子
    	while (1){
    		int row = rand() % Max_Row;
    		int col = rand() % Max_Col;
    		if (board[row][col] != ' '){
    			continue;
    		}
    		board[row][col] = 'o';
    		break;
    	}
    }
    

    主函数

    int main(){
    	char chess_board[Max_Row][Max_Col];
    	char result = ' ';
    	//1 初始化棋盘
    	Init(chess_board);
    	while (1){
    		//2 打印棋盘
    		print(chess_board);
    		//3 玩家落子
    		PlayerMove(chess_board);
    		//4 判定游戏是否结束
    		result = Iswin(chess_board);
    		if (result != ' '){
    			break;
    		}
    		//5电脑落子
    		ComputerMove(chess_board);
    		//6判断游戏是否结束
    		result = Iswin(chess_board);
    		if (result != ' '){
    			break;
    
    		}
    	}
    	print(chess_board);
    	if (result == 'x'){
    		printf("您赢了\n");
    	}
    	else if (result == 'o'){
    		printf("您输了\n");
    	}
    	else if(result== '='){
    		printf("和棋\n");
    	}
    	system("pause"); 
    	return 0;
    }
    

    总代码如下:

    #define _CRT_SECURE_NO_WARNINGS
    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    #define Max_Row 3
    #define Max_Col 3
    
    void Init(char board[Max_Row][Max_Col]){
    	for (int row = 0; row < Max_Row; ++row){
    		for (int col = 0; col < Max_Col; ++col){
    			board[row][col] = ' ';
    		}
    	}
    	srand(time(0));
    }
    
    void print(char board[Max_Row][Max_Col]){
    	printf("|---|---|---|\n");
    	for (int row = 0; row < Max_Row; ++row){
    		printf("| %c | %c | %c |\n", board[row][0], board[row][1], board[row][2]);
    		printf("|---|---|---|\n");
    	}
    }
    
    void PlayerMove(char board[Max_Row][Max_Col]){
    	while (1){
    		printf("请输入坐标,(row col)\n");
    		int row = 0;
    		int col = 0;
    		scanf("%d %d", &row, &col);
    		if (row < 0 || row >= Max_Row || col < 0 || col >= Max_Col){
    			printf("您的输入有误,请重新输入\n");
    			continue;
    		}
    		if (board[row][col] != ' '){
    			printf("该位置有子了,请重新输入\n");
    			continue;
    		}
    		board[row][col] = 'x';
    		break;
    	}
    }
    
    //满了返回1,没有满返回0
    int Isfull(char board[Max_Row][Max_Col]){
    	for (int row = 0; row < Max_Row; ++row){
    		for (int col = 0; col < Max_Col; ++col){
    			if (board[row][col] == ' '){
    				return 0;
    			}
    		}
    	}
    	return 1;
    }
    
    //返回值的类型是char
    //1,玩家胜利 x
    //2,电脑胜利 o
    //3,和棋     =  
    //4,未分胜负‘ ’
    char Iswin(char board[Max_Row][Max_Col]){
    	//行
    	for (int row = 0; row < Max_Row; ++row){
    		if (board[row][0] == board[row][1] && board[row][0] == board[row][2] && board[row][0] != ' '){
    			return board[row][0];
    		}
    	}
    	//列
    	for (int col = 0; col < Max_Col; ++col){
    		if (board[0][col] == board[1][col] && board[0][col] == board[2][col] && board[0][col] != ' '){
    			return board[0][col];
    		}
    	}
    	//对角线
    	if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != ' '){
    		return board[0][0];
    	}
    	if (board[0][2] == board[1][1] && board[0][0] == board[2][0] && board[0][2] != ' '){
    		return board[0][2];
    	}
    	if (Isfull(board)){
    		return '=';
    	}
    	else{
    		//胜负未分
    		return ' ';
    	}
    }
    void ComputerMove(char board[Max_Row][Max_Col]){
    	//随机落子
    	while (1){
    		int row = rand() % Max_Row;
    		int col = rand() % Max_Col;
    		if (board[row][col] != ' '){
    			continue;
    		}
    		board[row][col] = 'o';
    		break;
    	}
    }
    
    int main(){
    	char chess_board[Max_Row][Max_Col];
    	char result = ' ';
    	//1 初始化棋盘
    	Init(chess_board);
    	while (1){
    		//2 打印棋盘
    		print(chess_board);
    		//3 玩家落子
    		PlayerMove(chess_board);
    		//4 判定游戏是否结束
    		result = Iswin(chess_board);
    		if (result != ' '){
    			break;
    		}
    		//5电脑落子
    		ComputerMove(chess_board);
    		//6判断游戏是否结束
    		result = Iswin(chess_board);
    		if (result != ' '){
    			break;
    
    		}
    	}
    	print(chess_board);
    	if (result == 'x'){
    		printf("您赢了\n");
    	}
    	else if (result == 'o'){
    		printf("您输了\n");
    	}
    	else if(result== '='){
    		printf("和棋\n");
    	}
    	system("pause"); 
    	return 0;
    }
    
    展开全文
  • 看了这么多内核代码,终于要自己开始做...如果自己写一个LED驱动那是很简单,其实用linux内核中leds系统来做也是比较简单,内核中leds系统是将led抽象成platform_device,并有leds_class.这样,在/sys/class/le
    看了这么多内核代码,终于要自己开始做驱动了.按照由易到难,由浅入深的顺序,就从LED开始.
    

            LED驱动可以说是hello world之后最简单的驱动模块了.如果自己写一个LED驱动那是很简单的,其实用linux内核中的leds子系统来做也是比较简单的,内核中的leds子系统是将led抽象成platform_device,并有leds_class.这样,在/sys/class/leds/目录下面就可以利用sysfs文件系统来实现LED的操作.其实,也可以在此基础上添加/dev访问的接口,甚至用不着包含mknod的脚本和udev等工具,在模块注册后就可以生成/dev下的设备文件.

            一步一步的来,首先利用platform虚拟总线来实现sysfs文件系统下的LED操作.

            在mach-smdk2440.c中新增platform_device如下:

    1. static struct platform_device smdk_led5 = {  
    2.     .name       = "s3c24xx_led",  
    3.     .id     = 0,  
    4.     .dev        = {  
    5.         .platform_data = &smdk_pdata_led5,  
    6.         .release = &platform_led_release,  
    7.     },  
    8. };  
            对于具体的板子,是GPB5-8对应四个LED,所以这里smdk_pdata_led5的定义如下:

    1. static struct s3c24xx_led_platdata smdk_pdata_led5 = {  
    2.     .gpio       = S3C2410_GPB(5),  
    3.     .flags      = S3C24XX_LEDF_ACTLOW ,//| S3C24XX_LEDF_TRISTATE,  
    4.     .name       = "led5",  
    5.     //.def_trigger  = "nand-disk",  
    6. };  
            接着在static struct platform_device *smdk2440_devices[] __initdata中新增&smdk_led5,这样系统在启动时就会由smdk2440_machine_init调用platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));来添加刚才加上的platform_device.

            看完了platform_device再看下platform_driver是如何注册的:

            在drivers/leds目录下的Makefile中有obj-$(CONFIG_LEDS_S3C24XX)+= leds-s3c24xx.o

            所以在make menuconfig的时候记得将其选为M.

            这样,注册leds-s3c24xx.ko就会在/sys/class/leds中有

            led5  led6  led7  led8四个目录,进入led5目录,有

            brightness      device          power           trigger
            dev             max_brightness  subsystem       uevent

            执行echo 0 > brightness就可以关闭led,而echo 1 > brightness就可以打开led.

            因为有leds_class,而在led-class.c中leds-init函数中有leds_class->dev_attrs = led_class_attrs;
            其中,led_class_attrs定义如下

    1. static struct device_attribute led_class_attrs[] = {  
    2.     __ATTR(brightness, 0644, led_brightness_show, led_brightness_store),  
    3.     __ATTR(max_brightness, 0444, led_max_brightness_show, NULL),  
    4. #ifdef CONFIG_LEDS_TRIGGERS  
    5.     __ATTR(trigger, 0644, led_trigger_show, led_trigger_store),  
    6. #endif  
    7.     __ATTR_NULL,  
    8. };  
            根据sysfs的属性文件,读写属性文件最终调用的就是show和store函数,在这里就是led_brightness_show和led_brightness_store函数.
            顺着调用其实设置寄存器的动作是在leds-s3c24xx.c中的s3c24xx_led_set实现的.从这里可以看出,LEDS这个子系统也做了抽象,与平台相关的放在一个文件中,而与平台无关的抽象出来放在led-class中.

            到此,就可以通过sysfs文件系统来访问led设备了.

            那么,开头说的在此基础如何做/dev访问的接口呢?

            在leds目录下新建一个文件led-dev.c

            在Makefile中添加obj-$(CONFIG_LEDS_INTF_DEV)+= led-dev.o

            记得在Kconfig文件中也要添加对应的信息.

            led-dev.c文件内容如下:

    1. /* 
    2.  * LEDS subsystem, dev interface 
    3.  * 
    4.  * Copyright (C) 2012  Baikal 
    5.  * Author: Baikal <dndxhej@gmail.com> 
    6.  * 
    7.  * 
    8.  * This program is free software; you can redistribute it and/or modify 
    9.  * it under the terms of the GNU General Public License version 2 as 
    10.  * published by the Free Software Foundation. 
    11. */  
    12.   
    13.   
    14. #include <linux/module.h>  
    15. #include <linux/leds.h>  
    16. #include <linux/sched.h>  
    17.   
    18. #include <linux/fs.h>  
    19. #include <linux/device.h>  
    20. #include <asm/uaccess.h>  
    21. #include "leds.h"  
    22.   
    23. static dev_t led_devt;  
    24.   
    25. #define LED_DEV_MAX 8   /*actually,there is 4 leds on the 2440 board*/  
    26.   
    27.   
    28. static int led_dev_open(struct inode *inode, struct file *file)  
    29. {  
    30.   
    31.     printk(KERN_INFO "debug by baikal: led dev open\n");  
    32.     printk(KERN_INFO "i_rdev:0x%x\n",inode->i_rdev);  
    33.     printk(KERN_INFO "i_rdev:%d\n",inode->i_rdev);  
    34.     printk(KERN_INFO "i_rdev:major:%d minor:%d\n",MAJOR(inode->i_rdev),MINOR(inode->i_rdev));  
    35.     struct led_classdev *led = container_of(inode->i_cdev,  
    36.                     struct led_classdev, char_dev);  
    37.   
    38.   
    39.     file->private_data = led;  
    40.   
    41.   
    42.     return 0;  
    43. }  
    44.   
    45. static ssize_t  
    46. led_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)  
    47. {  
    48.     printk(KERN_INFO "debug by baikal: led dev read\n");  
    49. }  
    50.   
    51.   
    52. static ssize_t  
    53. led_dev_write(struct file *file, char __user *buf, size_t count, loff_t *ppos)  
    54. {  
    55.     char data;  
    56.     printk(KERN_INFO "debug by baikal: led dev write\n");  
    57.   
    58.     copy_from_user(&data,buf,count);  
    59.     if(data == '0')  
    60.         led_set_brightness(file->private_data,0);  
    61.     else  
    62.         led_set_brightness(file->private_data,1);          
    63. }  
    64.   
    65. static const struct file_operations led_dev_fops = {  
    66.     .owner      = THIS_MODULE,  
    67.     .read       = led_dev_read,  
    68.     .write      = led_dev_write,  
    69.     .open       = led_dev_open,  
    70. //  .release    = led_dev_release,  
    71.   
    72. };  
    73.   
    74.   
    75.   
    76. void led_dev_prepare(struct led_classdev *led)  
    77. {  
    78.     static int minor = 0;  
    79.     printk(KERN_INFO "debug by baikal: led dev pre\n");  
    80.   
    81.     led_devt = MKDEV(254,minor); //add by baikal  
    82.     minor++;  
    83.     led->dev->devt = MKDEV(MAJOR(led_devt), MINOR(led_devt));  
    84.   
    85.   
    86.     cdev_init(&led->char_dev, &led_dev_fops);  
    87.     //led->char_dev.owner = led->owner;  
    88.   
    89. }  
    90.   
    91. void led_dev_add_device(struct led_classdev *led)  
    92. {  
    93.     printk(KERN_INFO "debug by baikal: led dev add \n");  
    94.   
    95.     if (cdev_add(&led->char_dev, led->dev->devt, 1))  
    96.         printk(KERN_WARNING " failed to add char device ");  
    97.     else  
    98.         pr_debug("%s: dev (%d:)\n", led->name,  
    99.             MAJOR(led_devt));  
    100. }  
    101.   
    102. void led_dev_del_device(struct led_classdev *led)  
    103. {  
    104.     if (led->dev->devt)  
    105.         cdev_del(&led->char_dev);  
    106. }  
    107.   
    108.   
    109. void __init led_dev_init(void)  
    110. {  
    111. /* 
    112.     int err; 
    113.  
    114.     err = alloc_chrdev_region(&led_devt, 0, LED_DEV_MAX, "led"); 
    115.     if(err < 0) 
    116.         printk(KERN_ERR "%s: failed to allocate char dev region\n",__FILE__); 
    117. */  
    118. }  
    119.   
    120. void __exit led_dev_exit(void)  
    121. {  
    122. /* 
    123.     if(led_devt) 
    124.         unregister_chrdev_region(led_devt, LED_DEV_MAX); 
    125. */  
    126. }  
            并在led-class.c中的led_classdev_register函数的开头处添加
    1. static int minor = 0;  
    2. dev_t led = MKDEV(254,minor); //add by baikal  
    3. printk(KERN_INFO "debug by baikal: led class reg 1\n");  
    4.   
    5.   
    6. led_cdev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);  
    7. if (led_cdev->dev == NULL) {  
    8.     return -ENOMEM;  
    9. }  
    10. led_dev_prepare(led_cdev);              //add by baikal  
    11. printk(KERN_INFO "debug by baikal: led class reg 2\n");  
    12.   
    13. minor++;  
            并将led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,
         "%s", led_cdev->name);

            改为led_cdev->dev = device_create(leds_class, parent, led, led_cdev,
         "%s", led_cdev->name);
            在函数的结尾处再调用 led_dev_add_device(led_cdev);

            这样,在模块注册后在/dev目录下就有

    [root@BaikalHu led5]# ls /dev/l*
    /dev/led5   /dev/led7   /dev/loop0  /dev/loop2  /dev/loop4  /dev/loop6
    /dev/led6   /dev/led8   /dev/loop1  /dev/loop3  /dev/loop5  /dev/loop7

            这样就在/dev下生成了设备文件.

            可以照下面的方式来测试/dev下的led设备文件的功能:

    1. #include <sys/types.h>  
    2. #include <sys/stat.h>  
    3. #include <fcntl.h>  
    4. #include <stdio.h>  
    5. #include <errno.h>  
    6. #include <string.h>  
    7.   
    8. int main(int argc, char **argv)  
    9. {  
    10.     int fd;  
    11.     if(argc != 3)  
    12.     {  
    13.         printf("usage : ./led led5-8 on/off\n");  
    14.         return -1;  
    15.     }  
    16.   
    17.     char file[20] = "/dev/";  
    18.   
    19.     strcat(file, argv[1]);  
    20.   
    21.     fd = open(file, O_RDWR);  
    22.   
    23.     if(fd < 0)  
    24.     {     
    25.         perror("open led");  
    26.         return -1;  
    27.     }  
    28.   
    29.     if(!strcmp(argv[2],"on"))  
    30.     {  
    31.         write(fd,"1",1);  
    32.     }  
    33.     else if(!strcmp(argv[2],"off"))  
    34.     {  
    35.         write(fd,"0",1);  
    36.     }  
    37.   
    38.    
    39.     close(fd);  
    40.   
    41.     return 0;  
    42.   
    43.   
    44. }  
            测试一切正常.

            回头解释下为什么这样就可以自己生成/dev下的设备文件,原因在于在新内核中的device_add函数中有这么一段:

    1. if (MAJOR(dev->devt)) {  
    2.     error = device_create_file(dev, &devt_attr);  
    3.     if (error)  
    4.         goto ueventattrError;  
    5.   
    6.     error = device_create_sys_dev_entry(dev);  
    7.     if (error)  
    8.         goto devtattrError;  
    9.   
    10.     devtmpfs_create_node(dev);  
    11. }  
            看到devtmpfs_create_node了没,这就是答案.如果对devtmpfs有兴趣的话,以前写的《linux设备模型之字符设备》大概提到了devtmpfs.

            通过自己的添加,可以用sysfs和dev两种接口方式来访问LED.但是实际设置寄存器的函数都是同一处地方.

            linux下的驱动,最终还是要操作寄存器的,但是与裸机不同的是linux将硬件设备抽象为文件,那我们就必须按照这种机制来书写linux下的驱动,机制的根本是文件系统和设备模型,但是可以通过不同的策略来达到目的,比如sysfs和devtmpfs.

    展开全文
  • 程序的目的是编写一个能够对数字像片进行管理和查看的应用程序。 1.1 问题描述 图片管理器可作为计算机使用者浏览各种格式图片的载体而存在,作为人们日使用计算机工作的一大可视化工具。随着手机的日益普及,个人...
  • 基本都是单向通讯吧程序<调用>插件,插件<被动返回数据>程序,程序<内部处理>子程序事件这份源码就是一个插件如何主动传递数据给程序,然后程序内部处理,调用不同程序命令的方式插件<主动传递数据>程序,...
  • 一、Qt Creator 的安装和hello world 程序的编写(原创) 1.首先到Qt 的官方网站上下载Qt Creator,这里我们下载windows 版的。 下载地址:http://qt.nokia.com/downloads 如下图我们下载:Download Qt SDK for ...
  • 请计算,以下式是否成立: F(x,m) mod k ≡ c Input 第一行一个整数T,表示T组数据。 每组测试数据占一行,包含四个数字x,m,k,c 1≤x≤9 1≤m≤1010 0≤c≤10,000 Output 对于每组...
  • 中断系统的运行必须与子程序配合才能正确使用。... (4)编写中断服务子程序,处理中断请求。 前3条一般放在主程序的初始化程序段中。 举例如下:例1、假设允许外部中断0中断,并设定它为高优先级中断,其他中断源为
  • 文章目录linux字符设备驱动编程linux程序框架概念字符设备高级驱动课程初级驱动和高级驱动不同特点输入系统学习输入系统作用和框架输入系统编程方式前提条件make menuconfig 配置编写步骤(主要流程)...
  • DOS下内存分页程序的编写

    千次阅读 2007-07-27 13:32:00
    DOS下内存分页程序的编写 一. 前言 首先,我们先要弄清楚80386编程中涉及到的三个地址概念:物理地址、逻辑地址和线性地址。 1.物理地址:本质上,一个物理地址是CPU插脚上可测量的电压。CPU通过就是物理地址...
  • 高质量的子程序

    2015-09-19 22:16:28
    子程序是为实现一个特定目的而编写的一个可被调用方法(method)或过程(procedure)。例如C++中函数(function),Java中方法(method),或是Microsoft Visual Basic中函数过程(function procedure)或自...
  • 子程序是为实现一个特定目的而编写的一个可被调用方法或过程。例如 C++ 中函数(funtion), Java 中方法(method)。对于某些使用方式, C 和 C++ 中宏(macro)也可以认为是子程序。你可以把创建高质...
  • 请计算,以下式是否成立: F(x,m) mod k ≡ c Input 第一行一个整数T,表示T组数据。 每组测试数据占一行,包含四个数字x,m,k,c 1≤x≤9 1≤m≤1010 0≤c≤10,000 Output 对于每组...
  • Ubuntu中编写C语言程序

    2020-09-22 22:33:04
    Ubuntu中编写C语言程序1、准备工作1.1 安装GCC2、使用GCC编写C语言程序2.1 编写一个Hello World程序2.2 编写一个主程序文件main1.c和子程序文件sub1.c3、用Makefile方式编写程序 1、准备工作 1.1 安装GCC 安装GCC...
  • 文章目录学习任务学习内容编写一个主程序文件 main1.c 和一个子程序文件 sub1.c运用vc6编写在ubuntu系统下用Makefile方式编程主程序 学习任务 1.请编写一个主程序文件 main1.c 和一个子程序文件 sub1.c, 要求:...
  • 首次运用ubuntu编写程序:编写一个主程序文件main1.c和一个子程序文件sub1.c,有如下要求:子程序sub1.c包含一个算术运算函数float x2x(int a,int b),此函数功能为对两个输入整型参数做某个运算,将结果做浮点数返回...
  • 主线程负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等等)。这些代码只能顺序执行,无法并发执行 多线程: 拥有多个线程的程序,称作多线程程序。 iOS允许用户自己开辟新的线程,相对于主线程来讲,...
  • 编写USB 驱动程序

    千次阅读 2017-04-01 14:59:50
     前面学习了USB驱动的一些基础...编写与一个USB设备驱动程序的方法和其他总线驱动方式类似,驱动程序把驱动程序对象注册到USB系统中,稍后再使用制造商和设备标识来判断是否安装了硬件。当然,这些制造商和设备标
  • 该楼层疑似违规已被系统折叠隐藏此楼查看此楼/*************************************************************************************** 外部中断0实验 *实现现象:下载程序后按下K3按键可以对D1小灯状态取反。...
  • linux多进程程序编写

    2021-04-18 22:25:05
    通过编写多进程程序,使读者熟练掌握 fork()、exec()、wait()和 waitpid()等函数使用,进一步理解在 Linux 中多进程编程步骤。 2.实验内容 该实验有 3 个进程,其中一个为父进程,其余两个是该父进程创建的子...
  • 在Ubuntn编写一个主程序文件main1.c和一个子程序文件sub1.c, 要求:子程序sub1.c 包含一个算术运算函数float x2x(int a,int b),此函数功能为对两个输入整型参数做某个运算,将结果做浮点数返回;主程序main1.c...
  • ubuntu下编写C语言程序

    千次阅读 2020-09-30 10:54:24
    题目:编写一个主程序文件main1.c和一个子程序文件sub1.c,有如下要求:子程序sub1.c包含一个算术运算函数float x2x(int a,int b),此函数功能为对两个输入整型参数做某个运算,将结果做浮点数返回;主程序main1.c...
  • asp子程序

    2009-03-10 20:33:00
    实例:调用使用 VBScript 的子程序 sub vbproc(num1,num2)response.write(num1*num2)end sub%>您可以像这样调用一个程序:结果:或者,像这样:结果:如何从 ASP 调用以 VBScript 编写的子程序。 调用使用 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,746
精华内容 698
关键字:

子程序的编写方式