Linux 通过uinput机制实现蜂鸣器驱动

通过uinput机制模拟了input设备,实现了蜂鸣器的控制。

系统内核:2.6.21 发布版本fedora7

1. 主要流程如下:

2. 详细代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/uinput.h>
#include <fcntl.h>
#include <linux/input.h>
#include <unistd.h>
#include "beep_drv.h"

#define BEEP_DEBUG 1

#define USER_CTL_DEV "/dev/input/uinput"

#define VENDOR 0x001f
#define PRODUCT 0x0001
#define VERSION 1

#define MAGIC_NUMBER 0x884

int s_beep_fd = 0;

int snd_handle(int value)
{
#if BEEP_DEBUG
  if (s_beep_fd <= 0)
    return -1;
#endif

  if (value == MAGIC_NUMBER){

#if BEEP_DEBUG
    set_beep_on(s_beep_fd);
#else
    printf("beep on\n");
#endif
  } else {

#if BEEP_DEBUG
    set_beep_off(s_beep_fd);
#else
    printf("beep off\n");
#endif
  }

  return 0;
}

int event_handler_loop(int fd)
{
	int ret = 0;
        fd_set rd;
        FD_ZERO(&rd);
        FD_SET(fd,&rd);
	struct input_event event;
       
        while(1){
          ret = select(fd+1,&rd,NULL,NULL,NULL);
          if (ret < 0){
            printf("select io err\n");
            return -1;
          }

          ret =  read(fd,&event,sizeof(struct input_event));
          if (ret <= 0){
            printf("read io err\n");
            continue;
          }
           
          //printf("get event: %x,%x,%x\n",event.type,event.code,event.value);
          if(event.type == EV_SND){
            switch(event.code){
               case SND_TONE:
                 snd_handle(event.value);
               break;
               default:
                 printf("unknown event\n");
               break;
            }
          }
        }

  return 0;
}


int beep_probe(void)
{
  int beep_fd = beeplight_open();
  if (beep_fd < 0){
     return -1;
  }
  
  s_beep_fd = beep_fd;
  return beep_fd;
}

int main(void)
{
	struct uinput_user_dev beeper_dev;

	int beep_fd, fd, ret;
#if BEEP_DEBUG
        beep_fd = beep_probe();
        if (beep_fd < 0){
          printf("beep device not found!\n");
          return -1;
        }
#endif 
	fd = open(USER_CTL_DEV, O_RDWR);
	if (fd < 0) {
           printf("no user input stuct\n");
	   return fd;
	}

	ret = ioctl(fd, UI_SET_EVBIT, EV_SND);
	ret = ioctl(fd, UI_SET_SNDBIT, SND_TONE);

	memset(&beeper_dev, 0, sizeof(struct uinput_user_dev));

	snprintf(beeper_dev.name, UINPUT_MAX_NAME_SIZE, "Beeper");
	beeper_dev.id.bustype = BUS_USB;
	beeper_dev.id.vendor = VENDOR;
	beeper_dev.id.product = PRODUCT;
	beeper_dev.id.version = VERSION;

	ret = write(fd, &beeper_dev, sizeof(struct uinput_user_dev));

	ret = ioctl(fd, UI_DEV_CREATE);
	if (ret < 0) { 
           close(fd);
	   return ret;
	}

        ret = event_handler_loop(fd);
        if (ret < 0){
          printf("event loop exit\n");
        }

	ioctl(fd, UI_DEV_DESTROY);

#if BEEP_DEBUG
        beeplight_close(beep_fd);
#endif
	close(fd);
          
	return 0;
}

3. 运行上述代码,没问题的话会在/dev/input/目录下产生event设备节点,类似于一般的鼠标键盘,也可以通过cat /proc/bus/input/devices查看,因为没有在事件处理中write上报事件,所以直接读设备节点/dev/input/event*是没有数据的,只有写设备节点的功能。因为只处理了EV_SND事件,所以只要按照EV_SND格式封装struct input_event数据结构,往这个设备节点写,就会传入到事件循环,进而控制蜂鸣器开和关,注意MAGIC_NUMBER是区别其他设备的参数,测试程序test如下:

#include <linux/input.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

#define MAGIC_NUMBER 0x884

int main(int argc,char*argv[])
{
   int i = 0;
   int fd = 0;
   char dev_name[32];
   struct input_id event_id;
   struct input_event event;
   int beep_on = 0;

   if (argc != 3){
     printf("./beep_test </dev/input/event*>  <0|1>\n");
     return -1;
   }

   beep_on = atoi(argv[2]);
   if (beep_on)
     beep_on = MAGIC_NUMBER;

   snprintf(dev_name,32,"%s",argv[1]);
   fd = open(dev_name,O_RDWR);
   if (fd < 0){
    perror("open:");
    return fd;
   }

   if(!ioctl(fd,EVIOCGID,&event_id)){
    printf("vendor:%04x,product:%04x\n",event_id.vendor,event_id.product);
   }

   event.type = EV_SND;
   event.code = SND_TONE;
   event.value = beep_on;
   write(fd,&event,sizeof(struct input_event));

   close(fd);
   
  return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值