zoukankan      html  css  js  c++  java
  • Linux 一种调用蜂鸣器的方法

    最近想试试能不能把蜂鸣器精度提高到微秒级,然后学习了一下 ioctl 的代码……

    和系统中断次数有关……也就是说现在很难提高到微秒级。然后使用了较为底层的实现,发现跑 10000 次还是要 0.6s ……

    终究败在了 io 速度上……?(当然我不太懂内核,如果有 dalao 知道具体的原因请教教我)

    不过还是发现了一个较为奇特的写法。

    首先我用的驱动是 pcspkr,然后我去 /drivers/input/misc/pcspkr.c 里找到了这么一段代码(撰写该文的时候版本为 5bfc75d92e):

    static int pcspkr_event(struct input_dev *dev, unsigned int type,
    			unsigned int code, int value)
    {
    	...
    	if (count) {
    		/* set command for counter 2, 2 byte write */
    		outb_p(0xB6, 0x43);
    		/* select desired HZ */
    		outb_p(count & 0xff, 0x42);
    		outb((count >> 8) & 0xff, 0x42);
    		/* enable counter 2 */
    		outb_p(inb_p(0x61) | 3, 0x61);
    	} else {
    		/* disable counter 2 */
    		outb(inb_p(0x61) & 0xFC, 0x61);
    	}
    	...
    	return 0;
    }
    

    然后发现和 dev 无关,这意味着我们只需要有 outb 等函数即可。

    于是我们就可以魔改出一个 beep 函数(当然我没加锁):

    #include <unistd.h> // usleep
    #include <linux/input.h> // SND_BELL, SND_TONE
    #include <sys/io.h> // ioperm, inb_p, outb, outb_p
    #include <iostream>
    #include <vector>
    
    #define PIT_TICK_RATE 1193182
    
    int beep(unsigned int code, int value) {
    	unsigned int count = 0;
    
    	switch (code) {
    		case SND_BELL:
    			if (value) value = 1000;
    			break;
    		case SND_TONE: break;
    		default: return -1;
    	}
    
    	if (value > 20 && value < 32767)
    		count = PIT_TICK_RATE / value;
    
    	if (count) {
    		outb_p(0xB6, 0x43);
    		outb_p(count & 0xff, 0x42);
    		outb((count >> 8) & 0xff, 0x42);
    		outb_p(inb_p(0x61) | 3, 0x61);
    	} else {
    		outb(inb_p(0x61) & 0xFC, 0x61);
    	}
    
    	return 0;
    }
    
    int main() {
    	std::vector<int> init{0x42, 0x43, 0x61, 0x80};
    	for (auto t : init) {
    		int ret = ioperm(t, 1, 1);
    		std::cout << std::hex << t << " : " << ioperm(t, 1, 1) << std::endl;
    	}
    	beep(SND_BELL, 1000); // 开始响
    	beep(SND_TONE, 600); // 调声高
    	usleep(1000000);
    	beep(SND_BELL, 0); // 停止
    	return 0;
    }
    
    

    注意到要使用 outb 等函数之前要 ioperm,而我这边库的 outb_p 实现中还用到了 0x80。这样我们就可以在用户态中使用 outb 这种函数了!

    然后还是要注意这东西需要管理员权限……我也不知道人家 beep 程序是怎么写的,怎么做到不用管理员权限的……当然想学一下辣

    然后就整了这么一个好像没啥用的东西。

  • 相关阅读:
    Largest Rectangle in Histogram
    Valid Sudoku
    Set Matrix Zeroes
    Unique Paths
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Path Sum II
    Path Sum
    Validate Binary Search Tree
    新手程序员 e
  • 原文地址:https://www.cnblogs.com/daklqw/p/14925298.html
Copyright © 2011-2022 走看看