参考链接:

(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型接口。其引脚如下:

为操作并行口,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灯的开启、关闭,验证了并口驱动程序的正确性。

3. 驱动程序源码

(1)parport_drv.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>    /* printk() */
#include <linux/fs.h>        /* everything... */
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/ioport.h>
 
#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 <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/errno.h>
 
#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<da.loop;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并口驱动编程开发相关推荐

  1. linux内核_Linux驱动编程的本质就是Linux内核编程

    由于Linux驱动编程的本质属于Linux内核编程,因此我们非常有必要熟悉Linux内核以及Linux内核的特点. 这篇文章将会帮助读者打下Linux驱动编程的基础知识. 本篇文章分为如下三个小节进行 ...

  2. 树莓派底层IO驱动开发示例(一个简单io口驱动的开发)

    一.驱动代码的开发 1.树莓派寄存器的介绍 点击查看:树莓派(bcm2835芯片手册) GPFSEL0 GPIO Function Select 0: 功能选择 输入/输出 GPSET0 GPIO P ...

  3. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Oops在Linux 2.6内核+PowerPC架构下的前世今生

    Oops在Linux 2.6内核+PowerPC架构下的前世今生 Sailor_forever  sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人blo ...

  4. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的I2C驱动架构分析

    PowerPC + Linux2.6.25平台下的I2C驱动架构分析 Sailor_forever  sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人b ...

  5. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的SPI驱动架构分析

    PowerPC + Linux2.6.25平台下的SPI驱动架构分析 Sailor_forever  sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人b ...

  6. linux iio 设备驱动,FS4412开发板使用Linux IIO驱动框架实现ADC驱动

    1.概述 FS4412开发板有一个4通道(0/1/2).10/12比特精度的 ADC ,其中: 1)ADCIN0: 在核心板中引出 2)ADCIN1: 在核心板中引出 3)ADCIN2: 在核心板中引 ...

  7. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux信号机制分析

    Linux信号机制分析 Sailor_forever  sailing_9806@163.com 转载请注明 http://blog.csdn.net/sailor_8318/archive/2008 ...

  8. 【Linux内核及驱动编程】Linux信号机制分析

    Linux信号机制分析 Sailor_forever sailing_9806@163.com转载请注明 http://blog.csdn.net/sailor_8318/archive/2008/0 ...

  9. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux内核抢占实现机制分析

    Linux内核抢占实现机制分析 Sailor_forever  sailing_9806@163.com 转载请注明 http://blog.csdn.net/sailor_8318/archive/ ...

最新文章

  1. 【译】Spring 官方教程:Spring Security 架构
  2. 【知识发现】隐语义模型LFM算法python实现(三)
  3. 租金 预测_如何预测租金并优化租赁期限,从而节省资金
  4. MIP 支付组件,支付流程:
  5. c语言循环控制结构的单元课程设计,C语言单元课程设计(张芝雨).pdf
  6. centos6.5远程桌面连接(VNC\SPice)
  7. 头条和百度“大打出手”时,微信搜索去哪儿了?
  8. Selenium XPath示例
  9. Redis主从配置,哨兵,集群的设计原理
  10. ecplise反编译插件
  11. 手机内置天线慎用FPC
  12. UML统一建模语言(UML类图)
  13. 数据恢复哪家强?四大数据恢复类软件评测
  14. 第四届IT 2020高端论坛成功举办
  15. asp微信扫码签到源码
  16. 学会这三款软件,可以轻松完成录音转文字操作
  17. 【Vue3】vue3获取对象长度(非数组长度)
  18. PHP preg_match(): Unknown modifier '/'
  19. 小数乘分数怎么算过程_小数乘分数如何计算?
  20. Leetcode-“二分查找”-爱吃香蕉的珂珂

热门文章

  1. 记一次清除浏览器广告的经历
  2. 微信小程序-如何实现实现横纵滚动轴?【亲测有效】
  3. 通达信交易接口如何实现股票动态监测?
  4. 小学自动组卷系统C语言,题库管理自动组卷系统设计-PB(源程序+论文+开题报告+答辩PPT)...
  5. Bugku,Crypto:聪明的小羊
  6. 品质qc工程图_QC 工程图
  7. ES系列之利用filter让你的查询效率飞起来
  8. 计算机符号标志nf,测试标志位指令
  9. 品高脚踏移动警务云而来 引领公安行业云化新潮流
  10. 常见的http返回状态码(200、301、302、400)