X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=Documentation%2Fsound%2Falsa%2FDocBook%2Fwriting-an-alsa-driver.tmpl;h=1faf76383babd26875c9e5d303685a29c6096531;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=e789475304b6e03b8b8e5c60c72fd8f445f65a5b;hpb=cee37fe97739d85991964371c1f3a745c00dd236;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 e78947530..1faf76383 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 @@ - March 6, 2005 - 0.3.4 + 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 @@ -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. @@ -403,9 +403,8 @@ 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; + struct mychip { + struct snd_card *card; // rest of implementation will be in the section // "PCI Resource Managements" }; @@ -413,7 +412,7 @@ /* chip-specific destructor * (see "PCI Resource Managements") */ - static int snd_mychip_free(mychip_t *chip) + static int snd_mychip_free(struct mychip *chip) { .... // will be implemented later... } @@ -421,22 +420,21 @@ /* component-destructor * (see "Management of Cards and Components") */ - static int snd_mychip_dev_free(snd_device_t *device) + static int snd_mychip_dev_free(struct snd_device *device) { - mychip_t *chip = device->device_data; - 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, + 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,7 +445,7 @@ .... /* allocate a chip-specific data with zero filled */ - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -474,8 +472,8 @@ 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) */ @@ -582,7 +580,7 @@ @@ -605,7 +603,7 @@ @@ -830,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. @@ -891,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: @@ -918,12 +913,12 @@ - whether mychip_t is the type of the chip record. + whether struct mychip is the type of the chip record. @@ -932,7 +927,7 @@ private_data; + struct mychip *chip = (struct mychip *)card->private_data; ]]> @@ -949,16 +944,16 @@ After allocating a card instance via snd_card_new() (with NULL on the 4th arg), call - kcalloc(). + kzalloc(). @@ -971,8 +966,8 @@ @@ -1000,7 +995,7 @@ device_data; - return snd_mychip_free(chip); + return snd_mychip_free(device->device_data); } ]]> @@ -1087,15 +1081,15 @@ PCI Resource Managements Example port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_mychip_interrupt, - SA_INTERRUPT|SA_SHIRQ, "My Chip", - (void *)chip)) { + SA_INTERRUPT|SA_SHIRQ, "My Chip", chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); snd_mychip_free(chip); return -EBUSY; @@ -1179,7 +1172,7 @@ } /* PCI IDs */ - static struct pci_device_id snd_mychip_ids[] = { + static struct pci_device_id snd_mychip_ids[] __devinitdata = { { PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, .... @@ -1198,7 +1191,7 @@ /* initialization of the module */ static int __init alsa_card_mychip_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } /* clean up the module */ @@ -1223,7 +1216,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. @@ -1232,7 +1225,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. @@ -1243,8 +1236,8 @@ 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: kcalloc() automatically, so you + kzalloc() automatically, so you don't have to take care of resetting them. @@ -1330,8 +1323,7 @@ irq, snd_mychip_interrupt, - SA_INTERRUPT|SA_SHIRQ, "My Chip", - (void *)chip)) { + SA_INTERRUPT|SA_SHIRQ, "My Chip", chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); snd_mychip_free(chip); return -EBUSY; @@ -1372,7 +1364,7 @@ static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - mychip_t *chip = dev_id; + struct mychip *chip = dev_id; .... return IRQ_HANDLED; } @@ -1433,25 +1425,10 @@ res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + release_and_free_resource(chip->res_port); ]]> - - 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, - 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. @@ -1502,7 +1479,7 @@ iobase_virt) @@ -1552,7 +1529,7 @@ Registration of Device Struct At some point, typically after calling snd_device_new(), - you need to register the struct device of the chip + 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: @@ -1588,7 +1565,7 @@ 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 @@ -1803,19 +1780,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 @@ -1823,33 +1800,33 @@ } /* 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... @@ -1857,14 +1834,14 @@ 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) { @@ -1881,9 +1858,9 @@ /* 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 */ @@ -1892,7 +1869,7 @@ } /* 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, @@ -1904,7 +1881,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, @@ -1920,9 +1897,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, @@ -1959,9 +1936,9 @@ card, "My Chip", 0, 1, 1, @@ -2004,13 +1981,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; ]]> @@ -2039,7 +2016,7 @@ PCM Instance with a Destructor my_private_pcm_data); // 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 */ chip->my_private_pcm_data = kmalloc(...); @@ -2164,7 +2141,7 @@ @@ -2268,7 +2244,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 @@ -2283,7 +2259,7 @@ struct _snd_pcm_runtime { runtime; + struct snd_pcm_runtime *runtime = substream->runtime; ... runtime->hw = snd_mychip_playback_hw; /* common definition */ if (chip->model == VERY_OLD_ONE) @@ -2298,7 +2274,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. @@ -2528,7 +2509,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. @@ -2536,7 +2517,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.
@@ -2558,9 +2539,9 @@ struct _snd_pcm_runtime { runtime->private_data = data; @@ -2602,7 +2583,7 @@ 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. @@ -2610,7 +2591,7 @@ struct _snd_pcm_runtime { @@ -2632,7 +2613,7 @@ struct _snd_pcm_runtime { @@ -2647,10 +2628,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; @@ -2683,7 +2664,7 @@ struct _snd_pcm_runtime { @@ -2698,7 +2679,7 @@ struct _snd_pcm_runtime { runtime->private_data); @@ -2725,8 +2706,8 @@ struct _snd_pcm_runtime { @@ -2801,7 +2782,7 @@ struct _snd_pcm_runtime { @@ -2836,7 +2817,7 @@ struct _snd_pcm_runtime { @@ -2855,7 +2836,7 @@ struct _snd_pcm_runtime { Note that this callback became non-atomic since the recent version. - You can use schedule-related fucntions safely in this callback now. + You can use schedule-related functions safely in this callback now. @@ -2885,7 +2866,7 @@ struct _snd_pcm_runtime { @@ -2927,8 +2908,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 @@ -2937,6 +2918,8 @@ 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. @@ -2955,7 +2938,7 @@ struct _snd_pcm_runtime { @@ -3083,7 +3066,7 @@ struct _snd_pcm_runtime { static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - mychip_t *chip = dev_id; + struct mychip *chip = dev_id; spin_lock(&chip->lock); .... if (pcm_irq_invoked(chip)) { @@ -3127,7 +3110,7 @@ struct _snd_pcm_runtime { static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - mychip_t *chip = dev_id; + struct mychip *chip = dev_id; spin_lock(&chip->lock); .... if (pcm_irq_invoked(chip)) { @@ -3237,13 +3220,13 @@ struct _snd_pcm_runtime { 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) { @@ -3314,12 +3298,13 @@ struct _snd_pcm_runtime { Example of Hardware Constraints for Channels bits[0] == SNDRV_PCM_FMTBIT_S16_LE) { @@ -3392,18 +3377,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. @@ -3457,7 +3449,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 @@ -3608,7 +3600,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: @@ -3616,8 +3608,8 @@ struct _snd_pcm_runtime { Example of info callback type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; @@ -3651,8 +3643,8 @@ struct _snd_pcm_runtime { Example of get callback value.integer.value[0] = get_some_value(chip); return 0; } @@ -3702,8 +3694,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 @@ -3727,8 +3718,8 @@ struct _snd_pcm_runtime { private_value & 0xff; int shift = (kcontrol->private_value >> 16) & 0xff; @@ -3764,10 +3755,10 @@ struct _snd_pcm_runtime { Example of put callback current_value != ucontrol->value.integer.value[0]) { @@ -3824,7 +3815,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. @@ -3832,7 +3823,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 @@ -3859,7 +3850,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. @@ -3892,35 +3883,35 @@ struct _snd_pcm_runtime { Example of AC97 Interface private_data; + 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 = ac97->private_data; + 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; - ac97_template_t ac97; + struct snd_ac97_bus *bus; + struct snd_ac97_template ac97; int err; - static ac97_bus_ops_t ops = { + static struct snd_ac97_bus_ops ops = { .write = snd_mychip_ac97_write, .read = snd_mychip_ac97_read, }; @@ -3947,8 +3938,8 @@ struct _snd_pcm_runtime { - And then call snd_ac97_mixer() with an ac97_template_t + And then call snd_ac97_mixer() with an + struct snd_ac97_template record together with the bus pointer created above. private_data; + struct mychip *chip = ac97->private_data; .... return the_register_value; } @@ -4026,7 +4018,7 @@ struct _snd_pcm_runtime { @@ -4173,7 +4165,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. @@ -4222,7 +4214,7 @@ struct _snd_pcm_runtime { @@ -4263,17 +4255,17 @@ struct _snd_pcm_runtime { 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; ]]> @@ -4369,7 +4361,7 @@ struct _snd_pcm_runtime { card, "MyMIDI", 0, outs, ins, &rmidi); if (err < 0) return err; @@ -4429,7 +4421,7 @@ struct _snd_pcm_runtime { streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { - substream = list_entry(list, snd_rawmidi_substream_t, list); + 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 */ @@ -4473,12 +4465,12 @@ struct _snd_pcm_runtime { If there is more than one port, your callbacks can determine the - port index from the snd_rawmidi_substream_t data passed to each + port index from the struct snd_rawmidi_substream data passed to each callback: number; ]]> @@ -4491,7 +4483,7 @@ struct _snd_pcm_runtime { @@ -4509,7 +4501,7 @@ struct _snd_pcm_runtime { @@ -4532,7 +4524,7 @@ struct _snd_pcm_runtime { @@ -4557,7 +4549,7 @@ struct _snd_pcm_runtime { @@ -4613,7 +4605,7 @@ struct _snd_pcm_runtime { @@ -4657,7 +4649,7 @@ struct _snd_pcm_runtime { @@ -4671,7 +4663,7 @@ struct _snd_pcm_runtime { This callback is optional. If you do not set - drain in the snd_rawmidi_ops_t + drain in the struct snd_rawmidi_ops structure, ALSA will simply wait for 50 milliseconds instead. @@ -4713,7 +4705,7 @@ struct _snd_pcm_runtime { @@ -4746,7 +4738,7 @@ struct _snd_pcm_runtime { @@ -4777,7 +4769,7 @@ struct _snd_pcm_runtime { @@ -4814,7 +4806,7 @@ struct _snd_pcm_runtime { @@ -4833,7 +4825,7 @@ struct _snd_pcm_runtime { private_data = p; hw->private_free = mydata_free; ]]> @@ -4845,9 +4837,9 @@ struct _snd_pcm_runtime { private_data; + struct mydata *p = hw->private_data; kfree(p); } ]]> @@ -5071,9 +5063,9 @@ struct _snd_pcm_runtime { @@ -5154,7 +5146,7 @@ struct _snd_pcm_runtime { @@ -5214,14 +5206,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; ]]> @@ -5276,7 +5268,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; @@ -5311,7 +5303,7 @@ struct _snd_pcm_runtime { @@ -5355,8 +5347,8 @@ struct _snd_pcm_runtime { @@ -5371,10 +5363,10 @@ struct _snd_pcm_runtime { private_data; + struct my_chip *chip = entry->private_data; snd_iprintf(buffer, "This is my chip!\n"); snd_iprintf(buffer, "Port = %ld\n", chip->port); @@ -5463,7 +5455,7 @@ struct _snd_pcm_runtime { 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.) + - ALSA provides the common power-management layer. Each card driver - needs to have only low-level suspend and resume callbacks. + 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: - Retrieve the chip data from pm_private_data field. + 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_resume() for each codec. Save the register values if necessary. Stop the hardware if necessary. - Disable the PCI device by calling pci_disable_device(). + Disable the PCI device by calling + pci_disable_device(). Then, call + pci_save_state() at last. @@ -5540,18 +5577,24 @@ struct _snd_pcm_runtime { pm_private_data; + struct snd_card *card = pci_get_drvdata(pci); + struct mychip *chip = card->private_data; /* (2) */ - snd_pcm_suspend_all(chip->pcm); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); /* (3) */ - snd_mychip_save_registers(chip); + snd_pcm_suspend_all(chip->pcm); /* (4) */ - snd_mychip_stop_hardware(chip); + snd_ac97_suspend(chip->ac97); /* (5) */ - pci_disable_device(chip->pci); + snd_mychip_save_registers(chip); + /* (6) */ + snd_mychip_stop_hardware(chip); + /* (7) */ + pci_disable_device(pci); + pci_save_state(pci); return 0; } ]]> @@ -5563,14 +5606,17 @@ struct _snd_pcm_runtime { The scheme of the real resume job is as following. - Retrieve the chip data from pm_private_data field. - 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). + Call snd_power_change_state() with + SNDRV_CTL_POWER_D0 to notify the processes. @@ -5580,12 +5626,15 @@ struct _snd_pcm_runtime { pm_private_data; + struct snd_card *card = pci_get_drvdata(pci); + struct mychip *chip = card->private_data; /* (2) */ - pci_enable_device(chip->pci); + pci_restore_state(pci); + pci_enable_device(pci); + pci_set_master(pci); /* (3) */ snd_mychip_reinit_chip(chip); /* (4) */ @@ -5594,6 +5643,8 @@ struct _snd_pcm_runtime { snd_ac97_resume(chip->ac97); /* (6) */ snd_mychip_restart_chip(chip); + /* (7) */ + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } ]]> @@ -5602,8 +5653,23 @@ struct _snd_pcm_runtime { - OK, we have all callbacks now. Let's set up them now. In the - initialization of the card, add the following: + 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. @@ -5612,33 +5678,56 @@ struct _snd_pcm_runtime { const struct pci_device_id *pci_id) { .... - snd_card_t *card; - mychip_t *chip; + struct snd_card *card; + struct mychip *chip; + .... + card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL); .... - snd_card_set_pm_callback(card, snd_my_suspend, snd_my_resume, chip); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + .... + card->private_data = chip; + .... + } +]]> + + + + When you created the chip data with + snd_card_new(), it's anyway accessible + via private_data field. + + + +private_data; .... } ]]> - Here you don't have to put ifdef CONFIG_PM around, since it's already - checked in the header and expanded to empty if not needed. - If you need a space for saving the registers, you'll need to - allocate the buffer for it here, too, since it would be fatal + 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, - This can be done by passing a macro SND_PCI_PM_CALLBACKS - in the pci_driver struct. This macro is expanded to the correct - (global) callbacks if CONFIG_PM is set. + And next, set suspend/resume callbacks to the pci_driver. @@ -5648,7 +5737,10 @@ struct _snd_pcm_runtime { .id_table = snd_my_ids, .probe = snd_my_probe, .remove = __devexit_p(snd_my_remove), - SND_PCI_PM_CALLBACKS + #ifdef CONFIG_PM + .suspend = snd_my_suspend, + .resume = snd_my_resume, + #endif }; ]]> @@ -5991,32 +6083,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.