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 ]]>