ALSA: trident: Allocate resources with device-managed APIs

This patch converts the resource management in PCI trident driver with
devres as a clean up.  Each manual resource management is converted
with the corresponding devres helper, the page allocations are done
with the devres helper, and the card object release is managed now via
card->private_free instead of a lowlevel snd_device.

This should give no user-visible functional changes.

Link: https://lore.kernel.org/r/20210715075941.23332-49-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2021-07-15 09:59:10 +02:00
Родитель b1002b2d41
Коммит 5adfd8c266
4 изменённых файлов: 44 добавлений и 100 удалений

Просмотреть файл

@ -62,21 +62,18 @@ static int snd_trident_probe(struct pci_dev *pci,
return -ENOENT; return -ENOENT;
} }
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0, &card); sizeof(*trident), &card);
if (err < 0) if (err < 0)
return err; return err;
trident = card->private_data;
err = snd_trident_create(card, pci, err = snd_trident_create(card, pci,
pcm_channels[dev], pcm_channels[dev],
((pci->vendor << 16) | pci->device) == TRIDENT_DEVICE_ID_SI7018 ? 1 : 2, ((pci->vendor << 16) | pci->device) == TRIDENT_DEVICE_ID_SI7018 ? 1 : 2,
wavetable_size[dev], wavetable_size[dev]);
&trident); if (err < 0)
if (err < 0) {
snd_card_free(card);
return err; return err;
}
card->private_data = trident;
switch (trident->device) { switch (trident->device) {
case TRIDENT_DEVICE_ID_DX: case TRIDENT_DEVICE_ID_DX:
@ -102,26 +99,20 @@ static int snd_trident_probe(struct pci_dev *pci,
card->shortname, trident->port, trident->irq); card->shortname, trident->port, trident->irq);
err = snd_trident_pcm(trident, pcm_dev++); err = snd_trident_pcm(trident, pcm_dev++);
if (err < 0) { if (err < 0)
snd_card_free(card);
return err; return err;
}
switch (trident->device) { switch (trident->device) {
case TRIDENT_DEVICE_ID_DX: case TRIDENT_DEVICE_ID_DX:
case TRIDENT_DEVICE_ID_NX: case TRIDENT_DEVICE_ID_NX:
err = snd_trident_foldback_pcm(trident, pcm_dev++); err = snd_trident_foldback_pcm(trident, pcm_dev++);
if (err < 0) { if (err < 0)
snd_card_free(card);
return err; return err;
}
break; break;
} }
if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) { if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {
err = snd_trident_spdif_pcm(trident, pcm_dev++); err = snd_trident_spdif_pcm(trident, pcm_dev++);
if (err < 0) { if (err < 0)
snd_card_free(card);
return err; return err;
}
} }
if (trident->device != TRIDENT_DEVICE_ID_SI7018) { if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE,
@ -129,34 +120,24 @@ static int snd_trident_probe(struct pci_dev *pci,
MPU401_INFO_INTEGRATED | MPU401_INFO_INTEGRATED |
MPU401_INFO_IRQ_HOOK, MPU401_INFO_IRQ_HOOK,
-1, &trident->rmidi); -1, &trident->rmidi);
if (err < 0) { if (err < 0)
snd_card_free(card);
return err; return err;
}
} }
snd_trident_create_gameport(trident); snd_trident_create_gameport(trident);
err = snd_card_register(card); err = snd_card_register(card);
if (err < 0) { if (err < 0)
snd_card_free(card);
return err; return err;
}
pci_set_drvdata(pci, card); pci_set_drvdata(pci, card);
dev++; dev++;
return 0; return 0;
} }
static void snd_trident_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
}
static struct pci_driver trident_driver = { static struct pci_driver trident_driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.id_table = snd_trident_ids, .id_table = snd_trident_ids,
.probe = snd_trident_probe, .probe = snd_trident_probe,
.remove = snd_trident_remove,
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.driver = { .driver = {
.pm = &snd_trident_pm, .pm = &snd_trident_pm,

Просмотреть файл

@ -251,9 +251,9 @@ struct snd_trident_memblk_arg {
struct snd_trident_tlb { struct snd_trident_tlb {
__le32 *entries; /* 16k-aligned TLB table */ __le32 *entries; /* 16k-aligned TLB table */
dma_addr_t entries_dmaaddr; /* 16k-aligned PCI address to TLB table */ dma_addr_t entries_dmaaddr; /* 16k-aligned PCI address to TLB table */
struct snd_dma_buffer buffer; struct snd_dma_buffer *buffer;
struct snd_util_memhdr * memhdr; /* page allocation list */ struct snd_util_memhdr * memhdr; /* page allocation list */
struct snd_dma_buffer silent_page; struct snd_dma_buffer *silent_page;
}; };
struct snd_trident_voice { struct snd_trident_voice {
@ -400,8 +400,7 @@ int snd_trident_create(struct snd_card *card,
struct pci_dev *pci, struct pci_dev *pci,
int pcm_streams, int pcm_streams,
int pcm_spdif_device, int pcm_spdif_device,
int max_wavetable_size, int max_wavetable_size);
struct snd_trident ** rtrident);
int snd_trident_create_gameport(struct snd_trident *trident); int snd_trident_create_gameport(struct snd_trident *trident);
int snd_trident_pcm(struct snd_trident *trident, int device); int snd_trident_pcm(struct snd_trident *trident, int device);

Просмотреть файл

@ -42,7 +42,7 @@ static int snd_trident_sis_reset(struct snd_trident *trident);
static void snd_trident_clear_voices(struct snd_trident * trident, static void snd_trident_clear_voices(struct snd_trident * trident,
unsigned short v_min, unsigned short v_max); unsigned short v_min, unsigned short v_max);
static int snd_trident_free(struct snd_trident *trident); static void snd_trident_free(struct snd_card *card);
/* /*
* common I/O routines * common I/O routines
@ -3299,12 +3299,6 @@ static void snd_trident_proc_init(struct snd_trident *trident)
snd_card_ro_proc_new(trident->card, s, trident, snd_trident_proc_read); snd_card_ro_proc_new(trident->card, s, trident, snd_trident_proc_read);
} }
static int snd_trident_dev_free(struct snd_device *device)
{
struct snd_trident *trident = device->device_data;
return snd_trident_free(trident);
}
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
snd_trident_tlb_alloc snd_trident_tlb_alloc
@ -3324,23 +3318,27 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident)
/* TLB array must be aligned to 16kB !!! so we allocate /* TLB array must be aligned to 16kB !!! so we allocate
32kB region and correct offset when necessary */ 32kB region and correct offset when necessary */
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &trident->pci->dev, trident->tlb.buffer =
2 * SNDRV_TRIDENT_MAX_PAGES * 4, &trident->tlb.buffer) < 0) { snd_devm_alloc_pages(&trident->pci->dev, SNDRV_DMA_TYPE_DEV,
2 * SNDRV_TRIDENT_MAX_PAGES * 4);
if (!trident->tlb.buffer) {
dev_err(trident->card->dev, "unable to allocate TLB buffer\n"); dev_err(trident->card->dev, "unable to allocate TLB buffer\n");
return -ENOMEM; return -ENOMEM;
} }
trident->tlb.entries = (__le32 *)ALIGN((unsigned long)trident->tlb.buffer.area, SNDRV_TRIDENT_MAX_PAGES * 4); trident->tlb.entries = (__le32 *)ALIGN((unsigned long)trident->tlb.buffer->area, SNDRV_TRIDENT_MAX_PAGES * 4);
trident->tlb.entries_dmaaddr = ALIGN(trident->tlb.buffer.addr, SNDRV_TRIDENT_MAX_PAGES * 4); trident->tlb.entries_dmaaddr = ALIGN(trident->tlb.buffer->addr, SNDRV_TRIDENT_MAX_PAGES * 4);
/* allocate and setup silent page and initialise TLB entries */ /* allocate and setup silent page and initialise TLB entries */
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &trident->pci->dev, trident->tlb.silent_page =
SNDRV_TRIDENT_PAGE_SIZE, &trident->tlb.silent_page) < 0) { snd_devm_alloc_pages(&trident->pci->dev, SNDRV_DMA_TYPE_DEV,
SNDRV_TRIDENT_PAGE_SIZE);
if (!trident->tlb.silent_page) {
dev_err(trident->card->dev, "unable to allocate silent page\n"); dev_err(trident->card->dev, "unable to allocate silent page\n");
return -ENOMEM; return -ENOMEM;
} }
memset(trident->tlb.silent_page.area, 0, SNDRV_TRIDENT_PAGE_SIZE); memset(trident->tlb.silent_page->area, 0, SNDRV_TRIDENT_PAGE_SIZE);
for (i = 0; i < SNDRV_TRIDENT_MAX_PAGES; i++) for (i = 0; i < SNDRV_TRIDENT_MAX_PAGES; i++)
trident->tlb.entries[i] = cpu_to_le32(trident->tlb.silent_page.addr & ~(SNDRV_TRIDENT_PAGE_SIZE-1)); trident->tlb.entries[i] = cpu_to_le32(trident->tlb.silent_page->addr & ~(SNDRV_TRIDENT_PAGE_SIZE-1));
/* use emu memory block manager code to manage tlb page allocation */ /* use emu memory block manager code to manage tlb page allocation */
trident->tlb.memhdr = snd_util_memhdr_new(SNDRV_TRIDENT_PAGE_SIZE * SNDRV_TRIDENT_MAX_PAGES); trident->tlb.memhdr = snd_util_memhdr_new(SNDRV_TRIDENT_PAGE_SIZE * SNDRV_TRIDENT_MAX_PAGES);
@ -3497,36 +3495,24 @@ int snd_trident_create(struct snd_card *card,
struct pci_dev *pci, struct pci_dev *pci,
int pcm_streams, int pcm_streams,
int pcm_spdif_device, int pcm_spdif_device,
int max_wavetable_size, int max_wavetable_size)
struct snd_trident ** rtrident)
{ {
struct snd_trident *trident; struct snd_trident *trident = card->private_data;
int i, err; int i, err;
struct snd_trident_voice *voice; struct snd_trident_voice *voice;
struct snd_trident_pcm_mixer *tmix; struct snd_trident_pcm_mixer *tmix;
static const struct snd_device_ops ops = {
.dev_free = snd_trident_dev_free,
};
*rtrident = NULL;
/* enable PCI device */ /* enable PCI device */
err = pci_enable_device(pci); err = pcim_enable_device(pci);
if (err < 0) if (err < 0)
return err; return err;
/* check, if we can restrict PCI DMA transfers to 30 bits */ /* check, if we can restrict PCI DMA transfers to 30 bits */
if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(30))) { if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(30))) {
dev_err(card->dev, dev_err(card->dev,
"architecture does not support 30bit PCI busmaster DMA\n"); "architecture does not support 30bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO; return -ENXIO;
} }
trident = kzalloc(sizeof(*trident), GFP_KERNEL);
if (trident == NULL) {
pci_disable_device(pci);
return -ENOMEM;
}
trident->device = (pci->vendor << 16) | pci->device; trident->device = (pci->vendor << 16) | pci->device;
trident->card = card; trident->card = card;
trident->pci = pci; trident->pci = pci;
@ -3542,22 +3528,19 @@ int snd_trident_create(struct snd_card *card,
max_wavetable_size = 0; max_wavetable_size = 0;
trident->synth.max_size = max_wavetable_size * 1024; trident->synth.max_size = max_wavetable_size * 1024;
trident->irq = -1; trident->irq = -1;
card->private_free = snd_trident_free;
trident->midi_port = TRID_REG(trident, T4D_MPU401_BASE); trident->midi_port = TRID_REG(trident, T4D_MPU401_BASE);
pci_set_master(pci); pci_set_master(pci);
err = pci_request_regions(pci, "Trident Audio"); err = pci_request_regions(pci, "Trident Audio");
if (err < 0) { if (err < 0)
kfree(trident);
pci_disable_device(pci);
return err; return err;
}
trident->port = pci_resource_start(pci, 0); trident->port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_trident_interrupt, IRQF_SHARED, if (devm_request_irq(&pci->dev, pci->irq, snd_trident_interrupt,
KBUILD_MODNAME, trident)) { IRQF_SHARED, KBUILD_MODNAME, trident)) {
dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_trident_free(trident);
return -EBUSY; return -EBUSY;
} }
trident->irq = pci->irq; trident->irq = pci->irq;
@ -3565,13 +3548,10 @@ int snd_trident_create(struct snd_card *card,
/* allocate 16k-aligned TLB for NX cards */ /* allocate 16k-aligned TLB for NX cards */
trident->tlb.entries = NULL; trident->tlb.entries = NULL;
trident->tlb.buffer.area = NULL;
if (trident->device == TRIDENT_DEVICE_ID_NX) { if (trident->device == TRIDENT_DEVICE_ID_NX) {
err = snd_trident_tlb_alloc(trident); err = snd_trident_tlb_alloc(trident);
if (err < 0) { if (err < 0)
snd_trident_free(trident);
return err; return err;
}
} }
trident->spdif_bits = trident->spdif_pcm_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; trident->spdif_bits = trident->spdif_pcm_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
@ -3591,16 +3571,8 @@ int snd_trident_create(struct snd_card *card,
snd_BUG(); snd_BUG();
break; break;
} }
if (err < 0) { if (err < 0)
snd_trident_free(trident);
return err; return err;
}
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, trident, &ops);
if (err < 0) {
snd_trident_free(trident);
return err;
}
err = snd_trident_mixer(trident, pcm_spdif_device); err = snd_trident_mixer(trident, pcm_spdif_device);
if (err < 0) if (err < 0)
@ -3624,7 +3596,6 @@ int snd_trident_create(struct snd_card *card,
snd_trident_enable_eso(trident); snd_trident_enable_eso(trident);
snd_trident_proc_init(trident); snd_trident_proc_init(trident);
*rtrident = trident;
return 0; return 0;
} }
@ -3634,14 +3605,16 @@ int snd_trident_create(struct snd_card *card,
Description: This routine will free the device specific class for Description: This routine will free the device specific class for
the 4DWave card. the 4DWave card.
Parameters: trident - device specific private data for 4DWave card Parameters: card - card to release
Returns: None. Returns: None.
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
static int snd_trident_free(struct snd_trident *trident) static void snd_trident_free(struct snd_card *card)
{ {
struct snd_trident *trident = card->private_data;
snd_trident_free_gameport(trident); snd_trident_free_gameport(trident);
snd_trident_disable_eso(trident); snd_trident_disable_eso(trident);
// Disable S/PDIF out // Disable S/PDIF out
@ -3650,19 +3623,10 @@ static int snd_trident_free(struct snd_trident *trident)
else if (trident->device == TRIDENT_DEVICE_ID_SI7018) { else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL)); outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
} }
if (trident->irq >= 0) if (trident->tlb.buffer) {
free_irq(trident->irq, trident);
if (trident->tlb.buffer.area) {
outl(0, TRID_REG(trident, NX_TLBC)); outl(0, TRID_REG(trident, NX_TLBC));
snd_util_memhdr_free(trident->tlb.memhdr); snd_util_memhdr_free(trident->tlb.memhdr);
if (trident->tlb.silent_page.area)
snd_dma_free_pages(&trident->tlb.silent_page);
snd_dma_free_pages(&trident->tlb.buffer);
} }
pci_release_regions(trident->pci);
pci_disable_device(trident->pci);
kfree(trident);
return 0;
} }
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------

Просмотреть файл

@ -31,7 +31,7 @@
/* fill TLB entrie(s) corresponding to page with ptr */ /* fill TLB entrie(s) corresponding to page with ptr */
#define set_tlb_bus(trident,page,addr) __set_tlb_bus(trident,page,addr) #define set_tlb_bus(trident,page,addr) __set_tlb_bus(trident,page,addr)
/* fill TLB entrie(s) corresponding to page with silence pointer */ /* fill TLB entrie(s) corresponding to page with silence pointer */
#define set_silent_tlb(trident,page) __set_tlb_bus(trident, page, trident->tlb.silent_page.addr) #define set_silent_tlb(trident,page) __set_tlb_bus(trident, page, trident->tlb.silent_page->addr)
/* get aligned page from offset address */ /* get aligned page from offset address */
#define get_aligned_page(offset) ((offset) >> 12) #define get_aligned_page(offset) ((offset) >> 12)
/* get offset address from aligned page */ /* get offset address from aligned page */
@ -58,8 +58,8 @@ static inline void set_tlb_bus(struct snd_trident *trident, int page,
static inline void set_silent_tlb(struct snd_trident *trident, int page) static inline void set_silent_tlb(struct snd_trident *trident, int page)
{ {
page <<= 1; page <<= 1;
__set_tlb_bus(trident, page, trident->tlb.silent_page.addr); __set_tlb_bus(trident, page, trident->tlb.silent_page->addr);
__set_tlb_bus(trident, page+1, trident->tlb.silent_page.addr); __set_tlb_bus(trident, page+1, trident->tlb.silent_page->addr);
} }
#else #else
@ -92,7 +92,7 @@ static inline void set_silent_tlb(struct snd_trident *trident, int page)
int i; int i;
page *= UNIT_PAGES; page *= UNIT_PAGES;
for (i = 0; i < UNIT_PAGES; i++, page++) for (i = 0; i < UNIT_PAGES; i++, page++)
__set_tlb_bus(trident, page, trident->tlb.silent_page.addr); __set_tlb_bus(trident, page, trident->tlb.silent_page->addr);
} }
#endif /* PAGE_SIZE */ #endif /* PAGE_SIZE */