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接口,通常主機(jī)上是25針D型接口。其引腳如下:
?
為操作并行口,SPP(Standard Parallel Port標(biāo)準(zhǔn)并行接口)定義了寄存器,并映射到PC機(jī)的I/O空間。寄存器包括了以并口地址為基址的3塊連續(xù) 的寄存器,并口地址常見為3BCH、378H和278H,其中都包括數(shù)據(jù)、狀態(tài)和控制寄存器,分別對(duì)應(yīng)數(shù)據(jù)、狀態(tài)和控制信號(hào)線操作,通常稱為數(shù)據(jù)端口、狀 態(tài)端口和控制端口。打印機(jī)卡1的地址常為378H,其中數(shù)據(jù)口0378H、狀態(tài)口0379H、控制口037AH;打印機(jī)卡2的地址常為278H,其中數(shù)據(jù) 口0278H、狀態(tài)口0279H、控制口027AH。支持新的IEEE 1284標(biāo)準(zhǔn)的并口,使用8到16個(gè)寄存器,地址為378H or 278H,即插即用(Plug and Play)兼容的的并口適配器也可以重新加載。
并行接口輸出的是TTL標(biāo)準(zhǔn)邏輯電平,其中,標(biāo)準(zhǔn)TTL為+5V,低壓TTL 為+3.3V。一般情況下,小于0.8V是低電平,大于2V是高電平。
2. 實(shí)現(xiàn)功能
用一個(gè)LED發(fā)光二極管、一個(gè)電阻以及一些導(dǎo)線和電腦主機(jī)的并口連接了一條回路,最后通過測(cè)試程序控制LED燈的開啟、關(guān)閉,驗(yàn)證了并口驅(qū)動(dòng)程序的正確性。
3. 驅(qū)動(dòng)程序源碼
(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)測(cè)試代碼
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) 測(cè)試代碼 編譯命令: gcc -o par_test par_test.c
4. 實(shí)例運(yùn)行方法
(1)建立6個(gè)文件并拷貝源碼:parport_drv.c,? parport_drv.h, Makefile, par_test.c, load_rdwrdev, unload_rdwrdev
(2)運(yùn)行:Makefile 生成 parport_drv.o
(3)運(yùn)行模塊加載shell腳本:sudo bash load_rdwrdev
(4)編譯測(cè)試代碼文件 : gcc -o par_test par_test.c
(5)運(yùn)行: sudo ./par_test
(6) 運(yùn)行模塊卸載shell腳本:sudo bash unload_rdwrdev
5. 實(shí)驗(yàn)現(xiàn)象
并口D2引腳示波器信號(hào)波形
?
總結(jié)
以上是生活随笔為你收集整理的linux并口驱动编程开发的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机显示器维修,电脑显示器维修价格(液
- 下一篇: 如何在Linux下用ADSL拨号上网