X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=Documentation%2Fsound%2Falsa%2FDocBook%2Fwriting-an-alsa-driver.tmpl;h=ccd0a953953dcc09a52288d766bff968afff3e4b;hb=refs%2Fheads%2Fvserver;hp=63a46fd2b5273786014c5bfb9cfc7171a20214d6;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;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 63a46fd2b..ccd0a9539 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 + November 17, 2005 + 0.3.6 @@ -30,7 +30,7 @@ - Copyright (c) 2002-2004 Takashi Iwai tiwai@suse.de + Copyright (c) 2002-2005 Takashi Iwai tiwai@suse.de @@ -110,9 +110,9 @@ - One is the the trees provided as a tarball or via cvs from the + One is the trees provided as a tarball or via cvs from the ALSA's ftp site, and another is the 2.6 (or later) Linux kernel - tree. To synchronize both, the ALSA driver tree is split to + tree. To synchronize both, the ALSA driver tree is split into two different trees: alsa-kernel and alsa-driver. The former contains purely the source codes for the Linux 2.6 (or later) tree. This tree is designed only for compilation on 2.6 or @@ -371,7 +371,7 @@ create probe() callback. create remove() callback. create pci_driver table which contains the three pointers above. - create init() function just calling pci_module_init() to register the pci_driver table defined above. + create init() function just calling pci_register_driver() to register the pci_driver table defined above. create exit() function to call pci_unregister_driver() function. @@ -395,51 +395,46 @@ #include #include #include - #define SNDRV_GET_ID #include - // module parameters (see "Module Parameters") + /* module parameters (see "Module Parameters") */ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; - // definition of the chip-specific record - typedef struct snd_mychip mychip_t; - struct snd_mychip { - snd_card_t *card; + /* definition of the chip-specific record */ + struct mychip { + struct snd_card *card; // rest of implementation will be in the section // "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) + /* chip-specific destructor + * (see "PCI Resource Managements") + */ + static int snd_mychip_free(struct mychip *chip) { - // will be implemented later... + .... // will be implemented later... } - // component-destructor - // (see "Management of Cards and Components") - static int snd_mychip_dev_free(snd_device_t *device) + /* component-destructor + * (see "Management of Cards and Components") + */ + static int snd_mychip_dev_free(struct snd_device *device) { - mychip_t *chip = snd_magic_cast(mychip_t, - device->device_data, return -ENXIO); - return snd_mychip_free(chip); + return snd_mychip_free(device->device_data); } - // chip-specific constructor - // (see "Management of Cards and Components") - static int __devinit snd_mychip_create(snd_card_t *card, + /* chip-specific constructor + * (see "Management of Cards and Components") + */ + static int __devinit snd_mychip_create(struct snd_card *card, struct pci_dev *pci, - mychip_t **rchip) + struct mychip **rchip) { - mychip_t *chip; + struct mychip *chip; int err; - static snd_device_ops_t ops = { + static struct snd_device_ops ops = { .dev_free = snd_mychip_dev_free, }; @@ -447,9 +442,10 @@ // 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 = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -457,26 +453,30 @@ // rest of initialization here; will be implemented // later, see "PCI Resource Managements" + .... if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_mychip_free(chip); return err; } + + snd_card_set_dev(card, &pci->dev); + *rchip = chip; return 0; } - // constructor -- see "Constructor" sub-section + /* constructor -- see "Constructor" sub-section */ static int __devinit snd_mychip_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; - snd_card_t *card; - mychip_t *chip; + struct snd_card *card; + struct mychip *chip; int err; - // (1) + /* (1) */ if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { @@ -484,45 +484,42 @@ return -ENOENT; } - // (2) + /* (2) */ card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; - // (3) + /* (3) */ if ((err = snd_mychip_create(card, pci, &chip)) < 0) { snd_card_free(card); return err; } - // (4) + /* (4) */ strcpy(card->driver, "My Chip"); strcpy(card->shortname, "My Own Chip 123"); sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->ioport, chip->irq); - // (5) - // implemented later + /* (5) */ + .... // implemented later - // (6) + /* (6) */ if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } - // (7) - pci_set_drvdata(pci, chip); + /* (7) */ + pci_set_drvdata(pci, card); dev++; return 0; } - // destructor -- see "Destructor" sub-section + /* destructor -- see "Destructor" sub-section */ static void __devexit snd_mychip_remove(struct pci_dev *pci) { - mychip_t *chip = snd_magic_cast(mychip_t, - pci_get_drvdata(pci), return); - if (chip) - snd_card_free(chip->card); + snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); } ]]> @@ -583,7 +580,7 @@ @@ -606,7 +603,7 @@ - In the above, the chip record is stored. This pointer is + In the above, the card record is stored. This pointer is referred in the remove callback and power-management callbacks, too. - If the card doesn't support the suspend/resume, you can store - the card pointer instead of the chip pointer, so that - snd_card_free can be called directly - without cast in the remove callback. But anyway, be sure - which pointer is used. @@ -726,21 +718,15 @@ card); + snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); } ]]> - The above code assumes that the chip is allocated - with snd_magic stuff and - has the field to hold the card pointer (see the next - section). + The above code assumes that the card pointer is set to the PCI + driver data. @@ -758,13 +744,12 @@ #include #include #include - #define SNDRV_GET_ID #include ]]> - where the last twos are necessary only when module options are + where the last one is necessary only when module options are defined in the source file. If the codes are split to several files, the file without module options don't need them. @@ -779,7 +764,7 @@ - The ALSA interfaces like PCM or control API are define in other + The ALSA interfaces like PCM or control API are defined in other header files as <sound/xxx.h>. They have to be included after <sound/core.h>. @@ -819,7 +804,7 @@ @@ -843,7 +828,7 @@ After the card is created, you can attach the components (devices) to the card instance. On ALSA driver, a component is - represented as a snd_device_t object. + represented as a struct snd_device object. A component can be a PCM instance, a control interface, a raw MIDI interface, etc. Each of such instances has one component entry. @@ -904,14 +889,11 @@ The chip-specific information, e.g. the i/o port address, its resource pointer, or the irq number, is stored in the chip-specific record. - Usually, the chip-specific record is typedef'ed as - xxx_t like the following: @@ -919,13 +901,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. @@ -938,12 +913,12 @@ - whether mychip_t is the type of the chip record. + whether struct mychip is the type of the chip record. @@ -952,14 +927,13 @@ private_data; + struct mychip *chip = card->private_data; ]]> - 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. @@ -970,22 +944,19 @@ After allocating a card instance via snd_card_new() (with NULL on the 4th arg), call - snd_magic_kcalloc(). + kzalloc(). - - Once when the record is allocated via snd_magic stuff, you - can use magic-cast for the void pointer. @@ -995,8 +966,8 @@ @@ -1016,21 +987,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 @@ -1039,7 +995,7 @@ device_data, - return -ENXIO); - return snd_mychip_free(chip); + return snd_mychip_free(device->device_data); } ]]> @@ -1070,126 +1024,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. - -
@@ -1220,9 +1054,8 @@ For a device which allows hotplugging, you can use - snd_card_free_in_thread. This one will - postpone the destruction and wait in a kernel-thread until all - devices are closed. + snd_card_free_when_closed. This one will + postpone the destruction until all devices are closed.
@@ -1247,95 +1080,97 @@ PCI Resource Managements Example res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } - // release the irq + /* release the irq */ if (chip->irq >= 0) - free_irq(chip->irq, (void *)chip); - // release the data - snd_magic_kfree(chip); + free_irq(chip->irq, chip); + /* release the i/o ports & memory */ + pci_release_regions(chip->pci); + /* disable the PCI entry */ + pci_disable_device(chip->pci); + /* release the data */ + kfree(chip); return 0; } - // chip-specific constructor - static int __devinit snd_mychip_create(snd_card_t *card, + /* chip-specific constructor */ + static int __devinit snd_mychip_create(struct snd_card *card, struct pci_dev *pci, - mychip_t **rchip) + struct mychip **rchip) { - mychip_t *chip; + struct mychip *chip; int err; - static snd_device_ops_t ops = { + static struct snd_device_ops ops = { .dev_free = snd_mychip_dev_free, }; *rchip = NULL; - // check PCI availability (28bit DMA) + /* initialize the PCI entry */ if ((err = pci_enable_device(pci)) < 0) return err; - if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || - pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { + /* check PCI availability (28bit DMA) */ + if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { printk(KERN_ERR "error to set 28bit mask DMA\n"); + pci_disable_device(pci); return -ENXIO; } - chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL); - if (chip == NULL) + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } - // initialize the stuff + /* initialize the stuff */ chip->card = card; chip->pci = pci; 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; + /* (1) PCI resource allocation */ + if ((err = pci_request_regions(pci, "My Chip")) < 0) { + kfree(chip); + pci_disable_device(pci); + 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)) { + IRQF_SHARED, "My Chip", 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; - // (2) initialization of the chip hardware - // (not implemented in this document) + /* (2) initialization of the chip hardware */ + .... // (not implemented in this document) if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_mychip_free(chip); return err; } + + snd_card_set_dev(card, &pci->dev); + *rchip = chip; return 0; } - // PCI IDs + /* PCI IDs */ static struct pci_device_id snd_mychip_ids[] = { { PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, @@ -1344,7 +1179,7 @@ }; MODULE_DEVICE_TABLE(pci, snd_mychip_ids); - // pci_driver definition + /* pci_driver definition */ static struct pci_driver driver = { .name = "My Own Chip", .id_table = snd_mychip_ids, @@ -1352,22 +1187,13 @@ .remove = __devexit_p(snd_mychip_remove), }; - // initialization of the module + /* initialization of the module */ static int __init alsa_card_mychip_init(void) { - int err; - - if ((err = pci_module_init(&driver)) < 0) { - #ifdef MODULE - printk(KERN_ERR "My chip soundcard not found " - "or device busy\n"); - #endif - return err; - } - return 0; + return pci_register_driver(&driver); } - // clean up the module + /* clean up the module */ static void __exit alsa_card_mychip_exit(void) { pci_unregister_driver(&driver); @@ -1389,7 +1215,7 @@ The allocation of PCI resources is done in the probe() function, and usually an extra xxx_create() function is written for this - purpose. + purpose. @@ -1398,7 +1224,7 @@ allocating resources. Also, you need to set the proper PCI DMA mask to limit the accessed i/o range. In some cases, you might need to call pci_set_master() function, - too. + too. @@ -1409,9 +1235,10 @@ Now assume that this PCI device has an I/O port with 8 bytes - and an interrupt. Then mychip_t will have the - following fields: + and an interrupt. Then struct mychip will have the + following fields: @@ -1459,7 +1284,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 + kzalloc() automatically, so you don't have to take care of resetting them. @@ -1469,20 +1294,19 @@ 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); + pci_disable_device(pci); + return err; } + chip->port = pci_resource_start(pci, 0); ]]> + It will reserve the i/o port region of 8 bytes of the given PCI device. The returned value, chip->res_port, is allocated via kmalloc() by @@ -1498,10 +1322,9 @@ irq, snd_mychip_interrupt, - SA_INTERRUPT|SA_SHIRQ, "My Chip", - (void *)chip)) { - snd_mychip_free(chip); + IRQF_DISABLED|IRQF_SHARED, "My Chip", chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); + snd_mychip_free(chip); return -EBUSY; } chip->irq = pci->irq; @@ -1518,7 +1341,7 @@ On the PCI bus, the interrupts can be shared. Thus, - SA_SHIRQ is given as the interrupt flag of + IRQF_SHARED is given as the interrupt flag of request_irq(). @@ -1540,16 +1363,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); + struct mychip *chip = dev_id; .... return IRQ_HANDLED; } ]]> - - Again the magic-cast is used here to get the correct pointer - from the second argument. @@ -1561,64 +1381,74 @@ 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: res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + if (chip->irq >= 0) + free_irq(chip->irq, 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. - As you can see, the i/o resource pointer is also to be freed - via kfree_nocheck() after - release_resource() is called. You - cannot use kfree() here, because on ALSA, - kfree() may be a wrapper to its own - allocator with the memory debugging. Since the resource pointer - is allocated externally outside the ALSA, it must be released - via the native - kfree(). - kfree_nocheck() is used for that; it calls - the native kfree() without wrapper. + 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); +]]> + + - For releasing the interrupt, do like this: + 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: irq >= 0) - free_irq(chip->irq, (void *)chip); + release_and_free_resource(chip->res_port); ]]> + + + Don't forget to call pci_disable_device() + before all finished. + + + 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. @@ -1634,7 +1464,7 @@ When the chip-data is assigned to the card using snd_device_new() with SNDRV_DEV_LOWLELVEL , its destructor is - called at the last. that is, it is assured that all other + called at the last. That is, it is assured that all other components like PCMs and controls have been already released. You don't have to call stopping PCMs, etc. explicitly, but just stop the hardware in the low-level. @@ -1648,30 +1478,27 @@ - and the allocation would be (assuming its size is 512 bytes): + and the allocation would be like below: 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; + if ((err = pci_request_regions(pci, "My Chip")) < 0) { + kfree(chip); + return err; } + chip->iobase_phys = pci_resource_start(pci, 0); + chip->iobase_virt = ioremap_nocache(chip->iobase_phys, + pci_resource_len(pci, 0)); ]]> @@ -1681,15 +1508,13 @@ iobase_virt) - iounmap((void *)chip->iobase_virt); - if (chip->res_iobase) { - release_resource(chip->res_iobase); - kfree_nocheck(chip->res_iobase); - } + iounmap(chip->iobase_virt); + .... + pci_release_regions(chip->pci); .... } ]]> @@ -1699,6 +1524,30 @@ +
+ Registration of Device Struct + + At some point, typically after calling snd_device_new(), + you need to register the struct device of the chip + you're handling for udev and co. ALSA provides a macro for compatibility with + older kernels. Simply call like the following: + + +dev); +]]> + + + so that it stores the PCI's device pointer to the card. This will be + referred by ALSA core functions later when the devices are registered. + + + In the case of non-PCI, pass the proper device struct pointer of the BUS + instead. (In the case of legacy ISA without PnP, you don't have to do + anything.) + +
+
PCI Entries @@ -1781,16 +1630,7 @@ .... - #define chip_t mychip_t - .... - /* hardware definition */ - static snd_pcm_hardware_t snd_mychip_playback_hw = { + static struct snd_pcm_hardware snd_mychip_playback_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -1912,7 +1749,7 @@ }; /* hardware definition */ - static snd_pcm_hardware_t snd_mychip_capture_hw = { + static struct snd_pcm_hardware snd_mychip_capture_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -1931,10 +1768,10 @@ }; /* open callback */ - static int snd_mychip_playback_open(snd_pcm_substream_t *substream) + static int snd_mychip_playback_open(struct snd_pcm_substream *substream) { - mychip_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; + struct mychip *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; runtime->hw = snd_mychip_playback_hw; // more hardware-initialization will be done here @@ -1942,19 +1779,19 @@ } /* close callback */ - static int snd_mychip_playback_close(snd_pcm_substream_t *substream) + static int snd_mychip_playback_close(struct snd_pcm_substream *substream) { - mychip_t *chip = snd_pcm_substream_chip(substream); + struct mychip *chip = snd_pcm_substream_chip(substream); // the hardware-specific codes will be here return 0; } /* open callback */ - static int snd_mychip_capture_open(snd_pcm_substream_t *substream) + static int snd_mychip_capture_open(struct snd_pcm_substream *substream) { - mychip_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; + struct mychip *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; runtime->hw = snd_mychip_capture_hw; // more hardware-initialization will be done here @@ -1962,47 +1799,48 @@ } /* close callback */ - static int snd_mychip_capture_close(snd_pcm_substream_t *substream) + static int snd_mychip_capture_close(struct snd_pcm_substream *substream) { - mychip_t *chip = snd_pcm_substream_chip(substream); + struct mychip *chip = snd_pcm_substream_chip(substream); // the hardware-specific codes will be here return 0; } /* hw_params callback */ - static int snd_mychip_pcm_hw_params(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t * hw_params) + static int snd_mychip_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } /* hw_free callback */ - static int snd_mychip_pcm_hw_free(snd_pcm_substream_t *substream) + static int snd_mychip_pcm_hw_free(struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } /* prepare callback */ - static int snd_mychip_pcm_prepare(snd_pcm_substream_t *substream) + static int snd_mychip_pcm_prepare(struct snd_pcm_substream *substream) { - mychip_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; + struct mychip *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; - // set up the hardware with the current configuration - // for example... + /* set up the hardware with the current configuration + * for example... + */ mychip_set_sample_format(chip, runtime->format); mychip_set_sample_rate(chip, runtime->rate); mychip_set_channels(chip, runtime->channels); - mychip_set_dma_setup(chip, runtime->dma_area, + mychip_set_dma_setup(chip, runtime->dma_addr, chip->buffer_size, chip->period_size); return 0; } /* trigger callback */ - static int snd_mychip_pcm_trigger(snd_pcm_substream_t *substream, + static int snd_mychip_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { switch (cmd) { @@ -2019,18 +1857,18 @@ /* pointer callback */ static snd_pcm_uframes_t - snd_mychip_pcm_pointer(snd_pcm_substream_t *substream) + snd_mychip_pcm_pointer(struct snd_pcm_substream *substream) { - mychip_t *chip = snd_pcm_substream_chip(substream); + struct mychip *chip = snd_pcm_substream_chip(substream); unsigned int current_ptr; - // get the current hardware pointer + /* get the current hardware pointer */ current_ptr = mychip_get_hw_pointer(chip); return current_ptr; } /* operators */ - static snd_pcm_ops_t snd_mychip_playback_ops = { + static struct snd_pcm_ops snd_mychip_playback_ops = { .open = snd_mychip_playback_open, .close = snd_mychip_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -2042,7 +1880,7 @@ }; /* operators */ - static snd_pcm_ops_t snd_mychip_capture_ops = { + static struct snd_pcm_ops snd_mychip_capture_ops = { .open = snd_mychip_capture_open, .close = snd_mychip_capture_close, .ioctl = snd_pcm_lib_ioctl, @@ -2058,9 +1896,9 @@ */ /* create a pcm device */ - static int __devinit snd_mychip_new_pcm(mychip_t *chip) + static int __devinit snd_mychip_new_pcm(struct mychip *chip) { - snd_pcm_t *pcm; + struct snd_pcm *pcm; int err; if ((err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, @@ -2075,6 +1913,7 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mychip_capture_ops); /* pre-allocation of buffers */ + /* NOTE: this may fail */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 64*1024); @@ -2089,16 +1928,16 @@
Constructor - A pcm instance is allocated snd_pcm_new() + A pcm instance is allocated by snd_pcm_new() function. It would be better to create a constructor for pcm, namely, card, "My Chip", 0, 1, 1, @@ -2141,13 +1980,13 @@ specify more numbers, but they must be handled properly in open/close, etc. callbacks. When you need to know which substream you are referring to, then it can be obtained from - snd_pcm_substream_t data passed to each callback + struct snd_pcm_substream data passed to each callback as follows: number; ]]> @@ -2176,7 +2015,7 @@ PCM Instance with a Destructor private_data, return); - // free your own data + struct mychip *chip = snd_pcm_chip(pcm); + /* free your own data */ kfree(chip->my_private_pcm_data); - // do what you like else... + // do what you like else + .... } - static int __devinit snd_mychip_new_pcm(mychip_t *chip) + static int __devinit snd_mychip_new_pcm(struct mychip *chip) { - snd_pcm_t *pcm; + struct snd_pcm *pcm; .... - // allocate your own data + /* allocate your own data */ chip->my_private_pcm_data = kmalloc(...); - // set the destructor + /* set the destructor */ pcm->private_data = chip; pcm->private_free = mychip_pcm_free; .... @@ -2301,7 +2140,7 @@ @@ -2389,7 +2228,7 @@ struct _snd_pcm_runtime { For the operators (callbacks) of each sound driver, most of these records are supposed to be read-only. Only the PCM - middle-layer changes / updates these info. The excpetions are + middle-layer changes / updates these info. The exceptions are the hardware description (hw), interrupt callbacks (transfer_ack_xxx), DMA buffer information, and the private data. Besides, if you use the standard buffer allocation @@ -2404,7 +2243,7 @@ struct _snd_pcm_runtime {
Hardware Description - The hardware descriptor (snd_pcm_hardware_t) + The hardware descriptor (struct snd_pcm_hardware) contains the definitions of the fundamental hardware configuration. Above all, you'll need to define this in @@ -2419,9 +2258,9 @@ struct _snd_pcm_runtime { runtime; + struct snd_pcm_runtime *runtime = substream->runtime; ... - runtime->hw = snd_mychip_playback_hw; // common definition + runtime->hw = snd_mychip_playback_hw; /* common definition */ if (chip->model == VERY_OLD_ONE) runtime->hw.channels_max = 1; ]]> @@ -2434,7 +2273,7 @@ struct _snd_pcm_runtime { PAUSE bit means that the pcm supports the pause operation, while the RESUME bit means that the pcm supports - the suspend/resume operation. If these flags - are set, the trigger callback below - must handle the corresponding commands. + the full suspend/resume operation. + If PAUSE flag is set, + the trigger callback below + must handle the corresponding (pause push/release) commands. + The suspend/resume trigger commands can be defined even without + RESUME flag. See + Power Management section for details. @@ -2664,7 +2508,7 @@ struct _snd_pcm_runtime { Running Status The running status can be referred via runtime->status. - This is the pointer to snd_pcm_mmap_status_t + This is the pointer to struct snd_pcm_mmap_status record. For example, you can get the current DMA hardware pointer via runtime->status->hw_ptr. @@ -2672,7 +2516,7 @@ struct _snd_pcm_runtime { The DMA application pointer can be referred via runtime->control, which points - snd_pcm_mmap_control_t record. + struct snd_pcm_mmap_control record. However, accessing directly to this value is not recommended.
@@ -2685,17 +2529,20 @@ 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. runtime->private_data = data; .... } @@ -2735,29 +2582,28 @@ struct _snd_pcm_runtime { The callback function takes at least the argument with - snd_pcm_substream_t pointer. For retrieving the + snd_pcm_substream pointer. For retrieving the chip record from the given substream instance, you can use the following macro. - - - 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.
@@ -2766,7 +2612,7 @@ struct _snd_pcm_runtime { @@ -2781,10 +2627,10 @@ struct _snd_pcm_runtime { runtime; + struct mychip *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; runtime->hw = snd_mychip_playback_hw; return 0; @@ -2817,7 +2663,7 @@ struct _snd_pcm_runtime { @@ -2832,10 +2678,10 @@ struct _snd_pcm_runtime { runtime->private_data); + kfree(substream->runtime->private_data); .... } ]]> @@ -2859,8 +2705,8 @@ struct _snd_pcm_runtime { @@ -2919,10 +2765,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. @@ -2935,7 +2781,7 @@ struct _snd_pcm_runtime { @@ -2970,7 +2816,7 @@ struct _snd_pcm_runtime { @@ -2988,7 +2834,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 functions safely in this callback now. @@ -3018,7 +2865,7 @@ struct _snd_pcm_runtime { @@ -3060,8 +2907,8 @@ struct _snd_pcm_runtime { - When the pcm supports the suspend/resume operation - (i.e. SNDRV_PCM_INFO_RESUME flag is set), + When the pcm supports the suspend/resume operation, + regardless of full or partial suspend/resume support, SUSPEND and RESUME commands must be handled, too. These commands are issued when the power-management status is @@ -3070,10 +2917,17 @@ struct _snd_pcm_runtime { do suspend and resume of the pcm substream, and usually, they are identical with STOP and START commands, respectively. + See + Power Management section for details. - 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.
@@ -3083,7 +2937,7 @@ struct _snd_pcm_runtime { @@ -3139,6 +2993,9 @@ struct _snd_pcm_runtime { current appl_ptr for the internal buffer, and this callback is useful only for such a purpose.
+ + This callback is atomic. +
@@ -3190,7 +3047,7 @@ struct _snd_pcm_runtime { - If you aquire a spinlock in the interrupt handler, and the + If you acquire a spinlock in the interrupt handler, and the lock is used in other pcm callbacks, too, then you have to release the lock before calling snd_pcm_period_elapsed(), because @@ -3208,11 +3065,11 @@ 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); + struct mychip *chip = dev_id; spin_lock(&chip->lock); .... if (pcm_irq_invoked(chip)) { - // call updater, unlock before it + /* call updater, unlock before it */ spin_unlock(&chip->lock); snd_pcm_period_elapsed(chip->substream); spin_lock(&chip->lock); @@ -3252,29 +3109,30 @@ 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); + struct mychip *chip = dev_id; spin_lock(&chip->lock); .... if (pcm_irq_invoked(chip)) { unsigned int last_ptr, size; - // get the current hardware pointer (in frames) + /* get the current hardware pointer (in frames) */ last_ptr = get_hw_ptr(chip); - // calculate the processed frames since the - // last update + /* calculate the processed frames since the + * last update + */ if (last_ptr < chip->last_ptr) size = runtime->buffer_size + last_ptr - chip->last_ptr; else size = last_ptr - chip->last_ptr; - // remember the last updated point + /* remember the last updated point */ chip->last_ptr = last_ptr; - // accumulate the size + /* accumulate the size */ chip->size += size; - // over the period boundary? + /* over the period boundary? */ if (chip->size >= runtime->period_size) { - // reset the accumulator + /* reset the accumulator */ chip->size %= runtime->period_size; - // call updater + /* call updater */ spin_unlock(&chip->lock); snd_pcm_period_elapsed(substream); spin_lock(&chip->lock); @@ -3319,7 +3177,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. @@ -3330,11 +3188,16 @@ 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(). + + All three atomic callbacks (trigger, pointer, and ack) are + called with local interrupts disabled. + +
Constraints @@ -3356,13 +3219,13 @@ struct _snd_pcm_runtime { There are many different constraints. - Look in sound/asound.h for a complete list. + Look in sound/pcm.h for a complete list. You can even define your own constraint rules. For example, let's suppose my_chip can manage a substream of 1 channel if and only if the format is S16_LE, otherwise it supports any format - specified in the snd_pcm_hardware_t stucture (or in any + specified in the snd_pcm_hardware stucture (or in any other constraint_list). You can build a rule like this: Example of Hardware Constraints for Channels min < 2) { fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE; return snd_mask_refine(f, &fmt); @@ -3433,12 +3297,13 @@ struct _snd_pcm_runtime { Example of Hardware Constraints for Channels bits[0] == SNDRV_PCM_FMTBIT_S16_LE) { @@ -3511,18 +3376,18 @@ struct _snd_pcm_runtime { callbacks: info, get and put. Then, define a - snd_kcontrol_new_t record, such as: + struct snd_kcontrol_new record, such as: Definition of a Control The iface field specifies the type of - the control, - SNDRV_CTL_ELEM_IFACE_XXX. There are - MIXER, PCM, - CARD, etc. + the control, SNDRV_CTL_ELEM_IFACE_XXX, which + is usually MIXER. + Use CARD for global controls that are not + logically part of the mixer. + If the control is closely associated with some specific device on + the sound card, use HWDEP, + PCM, RAWMIDI, + TIMER, or SEQUENCER, and + specify the device number with the + device and + subdevice fields. @@ -3576,7 +3448,7 @@ struct _snd_pcm_runtime { - The private_values field contains + The private_value field contains an arbitrary long integer value for this record. When using generic info, get and @@ -3673,7 +3545,7 @@ struct _snd_pcm_runtime { More precise information can be found in - alsa-kernel/Documentation/sound/alsa/ControlNames.txt. + Documentation/sound/alsa/ControlNames.txt.
@@ -3727,7 +3599,7 @@ struct _snd_pcm_runtime { The info callback is used to get the detailed information of this control. This must store the - values of the given snd_ctl_elem_info_t + values of the given struct snd_ctl_elem_info object. For example, for a boolean control with a single element will be: @@ -3735,8 +3607,8 @@ struct _snd_pcm_runtime { Example of info callback type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; @@ -3770,8 +3642,8 @@ struct _snd_pcm_runtime { Example of get callback value.integer.value[0] = get_some_value(chip); return 0; } @@ -3821,8 +3693,7 @@ struct _snd_pcm_runtime { Here, the chip instance is retrieved via snd_kcontrol_chip() macro. This macro - converts from kcontrol->private_data to the type defined by - chip_t. The + just accesses to kcontrol->private_data. The kcontrol->private_data field is given as the argument of snd_ctl_new() (see the later subsection @@ -3846,8 +3717,8 @@ struct _snd_pcm_runtime { private_value & 0xff; int shift = (kcontrol->private_value >> 16) & 0xff; @@ -3883,10 +3754,10 @@ struct _snd_pcm_runtime { Example of put callback current_value != ucontrol->value.integer.value[0]) { @@ -3943,7 +3814,7 @@ struct _snd_pcm_runtime { where my_control is the - snd_kcontrol_new_t object defined above, and chip + struct snd_kcontrol_new object defined above, and chip is the object pointer to be passed to kcontrol->private_data which can be referred in callbacks. @@ -3951,7 +3822,7 @@ struct _snd_pcm_runtime { snd_ctl_new1() allocates a new - snd_kcontrol_t instance (that's why the definition + snd_kcontrol instance (that's why the definition of my_control can be with __devinitdata prefix), and snd_ctl_add assigns the given @@ -3978,7 +3849,7 @@ struct _snd_pcm_runtime { control id pointer for the notification. The event-mask specifies the types of notification, for example, in the above example, the change of control values is notified. - The id pointer is the pointer of snd_ctl_elem_id_t + The id pointer is the pointer of struct snd_ctl_elem_id to be notified. You can find some examples in es1938.c or es1968.c for hardware volume interrupts. @@ -4011,45 +3882,44 @@ struct _snd_pcm_runtime { Example of AC97 Interface private_data, return 0); + struct mychip *chip = ac97->private_data; .... // read a register value here from the codec return the_register_value; } - static void snd_mychip_ac97_write(ac97_t *ac97, + static void snd_mychip_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { - mychip_t *chip = snd_magic_cast(mychip_t, - ac97->private_data, return 0); + struct mychip *chip = ac97->private_data; .... // write the given register value to the codec } - static int snd_mychip_ac97(mychip_t *chip) + static int snd_mychip_ac97(struct mychip *chip) { - ac97_bus_t bus, *pbus; - ac97_t ac97; + struct snd_ac97_bus *bus; + struct snd_ac97_template ac97; int err; + static struct snd_ac97_bus_ops 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); } ]]> @@ -4062,18 +3932,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. @@ -4082,13 +3952,14 @@ struct _snd_pcm_runtime { - And then call snd_ac97_mixer() with an ac97_t + And then call snd_ac97_mixer() with an + struct snd_ac97_template record together with the bus pointer created above. private_data, return 0); + struct mychip *chip = ac97->private_data; .... return the_register_value; } @@ -4147,7 +4017,7 @@ struct _snd_pcm_runtime { @@ -4198,7 +4068,7 @@ struct _snd_pcm_runtime { Both snd_ac97_write() and snd_ac97_update() functions are used to set a value to the given register - (AC97_XXX). The different between them is + (AC97_XXX). The difference between them is that snd_ac97_update() doesn't write a value if the given value has been already set, while snd_ac97_write() always rewrites the @@ -4243,8 +4113,8 @@ struct _snd_pcm_runtime { Also, there is a function to change the sample rate (of a certain register such as - AC97_PCM_FRONT_DAC_RATE) when VRA is - supported by the codec: + AC97_PCM_FRONT_DAC_RATE) when VRA or + DRA is supported by the codec: snd_ac97_set_rate(). @@ -4273,7 +4143,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. @@ -4284,8 +4154,8 @@ struct _snd_pcm_runtime { Proc Files The ALSA AC97 interface will create a proc file such as - /proc/asound/card0/ac97#0 and - ac97#0regs. You can refer to these files to + /proc/asound/card0/codec97#0/ac97#0-0 and + ac97#0-0+regs. You can refer to these files to see the current status and registers of the codec. @@ -4294,7 +4164,7 @@ struct _snd_pcm_runtime { Multiple Codecs When there are several codecs on the same card, you need to - call snd_ac97_new() multiple times with + call snd_ac97_mixer() multiple times with ac97.num=1 or greater. The num field specifies the codec number. @@ -4332,18 +4202,6 @@ struct _snd_pcm_runtime { implementation of mpu401 stuff. For example, emu10k1 has its own mpu401 routines. - - - In this document, I won't explain the rawmidi interface API, - which is the basis of MPU401-UART implementation. - - - - For details, please check the source, - core/rawmidi.c, and examples such as - drivers/mpu401/mpu401_uart.c or - usb/usbmidi.c. -
@@ -4355,8 +4213,8 @@ struct _snd_pcm_runtime { @@ -4383,31 +4241,52 @@ struct _snd_pcm_runtime { + The 5th argument is bitflags for additional information. When the i/o port address above is a part of the PCI i/o region, the MPU401 i/o port might have been already allocated - (reserved) by the driver itself. In such a case, pass non-zero - to the 5th argument - (integrated). Otherwise, pass 0 to it, + (reserved) by the driver itself. In such a case, pass a bit flag + MPU401_INFO_INTEGRATED, and the mpu401-uart layer will allocate the i/o ports by itself. + + When the controller supports only the input or output MIDI stream, + pass MPU401_INFO_INPUT or + MPU401_INFO_OUTPUT bitflag, respectively. + Then the rawmidi instance is created as a single stream. + + + + MPU401_INFO_MMIO bitflag is used to change + the access method to MMIO (via readb and writeb) instead of + iob and outb. In this case, you have to pass the iomapped address + to snd_mpu401_uart_new(). + + + + When MPU401_INFO_TX_IRQ is set, the output + stream isn't checked in the default interrupt handler. The driver + needs to call snd_mpu401_uart_interrupt_tx() + by itself to start processing the output stream in irq handler. + + Usually, the port address corresponds to the command port and port + 1 corresponds to the data port. If not, you may change the cport field of - mpu401_t manually - afterward. However, mpu401_t pointer is not + struct snd_mpu401 manually + afterward. However, snd_mpu401 pointer is not returned explicitly by snd_mpu401_uart_new(). You need to cast rmidi->private_data to - mpu401_t explicitly, + snd_mpu401 explicitly, private_data, ); + struct snd_mpu401 *mpu; + mpu = rmidi->private_data; ]]> @@ -4466,6 +4345,354 @@ struct _snd_pcm_runtime { + + + + + RawMIDI Interface + +
+ Overview + + + The raw MIDI interface is used for hardware MIDI ports that can + be accessed as a byte stream. It is not used for synthesizer + chips that do not directly understand MIDI. + + + + ALSA handles file and buffer management. All you have to do is + to write some code to move data between the buffer and the + hardware. + + + + The rawmidi API is defined in + <sound/rawmidi.h>. + +
+ +
+ Constructor + + + To create a rawmidi device, call the + snd_rawmidi_new function: + + +card, "MyMIDI", 0, outs, ins, &rmidi); + if (err < 0) + return err; + rmidi->private_data = chip; + strcpy(rmidi->name, "My MIDI"); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; +]]> + + + + + + The first argument is the card pointer, the second argument is + the ID string. + + + + The third argument is the index of this component. You can + create up to 8 rawmidi devices. + + + + The fourth and fifth arguments are the number of output and + input substreams, respectively, of this device. (A substream is + the equivalent of a MIDI port.) + + + + Set the info_flags field to specify + the capabilities of the device. + Set SNDRV_RAWMIDI_INFO_OUTPUT if there is + at least one output port, + SNDRV_RAWMIDI_INFO_INPUT if there is at + least one input port, + and SNDRV_RAWMIDI_INFO_DUPLEX if the device + can handle output and input at the same time. + + + + After the rawmidi device is created, you need to set the + operators (callbacks) for each substream. There are helper + functions to set the operators for all substream of a device: + + + + + + + + + The operators are usually defined like this: + + + + + + These callbacks are explained in the Callbacks + section. + + + + If there is more than one substream, you should give each one a + unique name: + + +streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { + substream = list_entry(list, struct snd_rawmidi_substream, list); + sprintf(substream->name, "My MIDI Port %d", substream->number + 1); + } + /* same for SNDRV_RAWMIDI_STREAM_INPUT */ +]]> + + + +
+ +
+ Callbacks + + + In all callbacks, the private data that you've set for the + rawmidi device can be accessed as + substream->rmidi->private_data. + + + + + If there is more than one port, your callbacks can determine the + port index from the struct snd_rawmidi_substream data passed to each + callback: + + +number; +]]> + + + + +
+ <function>open</function> callback + + + + + + + + + This is called when a substream is opened. + You can initialize the hardware here, but you should not yet + start transmitting/receiving data. + +
+ +
+ <function>close</function> callback + + + + + + + + + Guess what. + + + + The open and close + callbacks of a rawmidi device are serialized with a mutex, + and can sleep. + +
+ +
+ <function>trigger</function> callback for output + substreams + + + + + + + + + This is called with a nonzero up + parameter when there is some data in the substream buffer that + must be transmitted. + + + + To read data from the buffer, call + snd_rawmidi_transmit_peek. It will + return the number of bytes that have been read; this will be + less than the number of bytes requested when there is no more + data in the buffer. + After the data has been transmitted successfully, call + snd_rawmidi_transmit_ack to remove the + data from the substream buffer: + + + + + + + + + If you know beforehand that the hardware will accept data, you + can use the snd_rawmidi_transmit function + which reads some data and removes it from the buffer at once: + + + + + + + + + If you know beforehand how many bytes you can accept, you can + use a buffer size greater than one with the + snd_rawmidi_transmit* functions. + + + + The trigger callback must not sleep. If + the hardware FIFO is full before the substream buffer has been + emptied, you have to continue transmitting data later, either + in an interrupt handler, or with a timer if the hardware + doesn't have a MIDI transmit interrupt. + + + + The trigger callback is called with a + zero up parameter when the transmission + of data should be aborted. + +
+ +
+ <function>trigger</function> callback for input + substreams + + + + + + + + + This is called with a nonzero up + parameter to enable receiving data, or with a zero + up parameter do disable receiving data. + + + + The trigger callback must not sleep; the + actual reading of data from the device is usually done in an + interrupt handler. + + + + When data reception is enabled, your interrupt handler should + call snd_rawmidi_receive for all received + data: + + + + + + +
+ +
+ <function>drain</function> callback + + + + + + + + + This is only used with output substreams. This function should wait + until all data read from the substream buffer has been transmitted. + This ensures that the device can be closed and the driver unloaded + without losing data. + + + + This callback is optional. If you do not set + drain in the struct snd_rawmidi_ops + structure, ALSA will simply wait for 50 milliseconds + instead. + +
+
+ +
+ + @@ -4498,7 +4725,7 @@ struct _snd_pcm_runtime { @@ -4524,13 +4751,45 @@ struct _snd_pcm_runtime {
- If this function returns successfully with 0, then create a + When the accessing to the hardware requires special method + instead of the standard I/O access, you can create opl3 instance + separately with snd_opl3_new(). + + + + + + + + + + Then set command, + private_data and + private_free for the private + access function, the private data and the destructor. + The l_port and r_port are not necessarily set. Only the + command must be set properly. You can retrieve the data + from opl3->private_data field. + + + + After creating the opl3 instance via snd_opl3_new(), + call snd_opl3_init() to initialize the chip to the + proper state. Note that snd_opl3_create() always + calls it internally. + + + + If the opl3 instance is created successfully, then create a hwdep device for this opl3. @@ -4567,7 +4826,7 @@ struct _snd_pcm_runtime { @@ -4578,16 +4837,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; ]]> @@ -4599,11 +4857,10 @@ struct _snd_pcm_runtime { private_data, return); - snd_magic_kfree(p); + struct mydata *p = hw->private_data; + kfree(p); } ]]> @@ -4735,7 +4992,7 @@ struct _snd_pcm_runtime { where size is the byte size to be pre-allocated and the max is the maximal size to be changed via prealloc proc file. - The allocator will try to get as the large area as possible + The allocator will try to get as large area as possible within the given size. @@ -4826,9 +5083,9 @@ struct _snd_pcm_runtime { @@ -4909,7 +5166,7 @@ struct _snd_pcm_runtime { @@ -4957,7 +5214,7 @@ struct _snd_pcm_runtime { If your hardware supports the page table like emu10k1 or the buffer descriptors like via82xx, you can use the scatter-gather (SG) DMA. ALSA provides an interface for handling SG-buffers. - The API is provided in <sound/pcm_sgbuf.h>. + The API is provided in <sound/pcm.h>. @@ -4969,14 +5226,14 @@ struct _snd_pcm_runtime { You need to pass the snd_dma_pci_data(pci), where pci is the struct pci_dev pointer of the chip as well. - The snd_sg_buf_t instance is created as + The struct snd_sg_buf instance is created as substream->dma_private. You can cast the pointer like: dma_private; + struct snd_sg_buf *sgbuf = (struct snd_sg_buf *)substream->dma_private; ]]> @@ -5031,7 +5288,7 @@ struct _snd_pcm_runtime { #include /* get the physical page pointer on the given offset */ - static struct page *mychip_page(snd_pcm_substream_t *substream, + static struct page *mychip_page(struct snd_pcm_substream *substream, unsigned long offset) { void *pageptr = substream->runtime->dma_area + offset; @@ -5066,7 +5323,7 @@ struct _snd_pcm_runtime { @@ -5096,7 +5353,7 @@ struct _snd_pcm_runtime { @@ -5110,8 +5367,8 @@ struct _snd_pcm_runtime { @@ -5126,11 +5383,10 @@ struct _snd_pcm_runtime { private_data, return); + struct my_chip *chip = entry->private_data; snd_iprintf(buffer, "This is my chip!\n"); snd_iprintf(buffer, "Port = %ld\n", chip->port); @@ -5158,29 +5414,12 @@ struct _snd_pcm_runtime { c.text.write_size = 256; entry->c.text.write = my_proc_write; ]]> - - The buffer size for read is set to 1024 implicitly by - snd_info_set_text_ops(). It should suffice - in most cases (the size will be aligned to - PAGE_SIZE anyway), but if you need to handle - very large text files, you can set it explicitly, too. - - - -c.text.read_size = 65536; -]]> - - - - For the write callback, you can use snd_info_get_line() to get a text line, and @@ -5214,22 +5453,23 @@ struct _snd_pcm_runtime { The callback is much more complicated than the text-file version. You need to use a low-level i/o functions such as copy_from/to_user() to transfer the - data. Also, you have to keep tracking the file position, too. + data. f_pos + size > local_max_size) - size = local_max_size - file->f_pos; - if (copy_to_user(buf, local_data + file->f_pos, size)) + if (pos + size > local_max_size) + size = local_max_size - pos; + if (copy_to_user(buf, local_data + pos, size)) return -EFAULT; - file->f_pos += size; return size; } ]]> @@ -5246,77 +5486,91 @@ struct _snd_pcm_runtime { Power Management - If the chip is supposed to work with with suspend/resume + If the chip is supposed to work with suspend/resume functions, you need to add the power-management codes to the driver. The additional codes for the power-management should be ifdef'ed with CONFIG_PM. + + If the driver supports the suspend/resume + fully, that is, the device can be + properly resumed to the status at the suspend is called, + you can set SNDRV_PCM_INFO_RESUME flag + to pcm info field. Usually, this is possible when the + registers of ths chip can be safely saved and restored to the + RAM. If this is set, the trigger callback is called with + SNDRV_PCM_TRIGGER_RESUME after resume + callback is finished. + + + + Even if the driver doesn't support PM fully but only the + partial suspend/resume is possible, it's still worthy to + implement suspend/resume callbacks. In such a case, applications + would reset the status by calling + snd_pcm_prepare() and restart the stream + appropriately. Hence, you can define suspend/resume callbacks + below but don't set SNDRV_PCM_INFO_RESUME + info flag to the PCM. + + + + Note that the trigger with SUSPEND can be always called when + snd_pcm_suspend_all is called, + regardless of SNDRV_PCM_INFO_RESUME flag. + The RESUME flag affects only the behavior + of snd_pcm_resume(). + (Thus, in theory, + SNDRV_PCM_TRIGGER_RESUME isn't needed + to be handled in the trigger callback when no + SNDRV_PCM_INFO_RESUME flag is set. But, + it's better to keep it for compatibility reason.) + - Basic jobs of suspend/resume are done in - suspend and - resume callbacks of - pci_driver struct. Unfortunately, the - API of these callbacks was changed at the middle time of Linux - 2.4.x, if you want to keep the support for older kernels, you - have to write two different callbacks. The example below is the - skeleton callbacks which just call the real suspend and resume - functions. + In the earlier version of ALSA drivers, a common + power-management layer was provided, but it has been removed. + The driver needs to define the suspend/resume hooks according to + the bus the device is assigned. In the case of PCI driver, the + callbacks look like below: - - For keeping the readability of 2.6 source code, it's recommended to - separate the above ifdef condition as the patch file in alsa-driver - directory. - See alsa-driver/pci/ali5451.c for example. - - The scheme of the real suspend job is as following. - Check whether the power-state is already D3hot. If yes, skip the job. + Retrieve the card and the chip data. + Call snd_power_change_state() with + SNDRV_CTL_POWER_D3hot to change the + power status. Call snd_pcm_suspend_all() to suspend the running PCM streams. + If AC97 codecs are used, call + snd_ac97_suspend() for each codec. Save the register values if necessary. Stop the hardware if necessary. - Set the power-state as D3hot by calling snd_power_change_state(). + Disable the PCI device by calling + pci_disable_device(). Then, call + pci_save_state() at last. @@ -5326,20 +5580,25 @@ struct _snd_pcm_runtime { card; - // (1) - if (card->power_state == SNDRV_CTL_POWER_D3hot) - return; - // (2) + /* (1) */ + struct snd_card *card = pci_get_drvdata(pci); + struct mychip *chip = card->private_data; + /* (2) */ + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + /* (3) */ snd_pcm_suspend_all(chip->pcm); - // (3) + /* (4) */ + snd_ac97_suspend(chip->ac97); + /* (5) */ snd_mychip_save_registers(chip); - // (4) + /* (6) */ snd_mychip_stop_hardware(chip); - // (5) - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + /* (7) */ + pci_disable_device(pci); + pci_save_state(pci); + return 0; } ]]> @@ -5350,17 +5609,17 @@ struct _snd_pcm_runtime { The scheme of the real resume job is as following. - Check whether the power-state is already D0. - If yes, skip the job. - Enable the pci device again by calling - pci_enable_device(). + Retrieve the card and the chip data. + Set up PCI. First, call pci_restore_state(). + Then enable the pci device again by calling pci_enable_device(). + Call pci_set_master() if necessary, too. Re-initialize the chip. Restore the saved registers if necessary. Resume the mixer, e.g. calling snd_ac97_resume(). Restart the hardware (if any). - Set the power-state as D0 by calling - snd_power_change_state(). + Call snd_power_change_state() with + SNDRV_CTL_POWER_D0 to notify the processes. @@ -5370,24 +5629,26 @@ struct _snd_pcm_runtime { card; - // (1) - if (card->power_state == SNDRV_CTL_POWER_D0) - return; - // (2) - pci_enable_device(chip->pci); - // (3) + /* (1) */ + struct snd_card *card = pci_get_drvdata(pci); + struct mychip *chip = card->private_data; + /* (2) */ + pci_restore_state(pci); + pci_enable_device(pci); + pci_set_master(pci); + /* (3) */ snd_mychip_reinit_chip(chip); - // (4) + /* (4) */ snd_mychip_restore_registers(chip); - // (5) + /* (5) */ snd_ac97_resume(chip->ac97); - // (6) + /* (6) */ snd_mychip_restart_chip(chip); - // (7) + /* (7) */ snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; } ]]> @@ -5395,41 +5656,48 @@ struct _snd_pcm_runtime { - In addition to the callbacks above, you should define a callback - for the changes via the ALSA control interface. It's defined - like below: + As shown in the above, it's better to save registers after + suspending the PCM operations via + snd_pcm_suspend_all() or + snd_pcm_suspend(). It means that the PCM + streams are already stoppped when the register snapshot is + taken. But, remind that you don't have to restart the PCM + stream in the resume callback. It'll be restarted via + trigger call with SNDRV_PCM_TRIGGER_RESUME + when necessary. + + + + OK, we have all callbacks now. Let's set them up. In the + initialization of the card, make sure that you can get the chip + data from the card instance, typically via + private_data field, in case you + created the chip data individually. power_state_private_data, return -ENXIO); - switch (power_state) { - case SNDRV_CTL_POWER_D0: - case SNDRV_CTL_POWER_D1: - case SNDRV_CTL_POWER_D2: - mychip_resume(chip); - break; - case SNDRV_CTL_POWER_D3hot: - case SNDRV_CTL_POWER_D3cold: - mychip_suspend(chip); - break; - default: - return -EINVAL; - } - return 0; + .... + struct snd_card *card; + struct mychip *chip; + .... + card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL); + .... + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + .... + card->private_data = chip; + .... } ]]> - - - OK, we have all callbacks now. Let's set up them now. In the - initialization of the card, add the following: + When you created the chip data with + snd_card_new(), it's anyway accessible + via private_data field. @@ -5438,41 +5706,43 @@ struct _snd_pcm_runtime { const struct pci_device_id *pci_id) { .... - snd_card_t *card; + struct snd_card *card; + struct mychip *chip; .... - #ifdef CONFIG_PM - card->set_power_state = snd_mychip_set_power_state; - card->power_state_private_data = chip; - #endif + card = snd_card_new(index[dev], id[dev], THIS_MODULE, + sizeof(struct mychip)); + .... + chip = card->private_data; .... } ]]> + - If you need a space for saving the registers, you'll need to - allocate the buffer for it here, too, since you cannot call - kmalloc() with - GFP_KERNEL flag or - vmalloc() in the suspend callback. + If you need a space for saving the registers, allocate the + buffer for it here, too, since it would be fatal + if you cannot allocate a memory in the suspend phase. The allocated buffer should be released in the corresponding destructor. - And next, set suspend/resume callbacks to the pci_driver, + And next, set suspend/resume callbacks to the pci_driver. @@ -5521,20 +5791,9 @@ struct _snd_pcm_runtime { The module parameters must be declared with the standard - MODULE_PARM() 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_param()(), + module_param_array()() and + MODULE_PARM_DESC() macros. @@ -5545,15 +5804,12 @@ struct _snd_pcm_runtime { @@ -5569,47 +5825,13 @@ struct _snd_pcm_runtime { - - For building the driver into kernel, you should define the - setup() function in addition, too. - ALSA provides get_id() function to retrieve - a string argument from the kernel boot parameters. - - - -= SNDRV_CARDS) - return 0; - (void)(get_option(&str,&enable[nr_dev]) == 2 && - get_option(&str,&index[nr_dev]) == 2 && - get_id(&str,&id[nr_dev]) == 2); - nr_dev++; - return 1; - } - - __setup("snd-mychip=", alsa_card_mychip_setup); - - #endif /* ifndef MODULE */ -]]> - - - @@ -5631,10 +5853,14 @@ struct _snd_pcm_runtime { Suppose that you'll create a new PCI driver for the card xyz. The card module name would be snd-xyz. The new driver is usually put into alsa-driver - tree. Then the driver is evaluated, audited and tested + tree, alsa-driver/pci directory in + the case of PCI cards. + Then the driver is evaluated, audited and tested by developers and users. After a certain time, the driver - will go to alsa-kernel tree and eventually integrated into - Linux 2.6 tree. + will go to alsa-kernel tree (to the corresponding directory, + such as alsa-kernel/pci) and eventually + integrated into Linux 2.6 tree (the directory would be + linux/sound/pci). @@ -5661,7 +5887,7 @@ struct _snd_pcm_runtime {
@@ -5678,12 +5904,15 @@ struct _snd_pcm_runtime { @@ -5730,7 +5959,8 @@ struct _snd_pcm_runtime { - Add a new directory (xyz) to extra-subdir-y list in alsa-driver/pci/Makefile + Add a new directory (xyz) in + alsa-driver/pci/Makefile like below @@ -5744,7 +5974,7 @@ struct _snd_pcm_runtime { - Under the directory xyz, create a Makefile + Under the directory xyz, create a Makefile Sample Makefile for a driver xyz @@ -5754,14 +5984,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 ]]> @@ -5856,32 +6086,23 @@ struct _snd_pcm_runtime { The first argument is the expression to evaluate, and the second argument is the action if it fails. When CONFIG_SND_DEBUG, is set, it will show an - error message such as BUG? (xxx) (called from - yyy). When no debug flag is set, this is - ignored. + error message such as BUG? (xxx) + together with stack trace. -
- -
- <function>snd_runtime_check()</function> - This macro is quite similar with - snd_assert(). Unlike - snd_assert(), the expression is always - evaluated regardless of - CONFIG_SND_DEBUG. When - CONFIG_SND_DEBUG is set, the macro will - show a message like ERROR (xx) (called from - yyy). + When no debug flag is set, this macro is ignored.
<function>snd_BUG()</function> - It calls snd_assert(0,) -- that is, just - prints the error message at the point. It's useful to show that - a fatal error happens there. + It shows BUG? message and + stack trace as well as snd_assert at the point. + It's useful to show that a fatal error happens there. + + + When no debug flag is set, this macro is ignored.