X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=Documentation%2Fsound%2Falsa%2FDocBook%2Fwriting-an-alsa-driver.tmpl;h=557786cc04765428ece43e18d9edc6486f0ddecb;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=fae0c98cfdca28e411a8190aaa9eabceda31aefd;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index fae0c98cf..557786cc0 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -18,8 +18,8 @@
- Mar. 6, 2004
- 0.3.1
+ July 11, 2004
+ 0.3.3
@@ -395,7 +395,6 @@
#include
#include
#include
- #define SNDRV_GET_ID
#include
// module parameters (see "Module Parameters")
@@ -411,10 +410,6 @@
// "PCI Resource Managements"
};
- // this should be go into
- // (see "Management of Cards and Components")
- #define mychip_t_magic 0xa15a4501
-
// chip-specific destructor
// (see "PCI Resource Managements")
static int snd_mychip_free(mychip_t *chip)
@@ -426,8 +421,7 @@
// (see "Management of Cards and Components")
static int snd_mychip_dev_free(snd_device_t *device)
{
- mychip_t *chip = snd_magic_cast(mychip_t,
- device->device_data, return -ENXIO);
+ mychip_t *chip = device->device_data;
return snd_mychip_free(chip);
}
@@ -448,8 +442,8 @@
// check PCI availability here
// (see "PCI Resource Managements")
- // allocate a chip-specific data with magic-alloc
- chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL);
+ // allocate a chip-specific data with zero filled
+ chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
@@ -744,7 +738,6 @@
#include
#include
#include
- #define SNDRV_GET_ID
#include
]]>
@@ -905,13 +898,6 @@
-
- You might have objections against such a typedef, but this
- typedef is necessary if you use a magic-cast
- (explained later).
-
-
In general, there are two ways to allocate the chip record.
@@ -943,9 +929,8 @@
- With this method, you don't have to allocate twice. But you
- cannot use magic-cast for this record pointer,
- instead.
+ With this method, you don't have to allocate twice.
+ The record is released together with the card instance.
@@ -956,7 +941,7 @@
After allocating a card instance via
snd_card_new() (with
NULL on the 4th arg), call
- snd_magic_kcalloc().
+ kcalloc().
@@ -965,13 +950,10 @@
mychip_t *chip;
card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL);
.....
- chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL);
+ chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
]]>
-
- Once when the record is allocated via snd_magic stuff, you
- can use magic-cast for the void pointer.
@@ -1002,21 +984,6 @@
-
- Also, you need to define a magic-value for mychip_t.
-
-
-
-
-
-
- (the detail will be described in the
-
- next subsection).
-
-
Next, initialize the fields, and register this chip
record as a low-level device with a specified
@@ -1045,8 +1012,7 @@
device_data,
- return -ENXIO);
+ mychip_t *chip = device->device_data;
return snd_mychip_free(chip);
}
]]>
@@ -1056,126 +1022,6 @@
where snd_mychip_free() is the real destructor.
-
-
- Not a magic but a logic
-
- Now, you might have a question: What is the advantage of the
- second method? Obviously, it looks far more complicated.
-
- As I wrote many times, the second method allows a
- magic-cast for mychip_t. If you
- have a void pointer (such as
- pcm->private_data), the pointer type
- is unknown at the compile time, and you cannot know even if a
- wrong pointer type is passed. The compiler would accept
- it. The magic-cast checks the pointer type at the runtime (and
- whether it's a null pointer, too). Hence, the cast will be
- much safer and good for debugging.
-
-
-
- As you have already seen, allocation with a magic-header can
- be done via snd_magic_kmalloc() or
- snd_magic_kcalloc().
-
-
-
-
-
-
-
- The difference of these two functions is whether the area is
- zero-cleared (kcalloc) or not
- (kmalloc).
-
-
-
- The first argument of the allocator is the type of the
- record. The magic-constant has to be defined for this type
- beforehand. In this case, we'll need to define
- mychip_t_magic, for example, as already
- seen,
-
-
-
-
-
-
-
- The value is arbitrary but should be unique.
- This is usually defined in
- <include/sndmagic.h> or
- <include/amagic.h> for alsa-driver tree,
- but you may define it locally in the code at the early
- development stage, since changing
- sndmagic.h will lead to the recompilation
- of the whole driver codes.
-
-
-
- The second argument is the extra-data length. It is usually
- zero. The third argument is the flags to be passed to kernel
- memory allocator, GFP_XXX. Normally,
- GFP_KERNEL is passed.
-
-
-
- For casting a pointer, use
- snd_magic_cast() macro:
-
-
-
-
-
-
-
- where source_pointer is the pointer to
- be casted (e.g. pcm->private_data), and
- action is the action to do if the cast
- fails (e.g. return -EINVAL).
-
-
-
- For releasing the magic-allocated data, you need to call
- snd_magic_kfree() function instead of
- kfree().
-
-
-
-
-
-
-
-
-
- If you call kfree() for the
- magic-allocated value, it will lead to memory leaks.
- When the ALSA drivers are compiled with
- CONFIG_SND_DEBUG_MEMORY kernel config (or
- configured with ), the
- non-matching free will be checked and you'll see warning
- messages.
-
-
-
- If you are 100% sure that your code is bug-free, you can
- compile the driver without
- CONFIG_SND_DEBUG_MEMORY kernel config,
- so that the magic-allocator and the magic-cast will be
- replaced to the normal kmalloc and cast.
-
-
@@ -1238,8 +1084,6 @@
struct pci_dev *pci;
unsigned long port;
- struct resource *res_port;
-
int irq;
};
@@ -1248,16 +1092,13 @@
// disable hardware here if any
// (not implemented in this document)
- // release the i/o port
- if (chip->res_port) {
- release_resource(chip->res_port);
- kfree_nocheck(chip->res_port);
- }
// release the irq
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
+ // release the i/o ports
+ pci_release_regions(chip->pci);
// release the data
- snd_magic_kfree(chip);
+ kfree(chip);
return 0;
}
@@ -1283,7 +1124,7 @@
return -ENXIO;
}
- chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL);
+ chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
@@ -1293,18 +1134,16 @@
chip->irq = -1;
// (1) PCI resource allocation
- chip->port = pci_resource_start(pci, 0);
- if ((chip->res_port = request_region(chip->port, 8,
- "My Chip")) == NULL) {
- snd_mychip_free(chip);
- printk(KERN_ERR "cannot allocate the port\n");
- return -EBUSY;
+ if ((err = pci_request_regions(pci, "My Chip")) < 0) {
+ kfree(chip);
+ return err;
}
+ chip->port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_mychip_interrupt,
SA_INTERRUPT|SA_SHIRQ, "My Chip",
(void *)chip)) {
+ printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
snd_mychip_free(chip);
- printk(KERN_ERR "cannot grab irq\n");
return -EBUSY;
}
chip->irq = pci->irq;
@@ -1420,8 +1259,6 @@
snd_card_t *card;
unsigned long port;
- struct resource *res_port;
-
int irq;
};
]]>
@@ -1436,7 +1273,7 @@
need to initialize this number as -1 before actual allocation,
since irq 0 is valid. The port address and its resource pointer
can be initialized as null by
- snd_magic_kcalloc() automatically, so you
+ kcalloc() automatically, so you
don't have to take care of resetting them.
@@ -1446,14 +1283,11 @@
port = pci_resource_start(pci, 0);
- if ((chip->res_port = request_region(chip->port, 8,
- "My Chip")) == NULL) {
- printk(KERN_ERR "cannot allocate the port 0x%lx\n",
- chip->port);
- snd_mychip_free(chip);
- return -EBUSY;
+ if ((err = pci_request_regions(pci, "My Chip")) < 0) {
+ kfree(chip);
+ return err;
}
+ chip->port = pci_resource_start(pci, 0);
]]>
@@ -1477,8 +1311,8 @@
if (request_irq(pci->irq, snd_mychip_interrupt,
SA_INTERRUPT|SA_SHIRQ, "My Chip",
(void *)chip)) {
- snd_mychip_free(chip);
printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
+ snd_mychip_free(chip);
return -EBUSY;
}
chip->irq = pci->irq;
@@ -1517,16 +1351,13 @@
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
- mychip_t *chip = snd_magic_cast(mychip_t, dev_id, return);
+ mychip_t *chip = dev_id;
....
return IRQ_HANDLED;
}
]]>
-
- Again the magic-cast is used here to get the correct pointer
- from the second argument.
@@ -1538,7 +1369,45 @@
For releasing the resources, check-and-release
- method is a safer way. For the i/o port, do like this:
+ method is a safer way. For the interrupt, do like this:
+
+
+
+irq >= 0)
+ free_irq(chip->irq, (void *)chip);
+]]>
+
+
+
+ Since the irq number can start from 0, you should initialize
+ chip->irq with a negative value (e.g. -1), so that you can
+ check the validity of the irq number as above.
+
+
+
+ When you requested I/O ports or memory regions via
+ pci_request_region() or
+ pci_request_regions() like this example,
+ release the resource(s) using the corresponding function,
+ pci_release_region() or
+ pci_release_regions().
+
+
+
+pci);
+]]>
+
+
+
+
+
+ When you requested manually via request_region()
+ or request_mem_region, you can release it via
+ release_resource(). Suppose that you keep
+ the resource pointer returned from request_region()
+ in chip->res_port, the release procedure looks like below:
@@ -1550,10 +1419,8 @@
]]>
-
-
- As you can see, the i/o resource pointer is also to be freed
+ As you can see, the resource pointer is also to be freed
via kfree_nocheck() after
release_resource() is called. You
cannot use kfree() here, because on ALSA,
@@ -1567,35 +1434,19 @@
- For releasing the interrupt, do like this:
-
-
-
-irq >= 0)
- free_irq(chip->irq, (void *)chip);
-]]>
-
-
-
And finally, release the chip-specific record.
- The chip instance is freed via
- snd_magic_kfree(). Please use this function
- for the object allocated by
- snd_magic_kmalloc(). If you free it with
- kfree(), it won't work properly and will
- result in the memory leak. Also, again, remember that you cannot
+ Again, remember that you cannot
set __devexit prefix for this destructor.
@@ -1629,7 +1480,6 @@
....
unsigned long iobase_phys;
unsigned long iobase_virt;
- struct resource *res_iobase;
};
]]>
@@ -1640,15 +1490,14 @@
iobase_phys = pci_resource_start(pci, 0);
chip->iobase_virt = (unsigned long)
- ioremap_nocache(chip->iobase_phys, 512);
- if ((chip->res_port = request_mem_region(chip->iobase_phys, 512,
- "My Chip")) == NULL) {
- printk(KERN_ERR "cannot allocate the memory region\n");
- snd_mychip_free(chip);
- return -EBUSY;
- }
+ ioremap_nocache(chip->iobase_phys,
+ pci_resource_len(pci, 0));
]]>
@@ -1663,10 +1512,8 @@
....
if (chip->iobase_virt)
iounmap((void *)chip->iobase_virt);
- if (chip->res_iobase) {
- release_resource(chip->res_iobase);
- kfree_nocheck(chip->res_iobase);
- }
+ ....
+ pci_release_regions(chip->pci);
....
}
]]>
@@ -1857,9 +1704,6 @@
#include
....
- #define chip_t mychip_t
- ....
-
/* hardware definition */
static snd_pcm_hardware_t snd_mychip_playback_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
@@ -2224,8 +2068,7 @@
private_data, return);
+ mychip_t *chip = snd_pcm_chip(pcm);
// free your own data
kfree(chip->my_private_pcm_data);
// do what you like else...
@@ -2653,8 +2496,11 @@ struct _snd_pcm_runtime {
done in
the open callback.
- Since it's a void pointer, you should use magic-kmalloc and
- magic-cast for such an object.
+ Don't mix this with pcm->private_data.
+ The pcm->private_data usually points the
+ chip instance assigned statically at the creation of PCM, while the
+ runtime->private_data points a dynamic
+ data created at the PCM open callback.
@@ -2663,7 +2509,7 @@ struct _snd_pcm_runtime {
{
my_pcm_data_t *data;
....
- data = snd_magic_kmalloc(my_pcm_data_t, 0, GFP_KERNEL);
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
substream->runtime->private_data = data;
....
}
@@ -2710,8 +2556,6 @@ struct _snd_pcm_runtime {
-
-
- It's expanded with a magic-cast, so the cast-error is
- automatically checked. You should define chip_t at
- the beginning of the code, since this will be referred in many
- places of pcm and control interfaces.
+ The macro reads substream->private_data,
+ which is a copy of pcm->private_data.
+ You can override the former if you need to assign different data
+ records per PCM substream. For example, cmi8330 driver assigns
+ different private_data for playback and capture directions,
+ because it uses two different codecs (SB- and AD-compatible) for
+ different directions.
@@ -2803,7 +2648,7 @@ struct _snd_pcm_runtime {
static int snd_xxx_close(snd_pcm_substream_t *substream)
{
....
- snd_magic_kfree(substream->runtime->private_data);
+ kfree(substream->runtime->private_data);
....
}
]]>
@@ -2887,10 +2732,10 @@ struct _snd_pcm_runtime {
Another note is that this callback is non-atomic
(schedulable). This is important, because the
- prepare callback
+ trigger callback
is atomic (non-schedulable). That is, mutex or any
- schedule-related functions are available only in
- hw_params callback.
+ schedule-related functions are not available in
+ trigger callback.
Please see the subsection
Atomicity for details.
@@ -2956,7 +2801,8 @@ struct _snd_pcm_runtime {
- As mentioned above, this callback is atomic.
+ Note that this callback became non-atomic since the recent version.
+ You can use schedule-related fucntions safely in this callback now.
@@ -3041,7 +2887,12 @@ struct _snd_pcm_runtime {
- This callback is also atomic.
+ As mentioned, this callback is atomic. You cannot call
+ the function going to sleep.
+ The trigger callback should be as minimal as possible,
+ just really triggering the DMA. The other stuff should be
+ initialized hw_params and prepare callbacks properly
+ beforehand.
@@ -3176,7 +3027,7 @@ struct _snd_pcm_runtime {
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
- mychip_t *chip = snd_magic_cast(mychip_t, dev_id, return);
+ mychip_t *chip = dev_id;
spin_lock(&chip->lock);
....
if (pcm_irq_invoked(chip)) {
@@ -3220,7 +3071,7 @@ struct _snd_pcm_runtime {
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
- mychip_t *chip = snd_magic_cast(mychip_t, dev_id, return);
+ mychip_t *chip = dev_id;
spin_lock(&chip->lock);
....
if (pcm_irq_invoked(chip)) {
@@ -3287,7 +3138,7 @@ struct _snd_pcm_runtime {
As already seen, some pcm callbacks are atomic and some are
not. For example, hw_params callback is
- non-atomic, while prepare callback is
+ non-atomic, while trigger callback is
atomic. This means, the latter is called already in a spinlock
held by the PCM middle layer. Please take this atomicity into
account when you use a spinlock or a semaphore in the callbacks.
@@ -3298,7 +3149,7 @@ struct _snd_pcm_runtime {
schedule or go to
sleep. The semaphore and mutex do sleep,
and hence they cannot be used inside the atomic callbacks
- (e.g. prepare callback).
+ (e.g. trigger callback).
For taking a certain delay in such a callback, please use
udelay() or mdelay().
@@ -3325,7 +3176,7 @@ struct _snd_pcm_runtime {
static unsigned int rates[] =
{4000, 10000, 22050, 44100};
static snd_pcm_hw_constraint_list_t constraints_rates = {
- .count = sizeof(rates) / sizeof(rates[0]),
+ .count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
@@ -3988,8 +3839,7 @@ struct _snd_pcm_runtime {
static unsigned short snd_mychip_ac97_read(ac97_t *ac97,
unsigned short reg)
{
- mychip_t *chip = snd_magic_cast(mychip_t,
- ac97->private_data, return 0);
+ mychip_t *chip = ac97->private_data;
....
// read a register value here from the codec
return the_register_value;
@@ -3998,26 +3848,26 @@ struct _snd_pcm_runtime {
static void snd_mychip_ac97_write(ac97_t *ac97,
unsigned short reg, unsigned short val)
{
- mychip_t *chip = snd_magic_cast(mychip_t,
- ac97->private_data, return 0);
+ mychip_t *chip = ac97->private_data;
....
// write the given register value to the codec
}
static int snd_mychip_ac97(mychip_t *chip)
{
- ac97_bus_t bus, *pbus;
- ac97_t ac97;
+ ac97_bus_t *bus;
+ ac97_template_t ac97;
int err;
+ static ac97_bus_ops_t ops = {
+ .write = snd_mychip_ac97_write,
+ .read = snd_mychip_ac97_read,
+ };
- memset(&bus, 0, sizeof(bus));
- bus.write = snd_mychip_ac97_write;
- bus.read = snd_mychip_ac97_read;
- if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0)
+ if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus)) < 0)
return err;
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
- return snd_ac97_mixer(pbus, &ac97, &chip->ac97);
+ return snd_ac97_mixer(bus, &ac97, &chip->ac97);
}
]]>
@@ -4030,18 +3880,18 @@ struct _snd_pcm_runtime {
Constructor
For creating an ac97 instance, first call snd_ac97_bus
- with ac97_bus_t record including callback functions.
+ with an ac97_bus_ops_t record with callback functions.
@@ -4050,13 +3900,13 @@ struct _snd_pcm_runtime {
- And then call snd_ac97_mixer() with an ac97_t
+ And then call snd_ac97_mixer() with an ac97_template_t
record together with the bus pointer created above.
private_data, return 0);
+ mychip_t *chip = ac97->private_data;
....
return the_register_value;
}
@@ -4241,7 +4090,7 @@ struct _snd_pcm_runtime {
On some chip, the clock of the codec isn't 48000 but using a
PCI clock (to save a quartz!). In this case, change the field
- ac97->clock to the corresponding
+ bus->clock to the corresponding
value. For example, intel8x0
and es1968 drivers have the auto-measurement function of the
clock.
@@ -4375,7 +4224,7 @@ struct _snd_pcm_runtime {
private_data, );
+ mpu = rmidi->private_data;
]]>
@@ -4546,16 +4395,15 @@ struct _snd_pcm_runtime {
You can then pass any pointer value to the
- private_data. Again, it should be a
- magic-allocated record, so that the cast can be checked more
- safely. If you assign a private data, you should define the
+ private_data.
+ If you assign a private data, you should define the
destructor, too. The destructor function is set to
private_free field.
private_data = p;
hw->private_free = mydata_free;
]]>
@@ -4569,9 +4417,8 @@ struct _snd_pcm_runtime {
private_data, return);
- snd_magic_kfree(p);
+ mydata_t *p = hw->private_data;
+ kfree(p);
}
]]>
@@ -5097,8 +4944,7 @@ struct _snd_pcm_runtime {
static void my_proc_read(snd_info_entry_t *entry,
snd_info_buffer_t *buffer)
{
- chip_t *cm = snd_magic_cast(mychip_t,
- entry->private_data, return);
+ chip_t *chip = entry->private_data;
snd_iprintf(buffer, "This is my chip!\n");
snd_iprintf(buffer, "Port = %ld\n", chip->port);
@@ -5267,8 +5113,7 @@ struct _snd_pcm_runtime {
static int mychip_suspend(snd_card_t *card, unsigned int state)
{
// (1)
- mychip_t *chip = snd_magic_cast(mychip_t, card->pm_private_data,
- return -ENXIO);
+ mychip_t *chip = card->pm_private_data;
// (2)
snd_pcm_suspend_all(chip->pcm);
// (3)
@@ -5310,8 +5155,7 @@ struct _snd_pcm_runtime {
static void mychip_resume(mychip_t *chip)
{
// (1)
- mychip_t *chip = snd_magic_cast(mychip_t, card->pm_private_data,
- return -ENXIO);
+ mychip_t *chip = card->pm_private_data;
// (2)
pci_enable_device(chip->pci);
// (3)
@@ -5428,19 +5272,7 @@ struct _snd_pcm_runtime {
The module parameters must be declared with the standard
module_param()(),
module_param_array()() and
- MODULE_PARM_DESC() macros. The ALSA provides
- an additional macro, MODULE_PARM_SYNTAX(),
- for describing its syntax. The strings will be written to
- /lib/modules/XXX/modules.generic_string
- file.
-
-
-
- For convenience, the typical string arguments given to
- MODULE_PARM_SYNTAX() are defined in
- <sound/initval.h>, such as
- SNDRV_ID_DESC or
- SNDRV_ENABLED.
+ MODULE_PARM_DESC() macros.
@@ -5454,13 +5286,10 @@ struct _snd_pcm_runtime {
static int boot_devs;
module_param_array(index, int, boot_devs, 0444);
MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
- MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
module_param_array(id, charp, boot_devs, 0444);
MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
- MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
module_param_array(enable, bool, boot_devs, 0444);
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
- MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
]]>
@@ -5479,9 +5308,8 @@ struct _snd_pcm_runtime {
@@ -5636,14 +5464,14 @@ struct _snd_pcm_runtime {
SND_TOPDIR=../..
endif
- include $(TOPDIR)/toplevel.config
- include $(TOPDIR)/Makefile.conf
+ include $(SND_TOPDIR)/toplevel.config
+ include $(SND_TOPDIR)/Makefile.conf
snd-xyz-objs := xyz.o abc.o def.o
obj-$(CONFIG_SND_XYZ) += snd-xyz.o
- include $(TOPDIR)/Rules.make
+ include $(SND_TOPDIR)/Rules.make
]]>