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型接口。其引脚如下:
为操作并行口,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并口驱动编程开发相关推荐
- linux内核_Linux驱动编程的本质就是Linux内核编程
由于Linux驱动编程的本质属于Linux内核编程,因此我们非常有必要熟悉Linux内核以及Linux内核的特点. 这篇文章将会帮助读者打下Linux驱动编程的基础知识. 本篇文章分为如下三个小节进行 ...
- 树莓派底层IO驱动开发示例(一个简单io口驱动的开发)
一.驱动代码的开发 1.树莓派寄存器的介绍 点击查看:树莓派(bcm2835芯片手册) GPFSEL0 GPIO Function Select 0: 功能选择 输入/输出 GPSET0 GPIO P ...
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Oops在Linux 2.6内核+PowerPC架构下的前世今生
Oops在Linux 2.6内核+PowerPC架构下的前世今生 Sailor_forever sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人blo ...
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的I2C驱动架构分析
PowerPC + Linux2.6.25平台下的I2C驱动架构分析 Sailor_forever sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人b ...
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的SPI驱动架构分析
PowerPC + Linux2.6.25平台下的SPI驱动架构分析 Sailor_forever sailing_9806#163.com (本原创文章发表于Sailor_forever 的个人b ...
- linux iio 设备驱动,FS4412开发板使用Linux IIO驱动框架实现ADC驱动
1.概述 FS4412开发板有一个4通道(0/1/2).10/12比特精度的 ADC ,其中: 1)ADCIN0: 在核心板中引出 2)ADCIN1: 在核心板中引出 3)ADCIN2: 在核心板中引 ...
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux信号机制分析
Linux信号机制分析 Sailor_forever sailing_9806@163.com 转载请注明 http://blog.csdn.net/sailor_8318/archive/2008 ...
- 【Linux内核及驱动编程】Linux信号机制分析
Linux信号机制分析 Sailor_forever sailing_9806@163.com转载请注明 http://blog.csdn.net/sailor_8318/archive/2008/0 ...
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux内核抢占实现机制分析
Linux内核抢占实现机制分析 Sailor_forever sailing_9806@163.com 转载请注明 http://blog.csdn.net/sailor_8318/archive/ ...
最新文章
- 【译】Spring 官方教程:Spring Security 架构
- 【知识发现】隐语义模型LFM算法python实现(三)
- 租金 预测_如何预测租金并优化租赁期限,从而节省资金
- MIP 支付组件,支付流程:
- c语言循环控制结构的单元课程设计,C语言单元课程设计(张芝雨).pdf
- centos6.5远程桌面连接(VNC\SPice)
- 头条和百度“大打出手”时,微信搜索去哪儿了?
- Selenium XPath示例
- Redis主从配置,哨兵,集群的设计原理
- ecplise反编译插件
- 手机内置天线慎用FPC
- UML统一建模语言(UML类图)
- 数据恢复哪家强?四大数据恢复类软件评测
- 第四届IT 2020高端论坛成功举办
- asp微信扫码签到源码
- 学会这三款软件,可以轻松完成录音转文字操作
- 【Vue3】vue3获取对象长度(非数组长度)
- PHP preg_match(): Unknown modifier '/'
- 小数乘分数怎么算过程_小数乘分数如何计算?
- Leetcode-“二分查找”-爱吃香蕉的珂珂
热门文章
- 记一次清除浏览器广告的经历
- 微信小程序-如何实现实现横纵滚动轴?【亲测有效】
- 通达信交易接口如何实现股票动态监测?
- 小学自动组卷系统C语言,题库管理自动组卷系统设计-PB(源程序+论文+开题报告+答辩PPT)...
- Bugku,Crypto:聪明的小羊
- 品质qc工程图_QC 工程图
- ES系列之利用filter让你的查询效率飞起来
- 计算机符号标志nf,测试标志位指令
- 品高脚踏移动警务云而来 引领公安行业云化新潮流
- 常见的http返回状态码(200、301、302、400)