《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》
《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》
第一部分、章節目錄
5.6.1.板載蜂鳴器驅動測試
5.6.2.misc類裝置介紹
5.6.3.misc驅動框架原始碼分析1
5.6.4.misc驅動框架原始碼分析2
5.6.5.蜂鳴器驅動原始碼分析1
5.6.6.蜂鳴器驅動原始碼分析2
第二部分、章節介紹
5.6.1.板載蜂鳴器驅動測試
本節使用核心中提供的蜂鳴器驅動來實踐測試蜂鳴器,要同時解決驅動層的問題和應用程式的編寫。
5.6.2.misc類裝置介紹
本節系統介紹misc類裝置的概念和分類特點,並且對misc類裝置的驅動框架詳細講解。
5.6.3.misc驅動框架原始碼分析1
本節分析misc類裝置驅動框架中核心自己實現的部分,即misc.c。
5.6.4.misc驅動框架原始碼分析2
本節繼續分析misc.c,重點是訊號量及其使用的一般技巧。
5.6.5.蜂鳴器驅動原始碼分析1
本節分析九鼎提供的buzzer驅動原始碼
5.6.6.蜂鳴器驅動原始碼分析2
本節分析九鼎提供的buzzer驅動原始碼
第三部分、隨堂記錄
5.6.1.板載蜂鳴器驅動測試
5.6.1.1、驅動部分
(1)九鼎移植核心已經提供了蜂鳴器驅動原始碼
(2)make menuconfig
(3)bug排查。修改Makefile中的巨集名,最終可以在系統中看到 /dev/buzzer
5.6.1.2、應用部分
(1)應用編寫:開啟檔案+ioctl
(2)測試實踐
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#define DEVNAME "/dev/buzzer"
#define PWM_IOCTL_SET_FREQ 1
#define PWM_IOCTL_STOP 0
int main(void)
{
int fd = -1;
fd = open(DEVNAME, O_RDWR);
if (fd < 0)
{
perror("open");
return -1;
}
ioctl(fd, PWM_IOCTL_SET_FREQ, 10000);
sleep(3);
ioctl(fd, PWM_IOCTL_STOP);
sleep(3);
ioctl(fd, PWM_IOCTL_SET_FREQ, 3000);
sleep(3);
ioctl(fd, PWM_IOCTL_STOP) ;
sleep(3);
close(fd);
return 0;
}
5.6.2.misc類裝置介紹
5.6.2.1、何為misc
(1)中文名:雜項裝置\雜散裝置
(2)/sys/class/misc
(3)典型的字元裝置
(4)有一套驅動框架,核心實現一部分(misc.c),驅動實現一部分(x210-buzzer.c)。
(5)misc是對原始的字元設備註冊介面的一個類層次的封裝,很多典型字元裝置都可以歸類到misc類中,使用misc驅動框架來管理。
5.6.2.2、misc類裝置驅動架構
(1)核心開發者實現部分,關鍵點有2個:一個是類的建立,另一個是開放給驅動開發者的介面
(2)具體裝置驅動工程師實現部分
5.6.2.3、本部分學習方法
(1)蜂鳴器驅動原始碼已有,分析為主
(2)複習並驗證前面講的驅動框架的思維
(3)有餘力的不妨開始注意一些細節
5.6.3.misc驅動框架原始碼分析1
5.6.3.1、misc原始碼框架基礎
(1)misc原始碼框架本身也是一個模組,核心啟動時自動載入
(2)原始碼框架的主要工作:註冊misc類,使用老介面註冊字元裝置驅動(主裝置號10),開放device註冊的介面misc_register給驅動工程師
5.6.3.2、misc類裝置的註冊
(1)驅動工程師需要藉助misc來載入自己的驅動時,只需要呼叫misc_register介面註冊自己的裝置即可,其餘均不用管。
(2)misc_list連結串列的作用。核心定義了一個misc_list連結串列用來記錄所有核心中註冊了的雜散類裝置。當我們向核心註冊一個misc類裝置時,核心就會向misc_list連結串列中insert一個節點。
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name)
struct list_head name = LIST_HEAD_INIT(name)
原式子:static LIST_HEAD(misc_list);
展開後:static struct list_head misc_list = { &(misc_list), &(misc_list) }
(3)主裝置號和次裝置號的作用和區分
/*
* linux/drivers/char/misc.c
*
* Generic misc open routine by Johan Myreen
*
* Based on code from Linus
*
* Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
* changes incorporated into 0.97pl4
* by Peter Cervasio (pete%[email protected]) (08SEP92)
* See busmouse.c for particulars.
*
* Made things a lot mode modular - easy to compile in just one or two
* of the misc drivers, as they are now completely independent. Linus.
*
* Support for loadable modules. 8-Sep-95 Philip Blundell <[email protected]>
*
* Fixed a failing symbol register to free the device registration
* Alan Cox <[email protected]> 21-Jan-96
*
* Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
*
* Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96
*
* Handling of mouse minor numbers for kerneld:
* Idea by Jacques Gelinas <[email protected]>,
* adapted by Bjorn Ekwall <[email protected]>
* corrected by Alan Cox <[email protected]>
*
* Changes for kmod (from kerneld):
* Cyrus Durgin <[email protected]>
*
* Added devfs support. Richard Gooch <[email protected]> 10-Jan-1998
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
/*
* Head entry for the doubly linked miscdevice list
*/
static LIST_HEAD(misc_list);
static DEFINE_MUTEX(misc_mtx);
/*
* Assigned numbers, used for dynamic minors
*/
#define DYNAMIC_MINORS 64 /* like dynamic majors */
static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
{
mutex_lock(&misc_mtx);
return seq_list_start(&misc_list, *pos);
}
static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
return seq_list_next(v, &misc_list, pos);
}
static void misc_seq_stop(struct seq_file *seq, void *v)
{
mutex_unlock(&misc_mtx);
}
static int misc_seq_show(struct seq_file *seq, void *v)
{
const struct miscdevice *p = list_entry(v, struct miscdevice, list);
seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
return 0;
}
static const struct seq_operations misc_seq_ops = {
.start = misc_seq_start,
.next = misc_seq_next,
.stop = misc_seq_stop,
.show = misc_seq_show,
};
static int misc_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &misc_seq_ops);
}
static const struct file_operations misc_proc_fops = {
.owner = THIS_MODULE,
.open = misc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
#endif
static int misc_open(struct inode * inode, struct file * file)
{
int minor = iminor(inode);
struct miscdevice *c;
int err = -ENODEV;
const struct file_operations *new_fops = NULL;
mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
new_fops = fops_get(c->fops);
break;
}
}
if (!new_fops) {
mutex_unlock(&misc_mtx);
request_module("char-major-%d-%d", MISC_MAJOR, minor);
mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
new_fops = fops_get(c->fops);
break;
}
}
if (!new_fops)
goto fail;
}
/*
* Place the miscdevice in the file's
* private_data so it can be used by the
* file operations, including f_op->open below
*/
file->private_data = c;
err = 0;
replace_fops(file, new_fops);
if (file->f_op->open)
err = file->f_op->open(inode,file);
fail:
mutex_unlock(&misc_mtx);
return err;
}
static struct class *misc_class;
static const struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.llseek = noop_llseek,
};
/**
* misc_register - register a miscellaneous device
* @misc: device structure
*
* Register a miscellaneous device with the kernel. If the minor
* number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
* and placed in the minor field of the structure. For other cases
* the minor number requested is used.
*
* The structure passed is linked into the kernel and may not be
* destroyed until it has been unregistered. By default, an open()
* syscall to the device sets file->private_data to point to the
* structure. Drivers don't need open in fops for this.
*
* A zero is returned on success and a negative errno code for
* failure.
*/
int misc_register(struct miscdevice * misc)
{
dev_t dev;
int err = 0;
bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR);
INIT_LIST_HEAD(&misc->list);
mutex_lock(&misc_mtx);
if (is_dynamic) {
int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
if (i >= DYNAMIC_MINORS) {
err = -EBUSY;
goto out;
}
misc->minor = DYNAMIC_MINORS - i - 1;
set_bit(i, misc_minors);
} else {
struct miscdevice *c;
list_for_each_entry(c, &misc_list, list) {
if (c->minor == misc->minor) {
err = -EBUSY;
goto out;
}
}
}
dev = MKDEV(MISC_MAJOR, misc->minor);
misc->this_device =
device_create_with_groups(misc_class, misc->parent, dev,
misc, misc->groups, "%s", misc->name);
if (IS_ERR(misc->this_device)) {
if (is_dynamic) {
int i = DYNAMIC_MINORS - misc->minor - 1;
if (i < DYNAMIC_MINORS && i >= 0)
clear_bit(i, misc_minors);
misc->minor = MISC_DYNAMIC_MINOR;
}
err = PTR_ERR(misc->this_device);
goto out;
}
/*
* Add it to the front, so that later devices can "override"
* earlier defaults
*/
list_add(&misc->list, &misc_list);
out:
mutex_unlock(&misc_mtx);
return err;
}
/**
* misc_deregister - unregister a miscellaneous device
* @misc: device to unregister
*
* Unregister a miscellaneous device that was previously
* successfully registered with misc_register().
*/
void misc_deregister(struct miscdevice *misc)
{
int i = DYNAMIC_MINORS - misc->minor - 1;
if (WARN_ON(list_empty(&misc->list)))
return;
mutex_lock(&misc_mtx);
list_del(&misc->list);
device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
if (i < DYNAMIC_MINORS && i >= 0)
clear_bit(i, misc_minors);
mutex_unlock(&misc_mtx);
}
EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);
static char *misc_devnode(struct device *dev, umode_t *mode)
{
struct miscdevice *c = dev_get_drvdata(dev);
if (mode && c->mode)
*mode = c->mode;
if (c->nodename)
return kstrdup(c->nodename, GFP_KERNEL);
return NULL;
}
static int __init misc_init(void)
{
int err;
struct proc_dir_entry *ret;
ret = proc_create("misc", 0, NULL, &misc_proc_fops);
misc_class = class_create(THIS_MODULE, "misc");
err = PTR_ERR(misc_class);
if (IS_ERR(misc_class))
goto fail_remove;
err = -EIO;
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
goto fail_printk;
misc_class->devnode = misc_devnode;
return 0;
fail_printk:
printk("unable to get major %d for misc devices\n", MISC_MAJOR);
class_destroy(misc_class);
fail_remove:
if (ret)
remove_proc_entry("misc", NULL);
return err;
}
subsys_initcall(misc_init);
5.6.4.misc驅動框架原始碼分析2
5.6.4.1、open函式分析
5.6.4.2、misc在proc下的展現
5.6.4.3、核心互斥鎖
(1)何為互斥鎖
(2)定義:DEFINE_MUTEX
(3)上鎖mutex_lock和解鎖mutex_unlock
(4)核心防止競爭狀態的手段:原子訪問、自旋鎖、互斥鎖、訊號量
(5)原子訪問主要用來做計數、自旋鎖後面講中斷會詳細講、互斥鎖和訊號量很相似(其實就是計數值為1的訊號量),互斥鎖的出現比訊號量晚,實現上比訊號量優秀,儘量使用互斥鎖。
5.6.5.蜂鳴器驅動原始碼分析1
5.6.5.1、dev_init
(1)訊號量
(2)miscdevice
(3)gpio_request
(4)printk
5.6.5.2、ioctl
(1)為什麼需要ioctl(input output control,輸入輸出控制)。
(2)ioctl怎麼用
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <plat/gpio-cfg.h>
//#include <plat/regs-clock.h>
//#include <plat/regs-gpio.h>
//#include <plat/gpio-bank-e.h>
//#include <plat/gpio-bank-f.h>
//#include <plat/gpio-bank-k.h>
#define DEVICE_NAME "buzzer"
#define PWM_IOCTL_SET_FREQ 1
#define PWM_IOCTL_STOP 0
static struct semaphore lock; //定義一個訊號量
// TCFG0在Uboot中設定,這裡不再重複設定
// Timer0輸入頻率Finput=pclk/(prescaler1+1)/MUX1
// =66M/16/16
// TCFG0 = tcnt = (pclk/16/16)/freq;
// PWM0輸出頻率Foutput =Finput/TCFG0= freq
static void PWM_Set_Freq( unsigned long freq )
{
unsigned long tcon;
unsigned long tcnt;
unsigned long tcfg1;
struct clk *clk_p;
unsigned long pclk;
//unsigned tmp;
//設定GPD0_2為PWM輸出
s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(2));
tcon = __raw_readl(S3C2410_TCON);
tcfg1 = __raw_readl(S3C2410_TCFG1);
//mux = 1/16
tcfg1 &= ~(0xf<<8);
tcfg1 |= (0x4<<8);
__raw_writel(tcfg1, S3C2410_TCFG1);
clk_p = clk_get(NULL, "pclk");
pclk = clk_get_rate(clk_p);
tcnt = (pclk/16/16)/freq;
__raw_writel(tcnt, S3C2410_TCNTB(2));
__raw_writel(tcnt/2, S3C2410_TCMPB(2));//佔空比為50%
tcon &= ~(0xf<<12);
tcon |= (0xb<<12); //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0
__raw_writel(tcon, S3C2410_TCON);
tcon &= ~(2<<12); //clear manual update bit
__raw_writel(tcon, S3C2410_TCON);
}
void PWM_Stop( void )
{
//將GPD0_2設定為input
s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(0));
}
static int x210_pwm_open(struct inode *inode, struct file *file)
{
if (!down_trylock(&lock))
return 0;
else
return -EBUSY;
}
static int x210_pwm_close(struct inode *inode, struct file *file)
{
up(&lock);
return 0;
}
// PWM:GPF14->PWM0
static int x210_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
case PWM_IOCTL_SET_FREQ:
printk("PWM_IOCTL_SET_FREQ:\r\n");
if (arg == 0)
return -EINVAL;
PWM_Set_Freq(arg);
break;
case PWM_IOCTL_STOP:
default:
printk("PWM_IOCTL_STOP:\r\n");
PWM_Stop();
break;
}
return 0;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = x210_pwm_open,
.release = x210_pwm_close,
.ioctl = x210_pwm_ioctl,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR, //255 系統自動分配次裝置號
.name = DEVICE_NAME, //裝置名字
.fops = &dev_fops, //file_operations結構體
相關推薦
《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》
《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》
第一部分、章節目錄 5.6.1.板載蜂鳴器驅動測試 5.6.2.misc類裝置介紹 5.6.3.misc驅動框架原始碼分析1 5.6.4.misc驅動框架原始碼分析2 5.6.5.蜂鳴器驅動原始碼分析1 5.6.6
6.misc類裝置與蜂鳴器驅動
第三部分、隨堂記錄
1.板載蜂鳴器驅動測試
1.1、驅動部分
(1)九鼎移植核心已經提供了蜂鳴器驅動原始碼
(2)make menuconfig
(3)bug排查。修改Makefile中的巨集名
《linux驅動開發-第11部分-5.11.網路裝置驅動介紹》
《linux驅動開發-第11部分-5.11.網路裝置驅動介紹》
第一部分、章節目錄 5.11.1.網路裝置驅動概述 5.11.2.虛擬網絡卡驅動分析1 5.11.3.虛擬網絡卡驅動分析2 5.11.4.DM9000驅動原始碼分析1 5.11.5.DM9000驅動原始碼分析2
第二部分
《5.linux驅動開發-第10部分-5.10.塊裝置驅動介紹》
《5.linux驅動開發-第10部分-5.10.塊裝置驅動介紹》
第一部分、章節目錄 5.10.1.正確理解塊裝置驅動的概念 5.10.2.塊裝置驅動框架簡介 5.10.3.塊裝置驅動案例分析1 5.10.4.塊裝置驅動案例分析2 5.10.5.塊裝置驅動案例分析3
第二部分、章節介
《5.linux驅動開發-第7部分-5.7.framebuffer驅動詳解》
《5.linux驅動開發-第7部分-5.7.framebuffer驅動詳解》
第一部分、章節目錄 5.7.1.framebuffer介紹 5.7.2.framebuffer應用程式設計實踐1 5.7.3.framebuffer應用程式設計實踐2 5.7.4.framebuffer應用程式
《5.linux驅動開發-第4部分-5.4.驅動框架入門之LED》
《5.linux驅動開發-第4部分-5.4.驅動框架入門之LED》
第一部分、章節目錄 5.4.1.何謂驅動框架 5.4.2.核心驅動框架中LED的基本情況 5.4.3.初步分析led驅動框架原始碼1 5.4.4.初步分析led驅動框架原始碼2 5.4.5.在核心中新增或去除某個驅動 5
《5.linux驅動開發-第3部分-5.3.字元裝置驅動高階》
《5.linux驅動開發-第3部分-5.3.字元裝置驅動高階》
第一部分、章節目錄 5.3.1.註冊字元裝置驅動新介面1 5.3.2.註冊字元裝置驅動新介面2 5.3.3.註冊字元裝置驅動新介面3 5.3.4.註冊字元裝置驅動新介面4 5.3.5.字元裝置驅動註冊程式碼分析1 5.3.6
《5.linux驅動開發-第2部分-5.2.字元裝置驅動基礎》
《5.linux驅動開發-第2部分-5.2.字元裝置驅動基礎》
第一部分、章節目錄 5.2.1.開啟驅動開發之路 5.2.2.最簡單的模組原始碼分析1 5.2.3.最簡單的模組原始碼分析2 5.2.4.最簡單的模組原始碼分析3 5.2.5.用開發板來除錯模組 5.2.6.字元裝置驅動工作
《5.linux驅動開發-第1部分-5.1.驅動應該怎麼學》
《5.linux驅動開發-第1部分-5.1.驅動應該怎麼學》
第一部分、章節目錄 5.1.1.什麼是驅動1 5.1.2.什麼是驅動2 5.1.3.模組化設計 5.1.4.linux裝置驅動分類 5.1.5.驅動程式的安全性要求 5.1.6.驅動應該這麼學
第二部分、章節介紹 5.1.
linux驅動開發之蜂鳴器驅動源碼分析(一)
linux 蜂鳴器 驅動 蜂鳴器的驅動源碼在/driver/char/buzzer/x210-buzzer.c文件中,源碼如下#include <linux/module.h>
#include <linux/kernel.h>
#include <linux
嵌入式Linux之我行——PWM在ARM Linux中的原理和蜂鳴器驅動例項開發
嵌入式Linux之我行,主要講述和總結了本人在學習嵌入式linux中的每個步驟。一為總結經驗,二希望能給想入門嵌入式Linux的朋友提供方便。如有錯誤之處,謝請指正。
一、開發環境
主 機:VMWare--Fedora 9
開發板:Mini2440--64MB N
linux驅動開發10之misc及蜂鳴器驅動
1.板載蜂鳴器驅動測試
1.1驅動部分
1)九鼎移植核心已經提供了蜂鳴器驅動原始碼
2)make menuconfig
3)bug排查。修改Makefile中的巨集名,最終可以在系統中看到 /dev/buzzer
由於makefile檔案與Kconfig檔案中的
[S5PV210 Linux字元驅動之PWM蜂鳴器驅動
在SMDK210.C中新增如下beeper_device 結構體
static struct platform_device beeper_device = {.name= "pwm_buzzer",.id = 1,.dev= {.parent
= &am
am335x_y蜂鳴器驅動
ati b-s dev mach-o name ive () drivers app 修改文件:1、板級文件/arch/arm/mach-omap2/board-am335xevm.c
static struct platform_device buzzer_device=
訊為4412蜂鳴器驅動實現
最近在搞訊為開發板的驅動,終於將訊為的蜂鳴器驅動搞定,現在進行一個總結。
編寫流程:
(1)分析硬體原理圖
要控制beep ----> gpd0_0 --->
高效蜂鳴器驅動法:用定時器掃描代替軟體延時
上班跟上學果然不一樣,就比如一個蜂鳴器的驅動,學生時代寫蜂鳴器的程式倒也直觀:
PWM_SET(0x0a,0x80);//PWM0輸出4.24Khz,佔空比50%
Delay_ms(200);//延時200ms
《5.linux驅動開發-第5部分-5.8.input子系統基礎之按鍵》
《5.linux驅動開發-第5部分-5.8.input子系統基礎之按鍵》
第一部分、章節目錄 5.8.1.什麼是input子系統 5.8.2.input裝置應用層程式設計實踐1 5.8.3.input裝置應用層程式設計實踐2 5.8.4.input子系統架構總覽1 5.8.5.input
《5.linux驅動開發-第5部分-5.5.linux裝置驅動模型》
《5.linux驅動開發-第5部分-5.5.linux裝置驅動模型》
第一部分、章節目錄 5.5.1.linux裝置驅動模型簡介 5.5.2.裝置驅動模型的底層架構 5.5.3.匯流排式裝置驅動組織方式 5.5.4.platform平臺匯流排簡介1 5.5.5.platform平臺匯流排
linux操作指令 第三部分
groupdel 手動 左右 del cat pass useradd user 用戶操作 文件簡單操作
1.文件內容查看 > cat filename //一次性把全部內容都輸出到終端 > more filename
Linux驅動開發(3)——以module方式註冊裝置
通過 s3c_device_leds_ctl->*smdk4x12_devices[]->platform_add_devices()->platform_device_register() 可以直接使用“platform_device_register()”來註冊裝置