当前位置:文档之家› linux音频alsa-uda134x驱动分析

linux音频alsa-uda134x驱动分析

linux音频alsa-uda134x驱动分析
linux音频alsa-uda134x驱动分析

linux音频alsa-uda134x驱动分析之一

https://www.doczj.com/doc/2614432378.html,/thread-1740-1-1.html

前言

目前,linux系统常用的音频驱动有两种形式:alsa oss

alsa:现在是linux下音频驱动的主要形式,与简单的oss兼容。

oss:过去的形式

而我们板子上的uda1341用的就是alsa驱动。

alsa概述:

因为我们用的是板上系统,用的也是alsa的一个soc子系统。所以我们直接讲解alsa soc 子系统。

ALSA SoC Layer

ALSA板上系统层

==============

The overall project goal of the ALSA System on Chip(ASoC)layer is to provide better ALSA support for embedded system-on-chip processors(e.g. pxa2xx,au1x00,iMX,etc)and portable audio codecs.Prior to the ASoC subsystem there was some support in the kernel for SoC audio,however it had some limitations:-

ALSA板上系统(ASoC)层的总体项目目标,是为对SOC嵌入式处理器和便携音频解码器提供更好的ALSA支持。在ASoC子系统之前,己有对内核的SoC音频支持,但是那些支持存在一些局限:

Codec drivers were often tightly coupled to the underlying SoC CPU.This is not ideal and leads to code duplication-for example,

Linux had different wm8731drivers for4different SoC platforms.

解码器常常与底层嵌入式处理器一对一紧密结合。这是非理想化的,因为这将导致代码的重复-例如,对四个不同的嵌入式平台,Linux要有不同的wm8731驱动。(理想的状态是我们可以只有一个wm8731的驱动代码,就可以对应于四个不同的处理器,但由上面说的,解码器-这里的wm8731与底层嵌入式处理器结合过于紧密,无法实现wm8731驱动代码的复用)

*There was no standard method to signal user initiated audio events(e.g.

Headphone/Mic insertion,Headphone/Mic detection after an insertion

event).These are quite common events on portable devices and often require machine specific code to re-route audio,enable amps,etc.,after such an event.

没有一个标准的方法可以产生用户初始化音频事件的信号(即,耳机/麦克插入,响应插入事件的耳机/麦克探测)。这些在便携设备上都是十分常见的事件并且在这些事件之后经常需要机器相关的代码来对音频重设路径,开启放大器等。

*Drivers tended to power up the entire codec when playing(or recording)audio.This is fine for a PC,but tends to waste a lot of power on portable devices.There was also no support for saving

power via changing codec oversampling rates,bias currents,etc.

放音(录音)时,驱动常常会打开整个解码器。对个人电脑来说这没什么问题,但是在便携设备上往往会导致电能的浪费。另外,也没有通过改变解码器采样率、偏置电流等方式来省电的支持。

ASoC Design

ASoC设计

===========

The ASoC layer is designed to address these issues and provide the following features:-

ASoC层被设计用来解决这些问题并提供如下特性:

*Codec independence.Allows reuse of codec drivers on other platforms and machines.

解码器独立。允许在其它平台或机器上重用解码器驱动。

*Easy I2S/PCM audio interface setup between codec and SoC.Each SoC interface and codec registers it's audio interface capabilities with the core and are subsequently matched and configured when the application hardware parameters are known.

解码器与SoC的I2S/PCM音频接口设置很容易。每个SoC接口与解码器都向ALSA核心注册它的音频接口能力,而且应用硬件参数己知时顺序匹配并配置。

*Dynamic Audio Power Management(DAPM).DAPM automatically sets the codec to

its minimum power state at all times.This includes powering up/down

internal power blocks depending on the internal codec audio routing and any active streams.

动态音频电源管理(DAPM)。DAPM自动无论何时,总是把解码器自动设置为它的最小电源状态。这包括依据内部解码音频线路和活跃的流来开启和关闭内部电源模块

*Pop and click reduction.Pops and clicks can be reduced by powering the codec up/down in the correct sequence(including using digital mute).ASoC signals the codec when to change power states.

咔嗒声减少。咔嗒声可以通过使用正确的解码器电源开启和关闭顺序而减少(包括使用数字消音)。ASoC在改变电源状态时向解码器发出信号。

*Machine specific controls:Allow machines to add controls to the sound card

(e.g.volume control for speaker amplifier).

机器相关的控制:允许机器增加对声卡的控制。(如扬声器放大器的音量控制)。

To achieve all this,ASoC basically splits an embedded audio system into3

components:-

要实现这些,ASoC基本上将嵌入式音频系统分为3个部分:

*Codec driver:The codec driver is platform independent and contains audio controls,audio interface capabilities,codec DAPM definition and codec IO functions.

解码器驱动:解码器驱动是平台无关的,包含音频控制、音频接口能力、解码器动态音频电源管理和解码器IO函数。

*Platform driver:The platform driver contains the audio DMA engine and audio interface drivers(e.g.I2S,AC97,PCM)for that platform.

平台驱动:平台驱动包含相应平台的音频DAM引擎和音频接口驱动(如I2S,AC97,PCM)

*Machine driver:The machine driver handles any machine specific controls and

audio events(e.g.turning on an amp at start of playback).

机器驱动:机器驱动处理所有机器相关的控制和音频事件(如回放开始时打开放大器)。

Documentation

文档

=============

The documentation is spilt into the following sections:-

本文档分成如下部分:

overview.txt:This file.

overview.txt:概述,本文件。

codec.txt:Codec driver internals.

codec.txt:解码器驱动内部实现

DAI.txt:Description of Digital Audio Interface standards and how to configure a DAI within your codec and CPU DAI drivers.

DAI.txt:对数字音频接口(DAI)标准和如何配置你的解码器和CPU的数字音频接品驱动中的数字音频接口的描述。

dapm.txt:Dynamic Audio Power Management

dapm.txt:动态音频电源管理

platform.txt:Platform audio DMA and DAI.

platform.txt:平台音频DMA和DAI。

machine.txt:Machine driver internals.

machine.txt:机器驱动内容介绍。

pop_clicks.txt:How to minimise audio artifacts.

pop_clicks.txt:如何最小化音步噪声。

clocking.txt:ASoC clocking for best power performance.

clocking.txt:最佳电源表现下的ASoC时钟

linux音频alsa-uda134x驱动分析之二(时钟)

https://www.doczj.com/doc/2614432378.html,/thread-1741-1-1.html

Audio Clocking

音频时钟

==============

This text describes the audio clocking terms in ASoC and digital audio in general.Note:Audio clocking can be complex!

本文本总体描述ASoC和数字音频中的音频时钟条款。

Master Clock

主时钟

------------

Every audio subsystem is driven by a master clock(sometimes referred to as MCLK or SYSCLK).This audio master clock can be derived from a number of sources (e.g.crystal,PLL,CPU clock)and is responsible for producing the correct audio playback and capture sample rates.

每个数字音频子系统都是由主时钟来驱动的(有时称为MCLK或SYSCLK)。音频主时钟可以派生于多种源(如晶振,锁相环,处理器时钟)。负责产生正确的音频播放和捕获采样率。

Some master clocks(e.g.PLLs and CPU based clocks)are configurable in that their speed can be altered by software(depending on the system use and to save power).Other master clocks are fixed at a set frequency(i.e.crystals).

有些主时钟是可配置的(如基于锁相环或处理器的时钟),它们可以通过软件改变速度(依赖于系统应用和省电的考虑)。另一些主时钟则是固定于一个特定的频率值(如晶振)。

DAI Clocks

数字音频时钟

----------

The Digital Audio Interface is usually driven by a Bit Clock(often referred

to

as BCLK).This clock is used to drive the digital audio data across the link between the codec and CPU.

数字音频接口往往是由一个位时钟来驱动的(通常记为BCLK)。这个时钟用于驱动数字音频数据在解码器与处理器间的传输。

The DAI also has a frame clock to signal the start of each audio frame.This clock is sometimes referred to as LRC(left right clock)or FRAME.This clock runs at exactly the sample rate(LRC=Rate).

数字音频接口还有一个帧时钟,用来指示一帧音频的开始。该时钟有时记为LRC(left right clock)或FRAME。该时钟严格工作于采样率上。

Bit Clock can be generated as follows:-

位时钟可以有如下产生方式:

BCLK=MCLK/x

or

BCLK=LRC*x

or

BCLK=LRC*Channels*Word Size

This relationship depends on the codec or SoC CPU in particular.In general it is best to configure BCLK to the lowest possible speed(depending on your rate,number of channels and word size)to save on power.

这个关系依赖于解码器,特别是板上处理器。大体上讲,最好将位时钟尽可能低速(取决于你的采样率,通道数和字长)以省电。

It is also desirable to use the codec(if possible)to drive(or master)the audio clocks as it usually gives more accurate sample rates than the CPU.

可能的话,最好使用解码器来驱动(或控制)音频时钟,因为通常它给出的采样率比处理器更精确。

linux音频alsa-uda134x驱动分析之三(解码器)

https://www.doczj.com/doc/2614432378.html,/thread-1742-1-1.html

ASoC Codec Driver

ASoC解码器驱动

=================

The codec driver is generic and hardware independent code that configures the codec to provide audio capture and playback.It should contain no code that is

specific to the target platform or machine.All platform and machine specific code should be added to the platform and machine drivers respectively.

解码器驱动是通用、硬件无关的代码,它配置解码器以支持音频捕获与回放。它不应包含任何与目标平台或机器相关的代码。平台或机器相关代码应该分别加入到平台和机器驱动中去。

Each codec driver*must*provide the following features:-

各解码器驱动必须提供如下特性:

1)Codec DAI and PCM configuration

2)Codec control IO-using I2C,3Wire(SPI)or both APIs

3)Mixers and audio controls

4)Codec audio operations

1)解码器数字音频接口和PCM配置。

2)解码器控制IO-使用I2C,3总线(SPI)或两个都有。

3)混音器和音频控制。

4)解码器音频操作。

Optionally,codec drivers can also provide:-

解码器驱动可以选择性提供:

5)DAPM description.

6)DAPM event handler.

7)DAC Digital mute control.

5)动态音频电源管理描述。

6)动态音频电源管理事件控制。

7)数模转换数字消音控制。

Its probably best to use this guide in conjunction with the existing codec driver code in sound/soc/codecs/

大家也许最好联同己存在于sound/soc/codecs/中的驱动代码一起来使用这个指导书。

ASoC Codec driver breakdown

ASoC解码器崩溃

===========================

1-Codec DAI and PCM configuration

1-解码器数字音频接口和PCM配置

-----------------------------------

Each codec driver must have a struct snd_soc_codec_dai to define its DAI and

PCM capabilities and operations.This struct is exported so that it can be registered with the core by your machine driver.

各解码器驱动必须有一个snd_soc_codec_dai数据结构,它用来定义DAI和PCM提供的功能和操作。这个数据结构要导出,好让你的机器驱动程序将它注册到ALSA核心中去。

e.g.

例如:

struct snd_soc_codec_dai wm8731_dai={

.name="WM8731",

/*playback capabilities*/

.playback={

.stream_name="Playback",

.channels_min=1,

.channels_max=2,

.rates=WM8731_RATES,

.formats=WM8731_FORMATS,},

/*capture capabilities*/

.capture={

.stream_name="Capture",

.channels_min=1,

.channels_max=2,

.rates=WM8731_RATES,

.formats=WM8731_FORMATS,},

/*pcm operations-see section4below*/

.ops={

.prepare=wm8731_pcm_prepare,

.hw_params=wm8731_hw_params,

.shutdown=wm8731_shutdown,

},

/*DAI operations-see DAI.txt*/

.dai_ops={

.digital_mute=wm8731_mute,

.set_sysclk=wm8731_set_dai_sysclk,

.set_fmt=wm8731_set_dai_fmt,

}

};

EXPORT_SYMBOL_GPL(wm8731_dai);

2-Codec control IO

2-解码器控制IO

--------------------

The codec can usually be controlled via an I2C or SPI style interface

(AC97combines control with data in the DAI).The codec drivers provide

functions to read and write the codec registers along with supplying a register cache:-

解码器通常可以通过I2C或SPI类型的接器进行控制(AC97的数字音频接口中把数据和控制结合在了一起)。解码器驱动提供读写解码器寄存器和供应寄存器缓存的功能。

/*IO control data and register cache*/

void*control_data;/*codec control(i2c/3wire)data*/

void*reg_cache;

Codec read/write should do any data formatting and call the hardware

read write below to perform the IO.These functions are called by the

core and ALSA when performing DAPM or changing the mixer:-

解码器读写要可以作用于任何格式,调用底层硬件的读写功能操作IO。ALSA核或ALSA在动态音频电源管理或改变混音器时会调用这些函数。

unsigned int(*read)(struct snd_soc_codec*,unsigned int);

int(*write)(struct snd_soc_codec*,unsigned int,unsigned int);

Codec hardware IO functions-usually points to either the I2C,SPI or AC97 read/write:-

解码器硬件IO函数-通常指向I2C,SPI或AC97的读写:

hw_write_t hw_write;

hw_read_t hw_read;

3-Mixers and audio controls

3-混音器和音频控制

-----------------------------

All the codec mixers and audio controls can be defined using the convenience macros defined in soc.h.

所有解码器混音器和音频控制都可以通过使用soc.h中定义的宏而带来方便。

#define SOC_SINGLE(xname,reg,shift,mask,invert)

Defines a single control as follows:-

这个宏可以定义一个单次操作:

xname=Control name e.g."Playback Volume"

reg=codec register

shift=control bit(s)offset in register

mask=control bit size(s) e.g.mask of7=3bits

invert=the control is inverted

Other macros include:-

其它的宏还有:

#define SOC_DOUBLE(xname,reg,shift_left,shift_right,mask,invert)

A stereo control

下面是一个立体声控制:

#define SOC_DOUBLE_R(xname,reg_left,reg_right,shift,mask,invert)

A stereo control spanning2registers

扩用两个寄存器的立体声控制如下:

#define SOC_ENUM_SINGLE(xreg,xshift,xmask,xtexts)

Defines an single enumerated control as follows:-

定义一个枚举控制如下:

xreg=register

xshift=control bit(s)offset in register

xmask=control bit(s)size

xtexts=pointer to array of strings that describe each setting

#define SOC_ENUM_DOUBLE(xreg,xshift_l,xshift_r,xmask,xtexts)

Defines a stereo enumerated control

上面的宏定义一个立体声枚举控制。

4-Codec Audio Operations

4-解码器音频操作

--------------------------

The codec driver also supports the following ALSA operations:-

解码器驱动还支持下面的ALSA操作:

/*SoC audio ops*/

struct snd_soc_ops{

int(*startup)(struct snd_pcm_substream*);

void(*shutdown)(struct snd_pcm_substream*);

int(*hw_params)(struct snd_pcm_substream*,struct snd_pcm_hw_params*);

int(*hw_free)(struct snd_pcm_substream*);

int(*prepare)(struct snd_pcm_substream*);

};

Please refer to the ALSA driver PCM documentation for details.

详情请参考ALSA驱动PCM文档:

https://www.doczj.com/doc/2614432378.html,/~iwai/writing-an-alsa-driver/c436.htm

5-DAPM description.

5-动态音频电源管理

---------------------

The Dynamic Audio Power Management description describes the codec power components and their relationships and registers to the ASoC core.

Please read dapm.txt for details of building the description.

动态音频电源管理描述的是解码器电源组件和它们的关系,和向ASoC核注册的方法。详情请阅dapm.txt。

Please also see the examples in other codec drivers.

也请参照其它解码器的例子。

6-DAPM event handler

6-动态音频电源管理事件句柄

----------------------

This function is a callback that handles codec domain PM calls and system domain PM calls(e.g.suspend and resume).It is used to put the codec

to sleep when not in use.

该功能是一个回调函数,用来处理解码器域的电源管理调用和系统域的电源管理调用(如挂起和恢复)。它用来在不用时使解码器进入休眠状态。

Power states:-

电源状态:

SNDRV_CTL_POWER_D0:/*full On*/

/*vref/mid,clk and osc on,active*/

SNDRV_CTL_POWER_D1:/*partial On*/

SNDRV_CTL_POWER_D2:/*partial On*/

SNDRV_CTL_POWER_D3hot:/*Off,with power*/

/*everything off except vref/vmid,inactive*/

SNDRV_CTL_POWER_D3cold:/*Everything Off,without power*/

7-Codec DAC digital mute control

7-解码器数模转换消音控制

----------------------------------

Most codecs have a digital mute before the DACs that can be used to minimise any system noise.The mute stops any digital data from

entering the DAC.

多数解码器都有一个数字消音装置放在数模转换器前面。它可以用来最小化系统躁声。消音器不让任何数字数据进入DAC。

A callback can be created that is called by the core for each codec DAI when the mute is applied or freed.

消音器使用或释放时会创造一个回调。ASoC核会为每个解码器数字音频接口调用这个回调函数。

i.e.

static int wm8974_mute(struct snd_soc_codec*codec,

struct snd_soc_codec_dai*dai,int mute)

{

u16mute_reg=wm8974_read_reg_cache(codec,WM8974_DAC)&0xffbf;

if(mute)

wm8974_write(codec,WM8974_DAC,mute_reg|0x40);

else

wm8974_write(codec,WM8974_DAC,mute_reg);

return0;

}

linux音频alsa-uda134x驱动分析之四(数字音频接口)

https://www.doczj.com/doc/2614432378.html,/thread-1743-1-1.html

ASoC currently supports the three main Digital Audio Interfaces(DAI)found on SoC controllers and portable audio CODECs today,namely AC97,I2S and PCM. ASoC现在支持如今的SoC控制器和便携音频解码器上的三个主要数字音频接口,即AC97,I2S,PCM。

AC97

AC97

====

AC97is a five wire interface commonly found on many PC sound cards.It is now also popular in many portable devices.This DAI has a reset line and time multiplexes its data on its SDATA_OUT(playback)and SDATA_IN(capture)lines. The bit clock(BCLK)is always driven by the CODEC(usually12.288MHz)and the

frame(FRAME)(usually48kHz)is always driven by the controller.Each AC97 frame is21uS long and is divided into13time slots.

AC97是一种个人电脑声卡上常见的五线接口。现在在很多便携设备中也很流行。这个数字音频接口有一个复位线,分时在SDATA_OUT(回放)和SDATA_IN(捕获)线上传送数据。位时钟常由解码器驱动(通常是12.288MHz).帧时钟(通常48kHz)总是由控制器驱动。每个AC97帧21uS,并分为13个时间槽。

The AC97specification can be found at:-

AC97说明书可以在下面的网址找到:

https://www.doczj.com/doc/2614432378.html,/design/chipsets/audio/ac97_r23.pdf

I2S

I2S

===

I2S is a common4wire DAI used in HiFi,STB and portable devices.The Tx and Rx lines are used for audio transmission,whilst the bit clock(BCLK)and left/right clock(LRC)synchronise the link.I2S is flexible in that either the controller or CODEC can drive(master)the BCLK and LRC clock lines.Bit clock usually varies depending on the sample rate and the master system clock (SYSCLK).LRCLK is the same as the sample rate.A few devices support separate ADC and DAC LRCLKs,this allows for simultaneous capture and playback at different sample rates.

I2S是一个4线数字音频接口,常用于HiFi,STB便携设备。Tx和Rx信号线用于音频传输。而位时钟和左右时钟(LRC)用于同步链接。I2S具有灵活性,因为控制器和解码器都可以控制位时钟和左右时钟。位时钟因采样率和主系统时钟而有不同。LRCLK与采样率相同。少数设备支持独立的ADC和DAC的LRCLK。这使在不同采样率情况下同步捕获和回放成为可能。

I2S has several different operating modes:-

I2S有几个不同的操作模式:

o I2S-MSB is transmitted on the falling edge of the first BCLK after LRC transition.

I2S模式-MSB在LRC后的第一个位时钟的下降沿传送。

o Left Justified-MSB is transmitted on transition of LRC.

左对齐模式:MSB在LRC传送时传送。

o Right Justified-MSB is transmitted sample size BCLKs before LRC

transition.

右对齐模式:MSB在(此句不懂)

PCM

PCM

===

PCM is another4wire interface,very similar to I2S,which can support a more flexible protocol.It has bit clock(BCLK)and sync(SYNC)lines that are used to synchronise the link whilst the Tx and Rx lines are used to transmit and receive the audio data.Bit clock usually varies depending on sample rate whilst sync runs at the sample rate.PCM also supports Time Division Multiplexing(TDM)in that several devices can use the bus simultaneously(this is sometimes referred to as network mode).

PCM也是一种4线制接口。与I2S非常相像,但支持一个更灵活的协议。它有位时钟(BCLK)和同步时钟(SYNC)用来在Tx和Rx在传送和接收音频数据是同步连接。位时钟通常因采样率的不同而不同,然而同步时钟(SYNC)与采样频率相同。PCM同样支持时分复用,可以几个设备同时使用总线(这有时被称为net work模式)。

Common PCM operating modes:-

常用的PCM操作模式:

o Mode A-MSB is transmitted on falling edge of first BCLK after FRAME/SYNC.模式A-MSB在FRAME/SYNC后第一个BCLK的下降沿传送。

o Mode B-MSB is transmitted on rising edge of FRAME/SYNC.

模式B-MSB在FRAME/SYNC的上升沿传送。

linux音频alsa-uda134x驱动分析之五(动态音频电源管理)

https://www.doczj.com/doc/2614432378.html,/thread-1744-1-1.html

Dynamic Audio Power Management for Portable Devices

便携设备的动态音频电源管理

===================================================

1.Description

1、概述

==============

Dynamic Audio Power Management(DAPM)is designed to allow portable

Linux devices to use the minimum amount of power within the audio subsystem at all times.It is independent of other kernel PM and as

such,can easily co-exist with the other PM systems.

动态音频电源管理(DAPM)设计用来使便携Linux设备可以在任何时最小化音频子系统的电能。它独立于其它内核电源管理,因此容易与其它电源管理系统共存。

DAPM is also completely transparent to all user space applications as

all power switching is done within the ASoC core.No code changes or recompiling are required for user space applications.DAPM makes power switching decisions based upon any audio stream(capture/playback)

activity and audio mixer settings within the device.

DAPM对用户程序也是完全透明的,因为所有的电源切换都是在ASoC核内部进行的。用户程序无须修改代码或重新编译。DAPM的切换是依据设备内部的各音频流(捕获/回放)活动和音频混音机设置决定的。

DAPM spans the whole machine.It covers power control within the entire audio subsystem,this includes internal codec power blocks and machine

level power systems.

DAPM扩展到整个机器。它包括整个音频子系统的电源控制。这包括内部解码器电源模块和机器级电源系统。

There are4power domains within DAPM

DAPM有4个电源域:

1.Codec domain-VREF,VMID(core codec and audio power)

Usually controlled at codec probe/remove and suspend/resume,although can be set at stream time if power is not needed for sidetone,etc. 1、解码器域-VREF,VMID(核解码器和音频电源)

通常在解码器检测/移除和挂起/恢复时控制,虽然在不需电源或侧音时也可以在流时间设置。

2.Platform/Machine domain-physically connected inputs and outputs

Is platform/machine and user action specific,is configured by the

machine driver and responds to asynchronous events e.g when HP

are inserted

2、平台/机器域-有物理连接的输入输出

是平台/机器相关且用户动作相关的。由机器驱动配置HP插入时响应同步事件。

3.Path domain-audio susbsystem signal paths

Automatically set when mixer and mux settings are changed by the user.

e.g.alsamixer,amixer.

3、路径域-音频子系统信号路径

混音机和复用器设置被用户改变时自动设置。如alsomixer,amixer.

4.Stream domain-DACs and ADCs.

Enabled and disabled when stream playback/capture is started and

stopped respectively. e.g.aplay,arecord.

4、数据流域-DAC和ADC

流插放/捕获开始和停止时分别使能和禁用,如aplay,arecord.

All DAPM power switching decisions are made automatically by consulting an audio routing map of the whole machine.This map is specific to each machine and consists of the interconnections between every audio component(including internal codec components).All audio components that effect power are called widgets hereafter.

所有动态音频电源管理(DAPM)电源开关自动取决于整个音频芯片的通路表。

这张通路表是具体到每台机器和每个音频之间的相互联系组成部分(包括内部解码器组件)。

2.DAPM Widgets

===============

Audio DAPM widgets fall into a number of types:-

o Mixer-Mixes several analog signals into a single analog signal.

o Mux-An analog switch that outputs only one of many inputs.

o PGA-A programmable gain amplifier or attenuation widget.

o ADC-Analog to Digital Converter

o DAC-Digital to Analog Converter

o Switch-An analog switch

o Input-A codec input pin

o Output-A codec output pin

o Headphone-Headphone(and optional Jack)

o Mic-Mic(and optional Jack)

o Line-Line Input/Output(and optional Jack)

o Speaker-Speaker

o Pre-Special PRE widget(exec before all others)

o Post-Special POST widget(exec after all others)

(Widgets are defined in include/sound/soc-dapm.h)

Widgets are usually added in the codec driver and the machine driver.There are convenience macros defined in soc-dapm.h that can be used to quickly build a list of widgets of the codecs and machines DAPM widgets.

Widget是通常添加在解码器驱动和机器的驱动程序。

有在soc-dapm.h方便的宏定义,可用于快速建立一个编解码器的动态音频电源管理部件和机器部件清单。

Most widgets have a name,register,shift and invert.Some widgets have extra parameters for stream name and kcontrols.

大部分部件有一个名称,寄存器,偏移量和取反值。有些部件有extra parameters for

stream name和kcontrols额外的参数.

2.1Stream Domain Widgets

2.1数据流域工具

-------------------------

Stream Widgets relate to the stream power domain and only consist of ADCs (analog to digital converters)and DACs(digital to analog converters).

数据流域工具涉及到流电源域,只有确定ADC(模拟到数字转换器)和DAC(数字到模拟转换器)组成。

Stream widgets have the following format:-

流部件的格式如下:-

SND_SOC_DAPM_DAC(name,stream name,reg,shift,invert),

NOTE:the stream name must match the corresponding stream name in your codec snd_soc_codec_dai.

the stream name必须符合在你的解码器snd_soc_codec_dai相应流的名称。

e.g.stream widgets for HiFi playback and capture

SND_SOC_DAPM_DAC("HiFi DAC","HiFi Playback",REG,3,1),

SND_SOC_DAPM_ADC("HiFi ADC","HiFi Capture",REG,2,1),

2.2Path Domain Widgets

2.2路径域小工具

-----------------------

Path domain widgets have a ability to control or affect the audio signal or audio paths within the audio subsystem.They have the following form:-

路径域部件有能力控制或影响的音频信号或音频子系统内的音频通道。他们有以下形式:-

SND_SOC_DAPM_PGA(name,reg,shift,invert,controls,num_controls)

Any widget kcontrols can be set using the controls and num_controls members.任何部件kcontrols可以设置使用的controls和num_controls成员。

e.g.Mixer widget(the kcontrols are declared first)

/*Output Mixer*/

static const snd_kcontrol_new_t wm8731_output_mixer_controls[]={

SOC_DAPM_SINGLE("Line Bypass Switch",WM8731_APANA,3,1,0),

SOC_DAPM_SINGLE("Mic Sidetone Switch",WM8731_APANA,5,1,0),

SOC_DAPM_SINGLE("HiFi Playback Switch",WM8731_APANA,4,1,0),

};

SND_SOC_DAPM_MIXER("Output Mixer",WM8731_PWR,4,1, wm8731_output_mixer_controls,

ARRAY_SIZE(wm8731_output_mixer_controls)),

If you dont want the mixer elements prefixed with the name of the mixer widget, you can use SND_SOC_DAPM_MIXER_NAMED_CTL instead.the parameters are the same as for SND_SOC_DAPM_MIXER.

如果你不想要的混频器,混频器的部件名称为前缀的元素,可以使用SND_SOC_DAPM_MIXER_NAMED_CTL代替。

该参数是作为SND_SOC_DAPM_MIXER相同。

2.3Platform/Machine domain Widgets

2.3平台域工具

-----------------------------------

Machine widgets are different from codec widgets in that they don't have a codec register bit associated with them.A machine widget is assigned to each machine audio component(non codec)that can be independently powered. e.g.平台域工具不同于其他codec域,它们没有一个编解码器寄存器位与他们有联系。

一台机器部件被分配到每台机器音频组件(非编解码器),可以独立供电。例如:

o Speaker Amp

o Microphone Bias

o Jack connectors

A machine widget can have an optional call back.

一台机器部件可以有一个可选的回调。

e.g.Jack connector widget for an external Mic that enables Mic Bias

when the Mic is inserted:-

例如:对一个外部麦克风,使麦克风偏置当麦克风插入插孔部件:-

static int spitz_mic_bias(struct snd_soc_dapm_widget*w,int event)

{

gpio_set_value(SPITZ_GPIO_MIC_BIAS,SND_SOC_DAPM_EVENT_ON(event));

return0;

}

SND_SOC_DAPM_MIC("Mic Jack",spitz_mic_bias),

2.4Codec Domain

2.4Codec域

----------------

The codec power domain has no widgets and is handled by the codecs DAPM event handler.This handler is called when the codec powerstate is changed wrt to any stream event or by kernel PM events.

编解码器的电源域没有部件,是由编解码器动态音频电源管理事件处理程序处理。

此处理程序被调用时,编解码器电源状态改变流相对于任何事件或内核PM事件。

2.5Virtual Widgets

2.5虚拟工具

-------------------

Sometimes widgets exist in the codec or machine audio map that don't have any corresponding soft power control.In this case it is necessary to create

a virtual widget-a widget with no control bits e.g.

有些工具在codec或平台音频表中无法被软件控制。

在这种情况下,有必要建立一个虚拟的小工具-例如,没有一个部件控制位。

SND_SOC_DAPM_MIXER("AC97Mixer",SND_SOC_DAPM_NOPM,0,0,NULL,0),

This can be used to merge to signal paths together in software.

这可以用于信号的软件合并到一起的路径。

After all the widgets have been defined,they can then be added to the DAPM subsystem individually with a call to snd_soc_dapm_new_control().

当所有的部件已经确定,他们就可以被添加到动态音频电源管理子系统单独以snd_soc_dapm_new_control()调用。

3.Codec Widget Interconnections

3.Codec工具互联

================================

Widgets are connected to each other within the codec and machine by audio paths (called interconnections).Each interconnection must be defined in order to create a map of all audio paths between widgets.

Widget是相互连接的编解码器和内(称为互连)音频通道机。

每个互连必须界定,以便建立一个部件之间的所有音频路径图。

This is easiest with a diagram of the codec(and schematic of the machine audio system),as it requires joining widgets together via their audio signal paths.

这是一个编解码器(和机器音响系统示意图)图最简单的,因为它需要通过加入他们的音频信号通道部件在一起。

e.g.,from the WM8731output mixer(wm8731.c)

The WM8731output mixer has3inputs(sources)

1.Line Bypass Input

2.DAC(HiFi playback)

3.Mic Sidetone Input

Each input in this example has a kcontrol associated with it(defined in example above)and is connected to the output mixer via it's kcontrol name.We can now connect the destination widget(wrt audio signal)with it's source widgets.这个例子中的每个输入都有与之相关联的kcontrol(在上面的例子定义),

并连接到调音台的输出通过它的kcontrol名称。

我们现在可以连接目标部件(相对于音频信号)与它的源部件。

/*output mixer*/

{"Output Mixer","Line Bypass Switch","Line Input"},

{"Output Mixer","HiFi Playback Switch","DAC"},

{"Output Mixer","Mic Sidetone Switch","Mic Bias"},

So we have:-

Destination Widget<===Path Name<===Source Widget

Or:-

Sink,Path,Source

Or:-

"Output Mixer"is connected to the"DAC"via the"HiFi Playback Switch".

When there is no path name connecting widgets(e.g.a direct connection)we pass NULL for the path name.

当没有连接部件的路径名(例如,直接连接),我们传递的路径名称为NULL。

Interconnections are created with a call to:-

互连创建一个调用:

snd_soc_dapm_connect_input(codec,sink,path,source);

Finally,snd_soc_dapm_new_widgets(codec)must be called after all widgets and interconnections have been registered with the core.This causes the core to scan the codec and machine so that the internal DAPM state matches the physical state of the machine.

最后,snd_soc_dapm_new_widgets(codec)必须被调用后,所有的部件和互连已登记的核心。

这能使得核心的codec和平台以便于使内部的动态音频电源管理(DAPM)状态匹配的机器的物理状态.

3.1Machine Widget Interconnections

3.1平台互联工具

-----------------------------------

Machine widget interconnections are created in the same way as codec ones and directly connect the codec pins to machine level widgets.

e.g.connects the speaker out codec pins to the internal speaker.

/*ext speaker connected to codec pins LOUT2,ROUT2*/

{"Ext Spk",NULL,"ROUT2"},

{"Ext Spk",NULL,"LOUT2"},

This allows the DAPM to power on and off pins that are connected(and in use) and pins that are NC respectively.

4Endpoint Widgets

===================

An endpoint is a start or end point(widget)of an audio signal within the machine and includes the codec. e.g.

o Headphone Jack

o Internal Speaker

o Internal Mic

o Mic Jack

o Codec Pins

When a codec pin is NC it can be marked as not used with a call to

snd_soc_dapm_set_endpoint(codec,"Widget Name",0);

The last argument is0for inactive and1for active.This way the pin and its input widget will never be powered up and consume power.

This also applies to machine widgets. e.g.if a headphone is connected to a

字符设备基础

Linux 字符设备基础 字符设备驱动程序在系统中的位置 操作系统内核需要访问两类主要设备,简单的字符设备,如打印机,键盘等;块设备,如软盘、硬盘等。与此对应,有两类设备驱动程序。分别称为字符设备驱动程序和块设备驱动程序。两者的主要差异是:与字符设备有关的系统调用几乎直接和驱动程序的内部功能结合在一起。而读写块设备则主要和快速缓冲存储区打交道。只有需要完成实际的输入/输出时,才用到块设备驱动程序。见下图: Linux 设备驱动程序的主要功能有: ● 对设备进行初始化; ● 使设备投入运行和退出服务; ● 从设备接收数据并将它们送到内核; ● 将数据从内核送到设备; ● 检测和处理设备出现的错误。 当引导系统时,内核调用每一个驱动程序的初始化函数。它的任务之一是将这一设备驱动程序使用的主设备号通知内核。同时,初始化函数还将驱动程序中的函数地址结构的指针送给内核。 内核中有两X 表。一X 表用于字符设备驱动程序,另一X 用于块设备驱动程序。这两X 表用来保存指向file_operations 结构的指针, 设备驱动程序内部的函数地址就保

存在这一结构中。内核用主设备号作为索引访问file_operations结构,因而能访问驱动程序内的子程序。 从开机到驱动程序的载入 系统启动过程中可能出现几种不同的方式检测设备硬件。首先机器硬件启动时BIOS会检测一部分必要的设备,如内存、显示器、键盘和硬盘等等。机器会把检测到的信息存放在特定的位置,如CMOS数据区。而另外某些设备会由设备驱动程序进行检测。 1 开机 2 引导部分(linux/config.h,arch/i386/boot/bootsect.S) 3 实模式下的系统初始化(arch/i386/boot/setup.S) 4 保护模式下的核心初始化 5 启动核心(init/main.c) init函数中函数调用关系如下: main.c init() filesystems.c sys_setup() genhd.c device_setup() mem.c chr_dev_init() 至此,驱动程序驻入内存。 设备驱动程序基本数据结构: struct device_struct 系统启动过程中要登记的块设备和字符设备管理表的定义在文件fs/devices.c中:struct device_struct { const char * name; struct file_operations * fops; }; static struct device_struct chrdevs[MAX_CHRDEV]; static struct device_struct blkdevs[MAX_BLKDEV]; 其实块设备表和字符设备表使用了相同的数据结构。在某些系统中,这些设备表也称作设备开关表,不同的是它们直接定义了一组函数指针进行对设备的管理。而这里系统用文件操作(file_operations)代替了那组开关。文件操作是文件系统与设备驱动程序之间的接口,系统特殊文件在建立的时候并没有把两者对应起来,只是把设备的缺省文件结构和i节点结构赋给设备文件,而真正的对应定义在系统启动之后,当设备被打开时时才进行的。 操作blkdev_open和chrdev_open定义在文件devices.c中,它们的基本功能是当设备文件初次打开时,根据该文件的i节点信息找到设备真正的文件操作接口,然后更新原来的设

Linux设备驱动程序举例

Linux设备驱动程序设计实例2007-03-03 23:09 Linux系统中,设备驱动程序是操作系统内核的重要组成部分,在与硬件设备之间 建立了标准的抽象接口。通过这个接口,用户可以像处理普通文件一样,对硬件设 备进行打开(open)、关闭(close)、读写(read/write)等操作。通过分析和设计设 备驱动程序,可以深入理解Linux系统和进行系统开发。本文通过一个简单的例子 来说明设备驱动程序的设计。 1、程序清单 //MyDev.c 2000年2月7日编写 #ifndef __KERNEL__ #define __KERNEL__//按内核模块编译 #endif #ifndef MODULE #define MODULE//设备驱动程序模块编译 #endif #define DEVICE_NAME "MyDev" #define OPENSPK 1 #define CLOSESPK 2 //必要的头文件 #include //同kernel.h,最基本的内核模块头文件 #include //同module.h,最基本的内核模块头文件 #include //这里包含了进行正确性检查的宏 #include //文件系统所必需的头文件 #include //这里包含了内核空间与用户空间进行数据交换时的函数宏 #include //I/O访问 int my_major=0; //主设备号 static int Device_Open=0; static char Message[]="This is from device driver"; char *Message_Ptr; int my_open(struct inode *inode, struct file *file) {//每当应用程序用open打开设备时,此函数被调用 printk ("\ndevice_open(%p,%p)\n", inode, file); if (Device_Open) return -EBUSY;//同时只能由一个应用程序打开 Device_Open++; MOD_INC_USE_COUNT;//设备打开期间禁止卸载 return 0; } static void my_release(struct inode *inode, struct file *file)

linux驱动程序的编写

linux驱动程序的编写 一、实验目的 1.掌握linux驱动程序的编写方法 2.掌握驱动程序动态模块的调试方法 3.掌握驱动程序填加到内核的方法 二、实验内容 1. 学习linux驱动程序的编写流程 2. 学习驱动程序动态模块的调试方法 3. 学习驱动程序填加到内核的流程 三、实验设备 PentiumII以上的PC机,LINUX操作系统,EL-ARM860实验箱 四、linux的驱动程序的编写 嵌入式应用对成本和实时性比较敏感,而对linux的应用主要体现在对硬件的驱动程序的编写和上层应用程序的开发上。 嵌入式linux驱动程序的基本结构和标准Linux的结构基本一致,也支持模块化模式,所以,大部分驱动程序编成模块化形式,而且,要求可以在不同的体系结构上安装。linux是可以支持模块化模式的,但由于嵌入式应用是针对具体的应用,所以,一般不采用该模式,而是把驱动程序直接编译进内核之中。但是这种模式是调试驱动模块的极佳方法。 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。同时,设备驱动程序是内核的一部分,它完成以下的功能:对设备初始化和释放;把数据从内核传送到硬件和从硬件读取数据;读取应用程序传送给设备文件的数据和回送应用程序请求的数据;检测和处理设备出现的错误。在linux操作系统下有字符设备和块设备,网络设备三类主要的设备文件类型。 字符设备和块设备的主要区别是:在对字符设备发出读写请求时,实际的硬件I/O一般就紧接着发生了;块设备利用一块系统内存作为缓冲区,当用户进程对设备请求满足用户要求时,就返回请求的数据。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。 1 字符设备驱动结构 Linux字符设备驱动的关键数据结构是cdev和file_operations结构体。

Linux驱动程序工作原理简介

Linux驱动程序工作原理简介 一、linux驱动程序的数据结构 (1) 二、设备节点如何产生? (2) 三、应用程序是如何访问设备驱动程序的? (2) 四、为什么要有设备文件系统? (3) 五、设备文件系统如何实现? (4) 六、如何使用设备文件系统? (4) 七、具体设备驱动程序分析 (5) 1、驱动程序初始化时,要注册设备节点,创建子设备文件 (5) 2、驱动程序卸载时要注销设备节点,删除设备文件 (7) 参考书目 (8) 一、linux驱动程序的数据结构 设备驱动程序实质上是提供一组供应用程序操作设备的接口函数。 各种设备由于功能不同,驱动程序提供的函数接口也不相同,但linux为了能够统一管理,规定了linux下设备驱动程序必须使用统一的接口函数file_operations 。 所以,一种设备的驱动程序主要内容就是提供这样的一组file_operations 接口函数。 那么,linux是如何管理种类繁多的设备驱动程序呢? linux下设备大体分为块设备和字符设备两类。 内核中用2个全局数组存放这2类驱动程序。 #define MAX_CHRDEV 255 #define MAX_BLKDEV 255 struct device_struct { const char * name; struct file_operations * fops; }; static struct device_struct chrdevs[MAX_CHRDEV]; static struct { const char *name; struct block_device_operations *bdops; } blkdevs[MAX_BLKDEV]; //此处说明一下,struct block_device_operations是块设备驱动程序内部的接口函数,上层文件系统还是通过struct file_operations访问的。

一个简单的演示用的Linux字符设备驱动程序.

实现如下的功能: --字符设备驱动程序的结构及驱动程序需要实现的系统调用 --可以使用cat命令或者自编的readtest命令读出"设备"里的内容 --以8139网卡为例,演示了I/O端口和I/O内存的使用 本文中的大部分内容在Linux Device Driver这本书中都可以找到, 这本书是Linux驱动开发者的唯一圣经。 ================================================== ===== 先来看看整个驱动程序的入口,是char8139_init(这个函数 如果不指定MODULE_LICENSE("GPL", 在模块插入内核的 时候会出错,因为将非"GPL"的模块插入内核就沾污了内核的 "GPL"属性。 module_init(char8139_init; module_exit(char8139_exit; MODULE_LICENSE("GPL"; MODULE_AUTHOR("ypixunil"; MODULE_DESCRIPTION("Wierd char device driver for Realtek 8139 NIC"; 接着往下看char8139_init( static int __init char8139_init(void {

int result; PDBG("hello. init.\n"; /* register our char device */ result=register_chrdev(char8139_major, "char8139", &char8139_fops; if(result<0 { PDBG("Cannot allocate major device number!\n"; return result; } /* register_chrdev( will assign a major device number and return if it called * with "major" parameter set to 0 */ if(char8139_major == 0 char8139_major=result; /* allocate some kernel memory we need */ buffer=(unsigned char*(kmalloc(CHAR8139_BUFFER_SIZE, GFP_KERNEL; if(!buffer { PDBG("Cannot allocate memory!\n"; result= -ENOMEM;

字符设备驱动程序

Linux字符设备驱动(转载) 来源: ChinaUnix博客日期:2008.01.01 18:52(共有0条评论) 我要评论 Linux字符设备驱动(转载) 这篇文章描述了在Linux 2.4下,如何建立一个虚拟的设备,对初学者来说很有帮助。原文地址:https://www.doczj.com/doc/2614432378.html,/186/2623186.shtml Linux下的设备驱动程序被组织为一组完成不同任务的函数的集合,通过这些函数使得Windows的设备操作犹如文件一般。在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作,如open ()、close ()、read ()、write () 等。 Linux主要将设备分为二类:字符设备和块设备。字符设备是指设备发送和接收数据以字符的形式进行;而块设备则以整个数据缓冲区的形式进行。字符设备的驱动相对比较简单。 下面我们来假设一个非常简单的虚拟字符设备:这个设备中只有一个4个字节的全局变量int global_var,而这个设备的名字叫做"gobalvar"。对"gobalvar"设备的读写等操作即是对其中全局变量global_var的操作。 驱动程序是内核的一部分,因此我们需要给其添加模块初始化函数,该函数用来完成对所控设备的初始化工作,并调用register_chrdev() 函数注册字符设备: static int __init gobalvar_init(void) { if (register_chrdev(MAJOR_NUM, " gobalvar ", &gobalvar_fops)) { //…注册失败 } else

LINUX字符设备驱动编写基本流程

---简介 Linux下的MISC简单字符设备驱动虽然使用简单,但却不灵活。 只能建立主设备号为10的设备文件。字符设备比较容易理解,同时也能够满足大多数简 单的硬件设备,字符设备通过文件系统中的名字来读取。这些名字就是文件系统中的特 殊文件或者称为设备文件、文件系统的简单结点,一般位于/dev/目录下使用ls进行查 看会显示以C开头证明这是字符设备文件crw--w---- 1 root tty 4, 0 4月 14 11:05 tty0。 第一个数字是主设备号,第二个数字是次设备号。 ---分配和释放设备编号 1)在建立字符设备驱动时首先要获取设备号,为此目的的必要的函数是 register_chrdev_region,在linux/fs.h中声明:int register_chrdev_region(dev_t first, unsigned int count, char *name);first是你想 要分配的起始设备编号,first的次编号通常是0,count是你请求的连续设备编号的 总数。count如果太大会溢出到下一个主设备号中。name是设备的名字,他会出现在 /proc/devices 和sysfs中。操作成功返回0,如果失败会返回一个负的错误码。 2)如果明确知道设备号可用那么上一个方法可行,否则我们可以使用内核动态分配的设 备号int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name);dev是个只输出的参数,firstminor请求的第一个要用的次编号, count和name的作用如上1)对于新驱动,最好的方法是进行动态分配 3)释放设备号,void unregister_chrdev_region(dev_t first unsigned int count); ---文件操作file_operations结构体,内部连接了多个设备具体操作函数。该变量内部 的函数指针指向驱动程序中的具体操作,没有对应动作的指针设置为NULL。 1)fops的第一个成员是struct module *owner 通常都是设置成THIS_MODULE。 linux/module.h中定义的宏。用来在他的操作还在被使用时阻止模块被卸载。 2)loff_t (*llseek) (struct file *, loff_t, int);该方法用以改变文件中的当前读/ 写位置 返回新位置。 3)ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);该函数用 以从设备文件 中读取数据,读取成功返回读取的字节数。

linux字符设备驱动课程设计报告

一、课程设计目的 Linux 系统的开源性使其在嵌入式系统的开发中得到了越来越广泛的应用,但其本身并没有对种类繁多的硬件设备都提供现成的驱动程序,特别是由于工程应用中的灵活性,其驱动程序更是难以统一,这时就需开发一套适合于自己产品的设备驱动。对用户而言,设备驱动程序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说是把设备映射为一个特殊的设备文件,用户程序可以像对其它文件一样对此设备文件进行操作。 通过这次课程设计可以了解linux的模块机制,懂得如何加载模块和卸载模块,进一步熟悉模块的相关操作。加深对驱动程序定义和设计的了解,了解linux驱动的编写过程,提高自己的动手能力。 二、课程设计内容与要求 字符设备驱动程序 1、设计目的:掌握设备驱动程序的编写、编译和装载、卸载方法,了解设备文件的创建,并知道如何编写测试程序测试自己的驱动程序是否能够正常工作 2、设计要求: 1) 编写一个简单的字符设备驱动程序,该字符设备包括打开、读、写、I\O控制与释放五个基本操作。 2) 编写一个测试程序,测试字符设备驱动程序的正确性。 3) 要求在实验报告中列出Linux内核的版本与内核模块加载过程。 三、系统分析与设计 1、系统分析 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它完成以下的功能: 1、对设备初始化和释放; 2、把数据从内核传送到硬件和从硬件读取数据; 3、读取应用程序传送给设备文件的数据和回送应用程序请求的数据; 4、检测和处理设备出现的错误。 字符设备提供给应用程序的是一个流控制接口,主要包括op e n、clo s e(或r ele as e)、r e ad、w r i t e、i o c t l、p o l l和m m a p等。在系统中添加一个字符设备驱动程序,实际上就是给上述操作添加对应的代码。对于字符设备和块设备,L i n u x内核对这些操作进行了统一的抽象,把它们定义在结构体fi le_operations中。 2、系统设计: 、模块设计:

一个简单字符设备驱动实例

如何编写Linux设备驱动程序 Linux是Unix操作系统的一种变种,在Linux下编写驱动程序的原理和思想完全类似于其他的Unix系统,但它dos或window环境下的驱动程序有很大的区别。在Linux环境下设计驱动程序,思想简洁,操作方便,功能也很强大,但是支持函数少,只能依赖kernel中的函数,有些常用的操作要自己来编写,而且调试也不方便。本文是在编写一块多媒体卡编制的驱动程序后的总结,获得了一些经验,愿与Linux fans共享,有不当之处,请予指正。 以下的一些文字主要来源于khg,johnsonm的Write linux device driver,Brennan's Guide to Inline Assembly,The Linux A-Z,还有清华BBS上的有关device driver的一些资料. 这些资料有的已经过时,有的还有一些错误,我依据自己的试验结果进行了修正. 一、Linux device driver 的概念 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它完成以下的功能: 1)对设备初始化和释放; 2)把数据从内核传送到硬件和从硬件读取数据; 3)读取应用程序传送给设备文件的数据和回送应用程序请求的数据; 4)检测和处理设备出现的错误。 在Linux操作系统下有两类主要的设备文件类型,一种是字符设备,另一种是块设备。字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待. 已经提到,用户进程是通过设备文件来与实际的硬件打交道。每个设备文件都都有其文件属性(c/b),表示是字符设备还是块设备。另外每个文件都有两个设备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分他们。设备文件的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问到驱动程序. 最后必须提到的是,在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度。也就是说,系统必须在你的驱动程序的子函数返回后才能进行其他的工作。如果你的驱动程序陷入死循环,不幸的是你只有重新启动机器了,然后就是漫长的fsck。 二、实例剖析 我们来写一个最简单的字符设备驱动程序。虽然它什么也不做,但是通过它可以了解Linux的设备驱动程序的工作原理.把下面的C代码输入机器,你就会获得一个真正的设备

linux 驱动程序开发

1 什么是驱动 a)裸板驱动 b)有系统驱动linux 将驱动封装了一套框架(每个驱动) c)大量和硬件无关的代码已写好只需要编程实现和硬件相关的代码 d)难点:框架的理解代码的理解 e)需要三方面的知识: i.硬件相关的知识 1.电路原理图 2.芯片的数据手册 3.总线协议rs232 i2c等 ii.内核的知识 1.内核驱动属于内核的一部分,它运行在内核态需要对内核知识有了解 2.内存管理 3.解决竞争状态(如上锁) 4.。。。 iii.驱动框架的知识 1.内核中已经实现了大量硬件驱动完成了驱动的框架编程只需要根据硬 件进行添加 2 搭建linux驱动开发工具 a)安装交叉编译环境 i.arm-linux-gcc uboot PATH b)移植uboot c)移植内核 d)制作根文件系统然后通过nfs方式让开发板可以加载 3 内核驱动开发的基本知识 a)如何学驱动编程? i.最好的老师就是内核源码(没有man 功能) 1.要是用某个函数就去查看某个函数的定义注释 2.查看内核中其他模块儿时如何使用该函数的 3.专业书籍: a)内核开发:linux内核的设计与实现机械工程出版社 b)驱动开发:圣经级别的-LDD3:LINUX DEVICE c)操作性别叫强的:精通linux设备驱动程序开发

关于linux内核: 1)linux内核中所使用的函数都是自身实现的它肯定不会调用c库中的函数 2)linux中代码绝大多数代码时gun c语言完成的不是标准c语言可以理解为标c的扩展版和少部分汇编 需要注意的问题: 1)内核态不能做浮点数运算 2)用户空间的每个进程都有独立的0-3G的虚拟空间 多个进程共享同一个内核 内核使用的地址空间为3G-4G 3)每个线程有独立的栈空间 4 写一个最简单的内核模块儿(因为驱动时内核的一个模块套路都一样) a)几个宏 i.__FUNCTION__:展开为所在函数的名称 ii.__LINE__:展开为printk所在的行号 iii.__DATE__:展开为编译程序的日期 b)通用头文件 i.#include ii.#include c)没有main函数 然后写一个makefile 其中:obj -m +=helloworld.o -m表示生成模块儿 make -C 内核路径编译对象路径modules(固定表示模块儿) 例子:make -C /home/changjian/dirver/kernel M=$(PWD) modules 报错:如taints kernel(污染内核)因为写的驱动没有声明license 因为linux为开源所以写的驱动也必须声明为开源可以在程序里加入:MODULE_LICENSE(“GPL”);声明为开源 模块儿驱动开发 1、模块儿参数 a)内核中安装模块时也可以传递参数 i.insmod xx.ko var=123 b)模块参数的使用方法 i.首先在模块中定义全局变量 ii.然后使用module_param 或者module_param_array来修饰该变量 这样一个普通的全局变量就变成可以安装模块时传递参数的模块参数 module_param(name,type,perm) name:变量名称 type: name的类型(不包括数组) perm:权限类型rwxr-x 等类型内核做了相关的宏定义形如efine S_IRWXG 表示r w x g(同组) module_param_array(name,type,nump,perm)将某个数组声明为模块 参数

字符设备驱动步骤

编写字符设备驱动框架的步骤 Step 1: 申请设备号(主要是申请主设备号) 有两种方式: ⑴静态申请 通过下面这个函数实现: int register_chrdev_region(dev_t from, unsigned count, const char *name); /* register_chrdev_region() - register a range of device numbers * @from: the first in the desired range of device numbers; must include * the major number. * @count: the number of consecutive device numbers required * @name: the name of the device or driver. * * Return value is zero on success, a negative error code on failure.*/ 这种方式主要用于,驱动开发者事先知道该驱动主设备号的情况。 ⑵动态申请 通过下面这个函数实现: int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name) /* alloc_chrdev_region() - register a range of char device numbers * @dev: output parameter for first assigned number * @baseminor: first of the requested range of minor numbers * @count: the number of minor numbers required * @name: the name of the associated device or driver * * Allocates a range of char device numbers. The major number will be * chosen dynamically, and returned (along with the first minor number) * in @dev. Returns zero or a negative error code.*/ 这种方式由系统动态分配一个设备号,返回的设备号保存在参数dev中。 Step 2 :注册字符设备 在linux 内核中用struct cdev表示一个字符设备。 字符设备的注册与注销分别通过下面的两个函数来实现: int cdev_add(struct cdev *p, dev_t dev, unsigned count); /** * cdev_add() - add a char device to the system * @p: the cdev structure for the device * @dev: the first device number for which this device is responsible * @count: the number of consecutive minor numbers corresponding to this * device * * cdev_add() adds the device represented by @p to the system, making it * live immediately. A negative error code is returned on failure.

linux简单的gpio驱动实例

今天完成了嵌入式linux的第一个驱动的编写和测试,虽然是个简单的程序,但是麻雀虽小,五脏俱全,希望可以给刚开始接触驱动编写的人一些提示,共同进步。 源代码: 分析如下: 下面是我的驱动程序: #include //配置头文件 #include /*内核头文件,作为系统核心的一部分,设备驱动程序在申请和释放内存时,不是调用malloc和free,而是调用kmalloc和 kfree*/ #include //调度,进程睡眠,唤醒,中断申请,中断释放 #include //时钟头文件 #include //用户定义模块初始函数名需引用的头文件 #include //模块加载的头文件 #include #include //这个是2440的寄存器头文件,asm/srch只是个链接 //实际根据自己的情况查找,一般 是../../linux2.*.*/include/asm/arch-s3c2440里编译器 //自己会查询链接,以前不知道,找了半天 // GPIO_LED DEVICE MAJOR #define GPIO_LED_MAJOR 97 //定义主设备号 //define LED STATUS 我的板子 LED在GPB0 与GPB1 处大家根据自己情况改 #define LED_ON 0 //定义LED灯的状态开 #define LED_OFF 1 // // ------------------- READ ------------------------ 这个前面要加static 否则警告 static ssize_t GPIO_LED_read (struct file * file ,char * buf, size_t count, loff_t * f_ops) {

Linux设备驱动程序说明介绍

Linux设备驱动程序简介 Linux是Unix操作系统的一种变种,在Linux下编写驱动程序的原理和思想完全类似于其他的Unix系统,但它dos或window环境下的驱动程序有很大的区别。在Linux环境下设计驱动程序,思想简洁,操作方便,功能也很强大,但是支持函数少,只能依赖kernel 中的函数,有些常用的操作要自己来编写,而且调试也不方便。本人这几周来为实验室自行研制的一块多媒体卡编制了驱动程序,获得了一些经验,愿与Linux fans共享,有不当之处,请予指正。 以下的一些文字主要来源于khg,johnsonm的Write linux device driver,Brennan's Guide to Inline Assembly,The Linux A-Z,还有清华BBS上的有关device driver的一些资料. 这些资料有的已经过时,有的还有一些错误,我依据自己的试验结果进行了修正. 一、Linux device driver 的概念 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口.设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作.设备驱动程序是内核的一部分,它完成以下的功能: 1.对设备初始化和释放. 2.把数据从内核传送到硬件和从硬件读取数据. 3.读取应用程序传送给设备文件的数据和回送应用程序请求的数据. 4.检测和处理设备出现的错误. 在Linux操作系统下有两类主要的设备文件类型,一种是字符设备,另一种是块设备.字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作.块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待. 已经提到,用户进程是通过设备文件来与实际的硬件打交道.每个设备文件都都有其文件属性(c/b),表示是字符设备还蔤强樯璞?另外每个文件都有两个设备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分他们.设备文件的的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问到驱动程序. 最后必须提到的是,在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度.也就是说,系统必须在你的驱动程序的子函数返回后才能进行其他的工作.如果你的驱动程序陷入死循环,不幸的是你只有重新启动机器了,然后就是漫长的fsck. 读/写时,它首先察看缓冲区的内容,如果缓冲区的数据 如何编写Linux操作系统下的设备驱动程序 二、实例剖析 我们来写一个最简单的字符设备驱动程序。虽然它什么也不做,但是通过它可以了解Linux的设备驱动程序的工作原理.把下面的C代码输入机器,你就会获得一个真正的设备驱动程序.不过我的kernel是2.0.34,在低版本的kernel上可能会出现问题,我还没测试过. [code]#define __NO_VERSION__

Linux设备驱动程序学习(18)-USB 驱动程序(三)

Linux设备驱动程序学习(18)-USB 驱动程序(三) (2009-07-14 11:45) 分类:Linux设备驱动程序 USB urb (USB request block) 内核使用2.6.29.4 USB 设备驱动代码通过urb和所有的 USB 设备通讯。urb用 struct urb 结构描述(include/linux/usb.h )。 urb以一种异步的方式同一个特定USB设备的特定端点发送或接受数据。一个USB 设备驱动可根据驱动的需要,分配多个 urb 给一个端点或重用单个 urb 给多个不同的端点。设备中的每个端点都处理一个 urb 队列, 所以多个 urb 可在队列清空之前被发送到相同的端点。 一个 urb 的典型生命循环如下: (1)被创建; (2)被分配给一个特定 USB 设备的特定端点; (3)被提交给 USB 核心; (4)被 USB 核心提交给特定设备的特定 USB 主机控制器驱动; (5)被 USB 主机控制器驱动处理, 并传送到设备; (6)以上操作完成后,USB主机控制器驱动通知 USB 设备驱动。 urb 也可被提交它的驱动在任何时间取消;如果设备被移除,urb 可以被USB 核心取消。urb 被动态创建并包含一个内部引用计数,使它们可以在最后一个用户释放它们时被自动释放。 struct urb

struct list_head urb_list;/* list head for use by the urb's * current owner */ struct list_head anchor_list;/* the URB may be anchored */ struct usb_anchor *anchor; struct usb_device *dev;/* 指向这个 urb 要发送的目标 struct usb_device 的指针,这个变量必须在这个 urb 被发送到 USB 核心之前被USB 驱动初始化.*/ struct usb_host_endpoint *ep;/* (internal) pointer to endpoint */ unsigned int pipe;/* 这个 urb 所要发送到的特定struct usb_device 的端点消息,这个变量必须在这个 urb 被发送到 USB 核心之前被 USB 驱动初始化.必须由下面的函数生成*/ int status;/*当 urb开始由 USB 核心处理或处理结束, 这个变量被设置为 urb 的当前状态. USB 驱动可安全访问这个变量的唯一时间是在 urb 结束处理例程函数中. 这个限制是为防止竞态. 对于等时 urb, 在这个变量中成功值(0)只表示这个 urb 是否已被去链. 为获得等时 urb 的详细状态, 应当检查 iso_frame_desc 变量. */ unsigned int transfer_flags;/* 传输设置*/ void*transfer_buffer;/* 指向用于发送数据到设备(OUT urb)或者从设备接收数据(IN urb)的缓冲区指针。为了主机控制器驱动正确访问这个缓冲, 它必须使用 kmalloc 调用来创建, 不是在堆栈或者静态内存中。对控制端点, 这个缓冲区用于数据中转*/ dma_addr_t transfer_dma;/* 用于以 DMA 方式传送数据到 USB 设备的缓冲区*/ int transfer_buffer_length;/* transfer_buffer 或者 transfer_dma 变量指向的缓冲区大小。如果这是 0, 传送缓冲没有被 USB 核心所使用。对于一个 OUT 端点, 如果这个端点大小比这个变量指定的值小, 对这个USB 设备的传输将被分成更小的块,以正确地传送数据。这种大的传送以连续的 USB 帧进行。在一个 urb 中提交一个大块数据, 并且使 USB 主机控制器去划分为更小的块, 比以连续地顺序发送小缓冲的速度快得多*/

Linux驱动框架及驱动加载

本讲主要概述Linux设备驱动框架、驱动程序的配置文件及常用的加载驱动程序的方法;并且介绍Red Hat Linux安装程序是如何加载驱动的,通过了解这个过程,我们可以自己将驱动程序放到引导盘中;安装完系统后,使用kudzu自动配置硬件程序。 Linux设备驱动概述 1. 内核和驱动模块 操作系统是通过各种驱动程序来驾驭硬件设备,它为用户屏蔽了各种各样的设备,驱动硬件是操作系统最基本的功能,并且提供统一的操作方式。正如我们查看屏幕上的文档时,不用去管到底使用nVIDIA芯片,还是ATI芯片的显示卡,只需知道输入命令后,需要的文字就显示在屏幕上。硬件驱动程序是操作系统最基本的组成部分,在Linux内核源程序中也占有较高的比例。 Linux内核中采用可加载的模块化设计(LKMs ,Loadable Kernel Modules),一般情况下编译的Linux内核是支持可插入式模块的,也就是将最基本的核心代码编译在内核中,其它的代码可以选择是在内核中,或者编译为内核的模块文件。 如果需要某种功能,比如需要访问一个NTFS分区,就加载相应的NTFS模块。这种设计可以使内核文件不至于太大,但是又可以支持很多的功能,必要时动态地加载。这是一种跟微内核设计不太一样,但却是切实可行的内核设计方案。 我们常见的驱动程序就是作为内核模块动态加载的,比如声卡驱动和网卡驱动等,而Linux最基础的驱动,如CPU、PCI总线、TCP/IP协议、APM(高级电源管理)、VFS等驱动程序则编译在内核文件中。有时也把内核模块就叫做驱动程序,只不过驱动的内容不一定是硬件罢了,比如ext3文件系统的驱动。 理解这一点很重要。因此,加载驱动时就是加载内核模块。下面来看一下有关模块的命令,在加载驱动程序要用到它们:lsmod、modprob、insmod、rmmod、modinfo。 lsmod

linux简单gpio驱动实例

Led test 今天完成了嵌入式linux的第一个驱动的编写和测试,虽然是个简单的程序, 但是麻雀虽小,五脏俱全,希望可以给刚开始接触驱动编写的人一些提示,共 同进步。 源代码: 分析如下: 下面是我的驱动程序: #include //配置头文件 #include /*内核头文件,作为系统核心的一部分,设备驱动程序在申请和释放内存时,不是调用malloc和free,而是调用kmalloc和 kfree*/ #include //调度,进程睡眠,唤醒,中断申请,中断释放 #include //时钟头文件 #include //用户定义模块初始函数名需引用的头文件 #include //模块加载的头文件 #include #include //这个是2440的寄存器头文件,asm/srch只是个链接 //实际根据自己的情况查找,一般 是../../linux2.*.*/include/asm/arch-s3c2440里编译器 //自己会查询链接,以前不知道,找了半天 // GPIO_LED DEVICE MAJOR #define GPIO_LED_MAJOR 97 //定义主设备号 //define LED STATUS 我的板子 LED在GPB0 与GPB1 处大家根据自己情况改 #define LED_ON 0 //定义LED灯的状态开 #define LED_OFF 1 // // ------------------- READ ------------------------ 这个前面要加static 否则警告 static ssize_t GPIO_LED_read (struct file * file ,char * buf, size_t count, loff_t * f_ops) {

相关主题
文本预览
相关文档 最新文档