linux并口驱动编程开发

参考链接:

(1)https://www.cnblogs.com/chungshu/archive/2012/11/26/2789257.html

(2)https://blog.csdn.net/bg2bkk/article/details/8946424

1. 并行接口(并口)简介

并行接口是常见的一种I/O接口,通常主机上是25针D型接口。其引脚如下:

 linux并口驱动编程开发_第1张图片

为操作并行口,SPP(Standard Parallel Port标准并行接口)定义了寄存器,并映射到PC机的I/O空间。寄存器包括了以并口地址为基址的3块连续 的寄存器,并口地址常见为3BCH、378H和278H,其中都包括数据、状态和控制寄存器,分别对应数据、状态和控制信号线操作,通常称为数据端口、状 态端口和控制端口。打印机卡1的地址常为378H,其中数据口0378H、状态口0379H、控制口037AH;打印机卡2的地址常为278H,其中数据 口0278H、状态口0279H、控制口027AH。支持新的IEEE 1284标准的并口,使用8到16个寄存器,地址为378H or 278H,即插即用(Plug and Play)兼容的的并口适配器也可以重新加载。

并行接口输出的是TTL标准逻辑电平,其中,标准TTL为+5V,低压TTL 为+3.3V。一般情况下,小于0.8V是低电平,大于2V是高电平。

2. 实现功能

用一个LED发光二极管、一个电阻以及一些导线和电脑主机的并口连接了一条回路,最后通过测试程序控制LED灯的开启、关闭,验证了并口驱动程序的正确性。

linux并口驱动编程开发_第2张图片


3. 驱动程序源码

(1)parport_drv.c

#include
#include
#include     /* printk() */
#include         /* everything... */
#include
#include
#include
#include
#include
#include
 
#include"parport_drv.h"   
/*****************************************************************************************/    
#define Drv_major 240   
#define Drv_name  "parport_drv"   
#define Drv_read_addr 0x379   
#define Drv_write_addr 0x378   
/*****************************************************************************************/    
MODULE_LICENSE ("GPL");
 
/*****************************************************************************************/  
int parport_open(struct inode *inode, struct file *filp);
ssize_t parport_write(struct file *filp, const char *buf, size_t count, loff_t *f_ops);
ssize_t parport_read(struct file *filp, char *buf, size_t count, loff_t *f_ops) ;
long    parport_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ;
int parport_release(struct inode *inode, struct file *filp) ;
 
/*****************************************************************************************/  
struct file_operations parport_fops = {   
    .owner  =   THIS_MODULE,   
    .write  =   parport_write,   
    .read   =   parport_read,   
    .open   =   parport_open,   
    .unlocked_ioctl =   parport_ioctl,   
    .release=   parport_release,   
};  
/*****************************************************************************************/  
int parport_open(struct inode *inode, struct file *filp)   
{   
    printk(KERN_ALERT "open the parport_dev\n");   
    return 0;   
}   
/*****************************************************************************************/    
ssize_t parport_write(struct file *filp, const char *buf, size_t count, loff_t *f_ops)   
{   
    unsigned char status;   
    int loop;   
    for(loop = 0; loop < count; loop++)   
    {   
        get_user(status, (char *)buf);   
        outb(status, Drv_write_addr);   
    }   
    return count;   
}   
/*****************************************************************************************/    
ssize_t parport_read(struct file *filp, char *buf, size_t count, loff_t *f_ops)   
{   
    unsigned char status;   
    int loop;   
    for(loop = 0; loop < count; loop++)   
    {   
        status = inb(Drv_read_addr);   
        put_user(status, (char *) &buf[loop]);   
    }   
    return count;   
}   
/*****************************************************************************************/    
long    parport_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)   
{   
    int loop;   
    struct dat data;   
    switch(cmd)   
    {   
        case PARPORT_WRITE:   
//          outb(status, Drv_write_addr);   
            copy_from_user(&data, (struct dat *)arg, sizeof(data));            
            printk(KERN_ALERT "out put %d\n",data.loop);   
            for(loop = 0; loop < data.loop; loop ++)   
            {   
                printk(KERN_ALERT "the %dth loop, write %d\n",loop,data.buf[loop]);   
                outb(data.buf[loop], Drv_write_addr);   
                wmb();   
            }   
            break;   
   
        case PARPORT_CLOSE:   
            outb(0x00, Drv_write_addr);   
            wmb();   
            break;   
    }   
    return 0;   
}   
/*****************************************************************************************/    
int parport_release(struct inode *inode, struct file *filp)   
{   
    printk(KERN_ALERT "close the module parport_dev\n");   
    return 0;   
}   
    
/*****************************************************************************************/   
int parport_init(void)   
{   
    int result;   
   
    result = register_chrdev(Drv_major, Drv_name, &parport_fops);   
    if(result < 0)   
    {
        printk("register charactre devices error!\n");
        return result;  
    }
          
    printk(KERN_ALERT "hello the module parport_dev\n");   
   
    return 0;   
}   
/*****************************************************************************************/    
void parport_exit(void)   
{   
    printk(KERN_ALERT "exit the module parport_drv\n");   
    unregister_chrdev(Drv_major, Drv_name);   
       
}   
/*****************************************************************************************/    
module_init(parport_init);   
module_exit(parport_exit);

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

(2) parport_drv.h

#ifndef _PARPORT_DRV_H   
#define _PARPORT_DRV_H   
   
   
#define PARPORT_WRITE 1   
#define PARPORT_CLOSE 2   
   
   
struct dat{   
    int loop;   
    unsigned char *buf;   
};   
   
   

#endif

(3)模块编译Makefile


# To build modules outside of the kernel tree, we run "make"
# in the kernel source tree; the Makefile these then includes this
# Makefile once again.
# This conditional selects whether we are being included from the
# kernel Makefile or not.
ifeq ($(KERNELRELEASE),)

    # Assume the source tree is where the running kernel was built
    # You should set KERNELDIR in the environment if it's elsewhere
    KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    # The current directory is passed to sub-makes as argument
    PWD := $(shell pwd)

modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean

else
    # called from kernel build system: just declare what our modules are
    obj-m := parport_drv.o
endif

(4)模块加载shell脚本 : load_rdwrdev

#!/bin/sh
insmod parport_drv.ko
mknod /dev/parport_drv c 240 0
chgrp staff /dev/parport_drv

chmod 664 /dev/parport_drv

(5)模块卸载shell脚本 :unload_rdwrdev

#!/bin/sh
rmmod parport_drv.ko
rm /dev/parport_drv

(6)测试代码

par_test.c

#include
#include
#include
#include
#include
#include
 
#include "parport_drv.h"   
 
/*****************************************************************************************/  
#define DEVICE_NAME "/dev/parport_drv"   
 
/*****************************************************************************************/   
int main()   
{   
    int fd;   
    char buf[128];   
    int loop;   
   
    fd = open(DEVICE_NAME, O_RDWR | O_NDELAY);   
   
    if(fd < 0)   
    {   
        perror("open device");   
        exit(1);   
    }   
    else   
    {   
        int i;   
        int arg=0x99;   
        unsigned char buf[255];   
        struct dat da;   
        da.loop = 4;   
        da.buf = (unsigned char *)malloc(5 * sizeof(unsigned char));   
        for(i = 0;i< da.loop; i++)   
            da.buf[i] = i*2+1;   
        for(i=0;i            printf("test:%d\n", da.buf[i]);   
        ioctl(fd, PARPORT_WRITE,&da);   
        sleep(1);   
        ioctl(fd, PARPORT_CLOSE);   
        sleep(1);   
        close(fd);   
    }   
   
    return 0;   
}  
 
/*****************************************************************************************/ 

(5) 测试代码 编译命令: gcc -o par_test par_test.c

4. 实例运行方法

(1)建立6个文件并拷贝源码:parport_drv.c,  parport_drv.h, Makefile, par_test.c, load_rdwrdev, unload_rdwrdev

(2)运行:Makefile 生成 parport_drv.o

(3)运行模块加载shell脚本:sudo bash load_rdwrdev

(4)编译测试代码文件 : gcc -o par_test par_test.c

(5)运行: sudo ./par_test

(6) 运行模块卸载shell脚本:sudo bash unload_rdwrdev

5. 实验现象

并口D2引脚示波器信号波形


linux并口驱动编程开发_第3张图片



 

你可能感兴趣的:(Linux)