linux蜂鸣器驱动指令,Linux 设备驱动简析—PC蜂鸣器驱动
/*
*By Neil Chiao ()
*欢迎到“新星湾()”指导
*/
在X86平台的主板上一般都有一个蜂鸣器,有人可能认为这么简单的东西,根本不需要驱动吧?但是其实Linux内核中专门有一个这样的驱动pcspkr.c。
(注意:本文分析的代码来自linux-2.6.28)
1、从用户空间代码开始
先看下面这个小程序,此程序的作用是让PC蜂鸣器叫,它open了/dev/tty10这个设备,难道PC蜂鸣器设备节点是/dev/tty10??
#include
#include
#include
int main(int argc, char *argv[])
{
int fd = open("/dev/tty10", O_RDONLY);
if (fd == -1 || argc != 3) return -1;
return ioctl(fd, KDMKTONE, (atoi(argv[2])<<16)+(1193180/atoi(argv[1])));
}
2、定位到内核中tty的ioctl实现(KDMKTONE)
其实,上述代码中,把/dev/tty10修改成tty2,tty5随便一个都是可以的(我试过的)。
下面定位到内核的tty实现,发现在vt_ioctl.c中有如下代码:
vt_ioctl()
{
......
case KDMKTONE:
if (!perm)
goto eperm;
{
unsigned int ticks, count;
ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
count = ticks ? (arg & 0xffff) : 0;
if (count)
count = CLOCK_TICK_RATE / count;
kd_mksound(count, ticks);
break;
}
......
}
上述代码最终调用kd_mksound函数来发声。kd_mksound函数实现如下:
void kd_mksound(unsigned int hz, unsigned int ticks)
{
struct list_head *node;
del_timer(&kd_mksound_timer);
if (hz) {
list_for_each_prev(node, &kbd_handler.h_list) {
struct input_handle *handle = to_handle_h(node);
if (test_bit(EV_SND, handle->dev->evbit)) {
if (test_bit(SND_TONE, handle->dev->sndbit)) {
input_inject_event(handle, EV_SND, SND_TONE, hz);
break;
}
if (test_bit(SND_BELL, handle->dev->sndbit)) {
input_inject_event(handle, EV_SND, SND_BELL, 1);
break;
}
}
}
if (ticks)
mod_timer(&kd_mksound_timer, jiffies + ticks);
} else
kd_nosound(0);
}
由代码,我们知道,kd_mksound函数实质上使用input_inject_event(handle, EV_SND, SND_TONE, hz)来触发了一个input事件,来使pc speaker叫。
3、input event机制
这里就涉及到了input子系统了,这个子系统还是比较复杂的,呵。
上述代码中的input_inject_event按下面顺序调用:
input_inject_eventà
input_handle_event(dev, type, code, value);à
input_pass_event
其中,input_handle_event如下:
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition = INPUT_IGNORE_EVENT;
switch (type) {
......
//PC
case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;
......
}
......
if (disposition & INPUT_PASS_TO_HANDLERS)
input_pass_event(dev, type, code, value);
}
input_pass_event函数实现如下:
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
if (handle)
handle->handler->event(handle, type, code, value);
else
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle,
type, code, value);
rcu_read_unlock();
}
PC蜂鸣器的event实现
input子系统根据input event的类型(PC蜂鸣器是EV_SND),最终调用相应的event处理,PC蜂鸣器的event在pcspkr.c中实现:
static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
unsigned int count = 0;
unsigned long flags;
if (type != EV_SND)
return -1;
switch (code) {
case SND_BELL: if (value) value = 1000;
case SND_TONE: break;
default: return -1;
}
if (value > 20 && value < 32767)
count = PIT_TICK_RATE / value;
spin_lock_irqsave(&i8253_lock, flags);
printk("count = %d\n",count);
//下面一段是让PC蜂鸣器叫最实质的实现,想看懂的话,请自己找ICH8南桥芯片手册看
if (count) {
outb_p(inb_p(0x61) | 3, 0x61);
outb_p(0xB6, 0x43);
outb_p(count & 0xff, 0x42);
outb((count >> 8) & 0xff, 0x42);
} else {
outb(inb_p(0x61) & 0xFC, 0x61);
}
spin_unlock_irqrestore(&i8253_lock, flags);
return 0;
}
linux蜂鸣器驱动指令,Linux 设备驱动简析—PC蜂鸣器驱动相关推荐
- linux c蜂鸣器驱动程序,Linux 设备驱动简析—PC蜂鸣器驱动
/* *By Neil Chiao () *欢迎到"新星湾()"指导 */ 在X86平台的主板上一般都有一个蜂鸣器,有人可能认为这么简单的东西,根本不需要驱动吧?但是其实Linux ...
- linux蜂鸣器驱动指令,linux蜂鸣器驱动 蜂鸣器--LINUX.doc
linux蜂鸣器驱动 蜂鸣器--LINUX 导读:就爱阅读网友为您分享以下"蜂鸣器--LINUX"的资讯,希望对您有所帮助,感谢您对92的支持! //mux = 1/16 tcfg ...
- Linux设备驱动简析—PC重启源码分析
Linux在PC上的关机和重启可能由两种行为引发,一是通过用户编程,一是系统自己产生的消息.用户和系统进行交互的方式也有两个,一个是系统调用:sys_reboot,另一个就是apm或acpi的设备文件 ...
- Linux设备树简析
1. 前言 限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺. 2. 设备树的来源 在 Linux 中,每个设备驱动,管理一组设备数据,类似面向对象编程中类和其实例对象的关 ...
- Linux进程描述符task_struct结构体简析
进程是处于执行期的程序以及它所管理的资源(如打开的文件.挂起的信号.进程状态.地址空间等等)的总称 Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个 ...
- linux中swi指令,Linux系统调用、新增系统调用方法
说明: 系统调用是内核和应用程序间的接口,应用程序要访问硬件设备和其他操作系统资源,可以通过系统调用来完成. 在linux中,系统调用是用户空间访问内核的一种手段,除异常和中断外,他们是进入内核的合法 ...
- linux ping大包指令,linux下ping命令使用详解,
linux下ping命令使用详解, •ping命令一般用于检测网络通与不通,也叫时延,其值越大,速度越慢PING(PacketInternetGrope),因特网包探索器,用于测试网络连接量的程序. ...
- linux修改时间指令,Linux 修改时间的指令
查询现在的时间 date "+%Y%m%d%H%M.%S" %Y->年 %m->月 %d->日 %H->时 %M->分 %S->秒 查出来后可直 ...
- linux df -h指令,Linux df 命令使用参数详解
df命令用来检查linux系统的文件系统的磁盘空间使用情况. 语法及格式 df [选项] [文件名] 常见参数 -a:--all,显示所有的文件系统,包括虚拟文件系统,参考示例2. -B:--bloc ...
- linux拨号上网指令,linux中的pppoe拨号上网
实例:(linux中的pppoe拨号上网) ①安装软件:把下载的pppoe传到linux下的/root目录下,在终端对软件进行拆包: ll:查看目录,能看见软件包的名字 tar -zxvf rp-pp ...
最新文章
- 使用 OpenMVG+PMVS实现视觉三维重建
- vs2012下 error4996
- 如何获取 docker 容器(container)的 ip 地址
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(18)-过滤器的使用和批量删除数据(伪删除和直接删除)...
- puppet(1.1-1.6)
- 【Elasticsearch】Elasticsearch 动态模板(Dynamic templates)
- FFmpeg总结(七)AV系列结构体之AVIOContext
- pearson相关系数_pearson相关系数与典型相关性分析(CCA)
- 【2020春招记录】 吉比特游戏研发笔试
- LG化学成为海水淡化领域膜领导品牌后,大举进军苦咸水反渗透膜市场
- 用python提取字符串的中英文——建议收藏反复观看
- openeuler 欧拉操作系统的几个图形界面安装方法
- linux/安卓的spi读写ADS1256出现读写错误
- win32asm导入表
- x722网卡支持百兆吗_用200M宽带,电脑网卡却只有百兆?这样可以解决!
- ORA-00257:archiver error.Connect internal only, until freed 问题解决
- Covid-19 肺部 X 射线分类和 CT 检测演示
- Mysql传智jing_dong数据库
- stdafx.h与Afx.h了解
- smcsuperio黑苹果_基于OpenCore0.6.1的黑苹果安装,小白也能看
热门文章
- 第二周 半导体器件基础(二)
- [SAP ABAP开发技术总结]增强Enhancement
- 简单线性回归R和Python预测身高体重国内生产总值二氧化碳排放量
- FreeRTOS下开启fatfs文件重入功能后,“Error:..\..\FreeRTOS\src\queue.c,1248“报错问题解决
- 团购幸存者:团购是个苦生意
- 怎么把pdf文件转换成word方法分享
- 二维数组更改vue,VueX中直接修改数据报错,修改一维数组,二维数组,报错的原因...
- 微信网页扫码登录的实现
- java 水波纹_java实现水波纹扩散效果
- 计算机中c盘是什么分区,电脑C盘怎么分区