一个驱动程序对应多个设备

1. 对于驱动程序中有两个关键的结构体:

struct file *filp:
    有一个关键的成员 -> void *private_data,用于存放用于私人的数据
inode:
    有一个关键的成员 -> unsigned int i_flags

2. 一个驱动多个设备的程序思路:

1个驱动程序,
1个struct file_operations 结构体
2个用户结构体数据(包含 struct cdev 结构体)
在 struct file_operation 结构体的 open 方法中根据 inode 结构体中的 i_cdev 成员找到 包含 cdev 的整个结构体,从而能在read/write中能够操作这个结构体的其他成员,具体如下:
在 open 中 将得到的 cdev 通过 struct file 结构体中的private_data 传递给 read/write 方法:
    filp->private_data = dev;
当然设备号和设备节点都是两个,通过访问不同的 /dev 下的设备,访问不同的用户数据

3. 程序:


char_multi_dev.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/device.h>

MODULE_LICENSE ("GPL");

int hello_major       = 250;
int hello_minor       = 0;
int number_of_devices = 2;
struct class *my_class;

struct hello_device
{
    char data[128];
    struct cdev cdev;

} hello_device[2];


static int hello_open (struct inode *inode, struct file *filp)
{
    struct hello_device *dev = container_of(inode->i_cdev, struct hello_device, cdev); 

    filp->private_data = dev;
    printk (KERN_INFO "Hey! device opened\n");

    return 0;
}

static int hello_release (struct inode *inode, struct file *filp)
{
    printk (KERN_INFO "Hmmm... device closed\n");

    return 0;
}

ssize_t hello_read (struct file *filp, char *buff, size_t count, loff_t *offp)
{
    ssize_t result = 0;
    struct hello_device *dev = filp->private_data;

    if (count < 0) return -EINVAL;
    if (count > 127) count = 127;
    if (copy_to_user (buff, dev->data, count)) 
    {
        result = -EFAULT;
    }
    else
    {
        printk (KERN_INFO "wrote %d bytes\n", (int)count);
        result = count;
    }

    return result;
}

/*
 *ssize_t hello_write (struct file *filp, const char  *buf, size_t count,
 *        loff_t *f_pos)
 *{
 *    ssize_t ret = 0;
 *
 *    printk (KERN_INFO "Writing %d bytes\n", count);
 *    if (count > 127) return -ENOMEM;
 *    if (count < 0) return -EINVAL;
 *    if (copy_from_user (data, buf, count)) {
 *        ret = -EFAULT;
 *    }
 *    else {
 *        data[count] = '\0';
 *        printk (KERN_INFO"Received: %s\n", data);
 *        ret = count;
 *    }
 *
 *    return ret;
 *}
 */


struct file_operations hello_fops = {
    .owner = THIS_MODULE,
    .open  = hello_open,
    .release = hello_release,
    .read  = hello_read,
    /*  .write = hello_write */
};

static void char_reg_setup_cdev (struct cdev *cdev, dev_t devno)
{
    int error;

    cdev_init (cdev, &hello_fops);
    cdev->owner = THIS_MODULE;
    error = cdev_add (cdev, devno , 1);
    if (error)
        printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);
}

static int __init hello_2_init (void)
{
    int result;
    dev_t devno;

    devno = MKDEV (hello_major, hello_minor);
    result = register_chrdev_region (devno, number_of_devices, "hello_multi");

    if (result < 0) {
        printk (KERN_WARNING "hello: can't get major number %d\n", hello_major);
        return result;
    }
    my_class = class_create(THIS_MODULE,"multi_dev_class");
    if(IS_ERR(my_class)) 
    {
        printk("Err: failed in creating class.\n");
        return -1; 
    }
    device_create(my_class,NULL, devno, NULL, "multi_dev0");
    device_create(my_class,NULL, devno + 1, NULL, "multi_dev1");

    char_reg_setup_cdev (&hello_device[0].cdev, devno);
    char_reg_setup_cdev (&hello_device[1].cdev, devno+1);
    printk (KERN_INFO "char device registered\n");
    strcpy(hello_device[0].data, "0000000000000000000");
    strcpy(hello_device[1].data, "1111111111111111111");

    return 0;
}

static void __exit hello_2_exit (void)
{
    dev_t devno = MKDEV (hello_major, hello_minor);

    cdev_del (&hello_device[0].cdev);
    cdev_del (&hello_device[1].cdev);

    device_destroy(my_class, devno);         // delete device node under /dev//必须先删除设备,再删除class类
    device_destroy(my_class, devno + 1);     // delete device node under /dev//必须先删除设备,再删除class类
    class_destroy(my_class);                 // delete class created by us
    unregister_chrdev_region (devno, number_of_devices);
    printk("char device exited\n");
}

module_init (hello_2_init);
module_exit (hello_2_exit);
关键点是 96行 和 98行

Makefile
ifeq ($(KERNELRELEASE),)

KERNELDIR ?= /lib/modules/$(shell uname -r)/build 
#KERNELDIR ?= ~/wor_lip/linux-3.4.112
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 modules* Module*

.PHONY: modules modules_install clean

else
    obj-m := char_multi_dev.o
endif

test.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

int main (void) 
{
    int fd1, fd2;
    char buf[64];

    if ((fd1 = open ("/dev/multi_dev0",O_RDONLY)) < 0)
    {
        perror("fail to open");
        return -1;
    }
    if ((fd2 = open ("/dev/multi_dev1",O_RDONLY)) < 0)
    {
        perror("fail to open");
        return -1;
    }

    read(fd1, buf, 64);
    printf("read from device0 : %s\n", buf);
    read(fd2, buf, 64);
    printf("read from device1 : %s\n", buf);

    return 0;
}

结果:
> sudo insmod char_multi_dev.ko 
>sudo ./a.out 
read from device0 : 0000000000000000000
read from device1 : 1111111111111111111
>sudo rmmod char_multi_dev
>dmesg
[11074.012373] char device registered
[11087.349961] Hey! device opened
[11087.349965] Hey! device opened
[11087.349967] wrote 64 bytes
[11087.350021] wrote 64 bytes
[11087.350055] Hmmm... device closed
[11087.350057] Hmmm... device closed
[11115.543117] char device exited

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
淘宝上卖的16路PWM舵机驱动模块的51单片机程序 部分程序如下 #include #include #include #include typedef unsigned char uchar; typedef unsigned int uint; sbit scl=P1^3; //时钟输入线 sbit sda=P1^4; //数据输入/输出端 sbit KEY1=P2^0; sbit KEY2=P2^1; #define PCA9685_adrr 0x80// 1+A5+A4+A3+A2+A1+A0+w/r //片选地址,将焊接点置1可改变地址, // 当IIC总 呱嫌 多片PCA9685或相同地址时才需焊接 // #define PCA9685_SUBADR1 0x2 // #define PCA9685_SUBADR2 0x3 // #define PCA9685_SUBADR3 0x4 #define PCA9685_MODE1 0x0 #define PCA9685_PRESCALE 0xFE #define LED0_ON_L 0x6 #define LED0_ON_H 0x7 #define LED0_OFF_L 0x8 #define LED0_OFF_H 0x9 // #define ALLLED_ON_L 0xFA // #define ALLLED_ON_H 0xFB // #define ALLLED_OFF_L 0xFC // #define ALLLED_OFF_H 0xFD #define SERVOMIN 115 // this is the 'minimum' pulse length count (out of 4096) #define SERVOMAX 590 // this is the 'maximum' pulse length count (out of 4096) #define SERVO000 130 //0度对应4096的脉宽计数值 #define SERVO180 520 //180度对应4096的脉宽计算值,四个值可根据不同舵机修改 /**********************函数的声明*********************************/ /*--------------------------------------------------------------- 毫秒延时函数 ----------------------------------------------------------------*/ void delayms(uint z) { uint x,y; for(x=z;x>0;x--) for(y=148;y>0;y--); } /*--------------------------------------------------------------- IIC总线所需的通用函数 ----------------------------------------------------------------*/ /*--------------------------------------------------------------- 微妙级别延时函数 大于4.7us ----------------------------------------------------------------*/ void delayus() { _nop_(); //在intrins.h文件里 _nop_(); _nop_(); _nop_(); _nop_(); } /*--------------------------------------------------------------- IIC总线初始化函数 ----------------------------------------------------------------*/ void init() { sda=1; //sda scl使用前总是被拉高 delayus(); scl=1; delayus(); } /*--------------------------------------------------------------- IIC总线启动信号函数 ----------------------------------------------------------------*/ void start() { sda=1; delayus(); scl=1; //scl拉高时 sda突然来个低电平 就启动了IIC总线 delayus(); sda=0; delayus(); scl=0; delayus(); } /*--------------------------------------------------------------- IIC总线停止信号函数 ----------------------------------------------------------------*/ void stop() { sda=0; delayus(); scl=1; //scl拉高时 sda突然来个高电平 就停止了IIC总线 delayus(); sda=1; delayus(); } /*--------------------------------------------------------------- IIC总线应答信号函数 ----------------------------------------------------------------*/ void ACK() { uchar i; scl=1; delayus(); while((sda=1)&&(i<255)) i++; scl=0; delayus(); } /*--------------------------------------------------------------- 写一个字节,无返回值,需输入一个字节值 ----------------------------------------------------------------*/ void write_byte(uchar byte) { uchar i,temp; temp=byte; for(i=0;i<8;i++) { temp=temp<<1; scl=0; delayus(); sda=CY; delayus(); scl=1; delayus(); } scl=0; delayus(); sda=1; delayus(); } /*--------------------------------------------------------------- 读一个字节函数,有返回值 ----------------------------------------------------------------*/ uchar read_byte() { uchar i,j,k; scl=0; delayus(); sda=1; delayus(); for(i=0;i<8;i++) { delayus(); scl=1; delayus(); if(sda==1) { j=1; } else j=0; k=(k<< 1)|j; scl=0; } delayus(); return k; } /*--------------------------------------------------------------- 有关PCA9685模块的函数 ----------------------------------------------------------------*/ /*--------------------------------------------------------------- 向PCA9685里写地址,数据 ----------------------------------------------------------------*/ void PCA9685_write(uchar address,uchar date) { start(); write_byte(PCA9685_adrr); //PCA9685的片选地址 ACK(); write_byte(address); //写地址控制字节 ACK(); write_byte(date); //写数据 ACK(); stop(); } /*--------------------------------------------------------------- 从PCA9685里的地址值中读数据(有返回值) ----------------------------------------------------------------*/ uchar PCA9685_read(uchar address) { uchar date; start(); write_byte(PCA9685_adrr); //PCA9685的片选地址 ACK(); write_byte(address); ACK(); start(); write_byte(PCA9685_adrr|0x01); //地址的第八位控制数据流方向,就是写或读 ACK(); date=read_byte(); stop(); return date; }
很高兴为您服务,我可以为您提供一个STM32串口驱动程序的示例: #include <stm32f10x.h> //Define USART1 #define USART1_DR_Base 0x40013804 #define USART1_BRR 0x40013808 #define USART1_CR1 0x4001380C #define USART1_CR2 0x40013810 #define USART1_CR3 0x40013814 #define USART1_GTPR 0x40013818 //Define USART1 Baudrate #define USART1_Baudrate 9600 //Define USART1 GPIO #define USART1_GPIO_TX GPIOA,GPIO_Pin_9 #define USART1_GPIO_RX GPIOA,GPIO_Pin_10 //Define USART1 GPIO Mode #define USART1_GPIO_Mode GPIO_Mode_AF_PP //Define USART1 GPIO Speed #define USART1_GPIO_Speed GPIO_Speed_50MHz //Define USART1 GPIO Remap #define USART1_GPIO_Remap GPIO_Remap_USART1 //Function Prototype void USART1_Init(void); void USART1_SendByte(uint8_t data); uint8_t USART1_ReceiveByte(void); //USART1 Init Function void USART1_Init(void) { //Define Local Variables GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; //Enable USART1 and GPIOA Periph Clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); //Configure USART1_TX and USART1_RX Pin GPIO_InitStructure.GPIO_Pin = USART1_GPIO_TX | USART1_GPIO_RX; GPIO_InitStructure.GPIO_Mode = USART1_GPIO_Mode; GPIO_InitStructure.GPIO_Speed = USART1_GPIO_Speed; GPIO_Init(GPIOA, &GPIO_InitStructure); //Remap USART1_TX and USART1_RX GPIO_PinRemapConfig(USART1_GPIO_Remap, ENABLE); //Configure USART1 USART_InitStructure.USART_BaudRate = USART1_Baudrate; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); //Enable USART1 USART_Cmd(USART1, ENABLE); //Configure USART1 NVIC NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } //USART1 Send Byte Function void USART1_SendByte(uint8_t data) { USART_SendData(USART1, data); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } //USART1 Receive Byte Function uint8_t USART1_ReceiveByte(void) { while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); return (uint8_t)USART_ReceiveData(USART1); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值