Revision ebff65473f56e6c30de928fd6a4f1ce5ae36e8c5 authored by Shawn Guo on 02 December 2013, 05:26:50 UTC, committed by Mark Brown on 02 December 2013, 11:50:53 UTC
Since devm_card_release() expects parameter 'res' to be a pointer to
struct snd_soc_card, devm_snd_soc_register_card() should really pass
such a pointer rather than the one to struct device.

This bug causes the kernel Oops below with imx-sgtl500 driver when we
remove the module.  It happens because with 'card' pointing to the wrong
structure, card->num_rtd becomes 0 in function soc_remove_dai_links().
Consequently, soc_remove_link_components() and in turn
soc_cleanup_codec[platform]_debugfs() will not be called on card
removal.  It results in that debugfs_card_root is being removed while
its child entries debugfs_codec_root and debugfs_platform_root are still
there, and thus the kernel Oops.

Fix the bug by correcting the parameter 'res' to be the pointer to
struct snd_soc_card.

$ lsmod
Module                  Size  Used by
snd_soc_imx_sgtl5000     3506  0
snd_soc_sgtl5000       13677  2
snd_soc_imx_audmux      5324  1 snd_soc_imx_sgtl5000
snd_soc_fsl_ssi         8139  2
imx_pcm_dma             1380  1 snd_soc_fsl_ssi
$ rmmod snd_soc_imx_sgtl5000
Unable to handle kernel paging request at virtual address e594025c
pgd = be134000
[e594025c] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
Modules linked in: snd_soc_imx_sgtl5000(-) snd_soc_sgtl5000 snd_soc_imx_audmux snd_soc_fsl_ssi imx_pcm_dma
CPU: 0 PID: 1793 Comm: rmmod Not tainted 3.13.0-rc1 #1570
task: bee28900 ti: bfbec000 task.ti: bfbec000
PC is at debugfs_remove_recursive+0x28/0x154
LR is at snd_soc_unregister_card+0xa0/0xcc
pc : [<80252b38>]    lr : [<80496ac4>]    psr: a0000013
sp : bfbede00  ip : bfbede28  fp : bfbede24
r10: 803281d4  r9 : bfbec000  r8 : 803271ac
r7 : bef54440  r6 : 00000004  r5 : bf9a4010  r4 : bf9a4010
r3 : e5940224  r2 : 00000000  r1 : bef54450  r0 : 803271ac
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c53c7d  Table: 4e13404a  DAC: 00000015
Process rmmod (pid: 1793, stack limit = 0xbfbec240)
Stack: (0xbfbede00 to 0xbfbee000)
de00: 00000000 bf9a4010 bf9a4010 00000004 bef54440 bec89000 bfbede44 bfbede28
de20: 80496ac4 80252b1c 804a4b60 bfbede60 bf9a4010 00000004 bfbede54 bfbede48
de40: 804a4b74 80496a30 bfbede94 bfbede58 80328728 804a4b6c bfbede94 a0000013
de60: bf1b5800 bef54440 00000002 bf9a4010 7f0169f8 bf9a4044 00000081 8000e9c4
de80: bfbec000 00000000 bfbedeac bfbede98 80328cb0 80328618 7f016000 bf9a4010
dea0: bfbedec4 bfbedeb0 8032561c 80328c84 bf9a4010 7f0169f8 bfbedee4 bfbedec8
dec0: 80325e84 803255a8 bee28900 7f0169f8 00000000 78208d30 bfbedefc bfbedee8
dee0: 80325410 80325dd4 beca8100 7f0169f8 bfbedf14 bfbedf00 803264f8 803253c8
df00: 7f01635c 7f016a3c bfbedf24 bfbedf18 80327098 803264d4 bfbedf34 bfbedf28
df20: 7f016370 80327090 bfbedfa4 bfbedf38 80085ef0 7f016368 bfbedf54 5f646e73
df40: 5f636f73 5f786d69 6c746773 30303035 00000000 78208008 bfbedf84 bfbedf68
df60: 800613b0 80061194 fffffffe 78208d00 7efc2f07 00000081 7f016a3c 00000800
df80: bfbedf84 00000000 00000000 fffffffe 78208d00 7efc2f07 00000000 bfbedfa8
dfa0: 8000e800 80085dcc fffffffe 78208d00 78208d30 00000800 a8c82400 a8c82400
dfc0: fffffffe 78208d00 7efc2f07 00000081 00000002 00000000 78208008 00000800
dfe0: 7efc2e1c 7efc2ba8 76f5ca47 76edec7c 80000010 78208d30 00000000 00000000
Backtrace:
[<80252b10>] (debugfs_remove_recursive+0x0/0x154) from [<80496ac4>] (snd_soc_unregister_card+0xa0/0xcc)
 r8:bec89000 r7:bef54440 r6:00000004 r5:bf9a4010 r4:bf9a4010
r3:00000000
[<80496a24>] (snd_soc_unregister_card+0x0/0xcc) from [<804a4b74>] (devm_card_release+0x14/0x18)
 r6:00000004 r5:bf9a4010 r4:bfbede60 r3:804a4b60
[<804a4b60>] (devm_card_release+0x0/0x18) from [<80328728>] (release_nodes+0x11c/0x1dc)
[<8032860c>] (release_nodes+0x0/0x1dc) from [<80328cb0>] (devres_release_all+0x38/0x54)
[<80328c78>] (devres_release_all+0x0/0x54) from [<8032561c>] (__device_release_driver+0x80/0xd4)
 r4:bf9a4010 r3:7f016000
[<8032559c>] (__device_release_driver+0x0/0xd4) from [<80325e84>] (driver_detach+0xbc/0xc0)
 r5:7f0169f8 r4:bf9a4010
[<80325dc8>] (driver_detach+0x0/0xc0) from [<80325410>] (bus_remove_driver+0x54/0x98)
 r6:78208d30 r5:00000000 r4:7f0169f8 r3:bee28900
[<803253bc>] (bus_remove_driver+0x0/0x98) from [<803264f8>] (driver_unregister+0x30/0x50)
 r4:7f0169f8 r3:beca8100
[<803264c8>] (driver_unregister+0x0/0x50) from [<80327098>] (platform_driver_unregister+0x14/0x18)
 r4:7f016a3c r3:7f01635c
[<80327084>] (platform_driver_unregister+0x0/0x18) from [<7f016370>] (imx_sgtl5000_driver_exit+0x14/0x1c [snd_soc_imx_sgtl5000])
[<7f01635c>] (imx_sgtl5000_driver_exit+0x0/0x1c [snd_soc_imx_sgtl5000]) from [<80085ef0>] (SyS_delete_module+0x130/0x18c)
[<80085dc0>] (SyS_delete_module+0x0/0x18c) from [<8000e800>] (ret_fast_syscall+0x0/0x48)
 r6:7efc2f07 r5:78208d00 r4:fffffffe
Code: 889da9f8 e5983020 e3530000 089da9f8 (e5933038)
---[ end trace 825e7e125251a225 ]---

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Mark Brown <broonie@linaro.org>
1 parent 8f1ec93
Raw File
snd_wavefront.h
#ifndef __SOUND_SND_WAVEFRONT_H__
#define __SOUND_SND_WAVEFRONT_H__

#include <sound/mpu401.h>
#include <sound/hwdep.h>
#include <sound/rawmidi.h>
#include <sound/wavefront.h>  /* generic OSS/ALSA/user-level wavefront header */

/* MIDI interface */

struct _snd_wavefront_midi;
struct _snd_wavefront_card;
struct _snd_wavefront;

typedef struct _snd_wavefront_midi snd_wavefront_midi_t;
typedef struct _snd_wavefront_card snd_wavefront_card_t;
typedef struct _snd_wavefront snd_wavefront_t;

typedef enum { internal_mpu = 0, external_mpu = 1 } snd_wavefront_mpu_id;

struct _snd_wavefront_midi {
        unsigned long            base;        /* I/O port address */
	char                     isvirtual;   /* doing virtual MIDI stuff ? */
	char			 istimer;     /* timer is used */
        snd_wavefront_mpu_id     output_mpu;  /* most-recently-used */
        snd_wavefront_mpu_id     input_mpu;   /* most-recently-used */
        unsigned int             mode[2];     /* MPU401_MODE_XXX */
	struct snd_rawmidi_substream	 *substream_output[2];
	struct snd_rawmidi_substream	 *substream_input[2];
	struct timer_list	 timer;
        spinlock_t               open;
        spinlock_t               virtual;     /* protects isvirtual */
};

#define	OUTPUT_READY	0x40
#define	INPUT_AVAIL	0x80
#define	MPU_ACK		0xFE
#define	UART_MODE_ON	0x3F

extern struct snd_rawmidi_ops snd_wavefront_midi_output;
extern struct snd_rawmidi_ops snd_wavefront_midi_input;

extern void   snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *);
extern void   snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *);
extern void   snd_wavefront_midi_interrupt (snd_wavefront_card_t *);
extern int    snd_wavefront_midi_start (snd_wavefront_card_t *);

struct _snd_wavefront {
	unsigned long    irq;   /* "you were one, one of the few ..." */
	unsigned long    base;  /* low i/o port address */
	struct resource	 *res_base; /* i/o port resource allocation */

#define mpu_data_port    base 
#define mpu_command_port base + 1 /* write semantics */
#define mpu_status_port  base + 1 /* read semantics */
#define data_port        base + 2 
#define status_port      base + 3 /* read semantics */
#define control_port     base + 3 /* write semantics  */
#define block_port       base + 4 /* 16 bit, writeonly */
#define last_block_port  base + 6 /* 16 bit, writeonly */

	/* FX ports. These are mapped through the ICS2115 to the YS225.
	   The ICS2115 takes care of flipping the relevant pins on the
	   YS225 so that access to each of these ports does the right
	   thing. Note: these are NOT documented by Turtle Beach.
	*/

#define fx_status       base + 8 
#define fx_op           base + 8 
#define fx_lcr          base + 9 
#define fx_dsp_addr     base + 0xa
#define fx_dsp_page     base + 0xb 
#define fx_dsp_lsb      base + 0xc 
#define fx_dsp_msb      base + 0xd 
#define fx_mod_addr     base + 0xe
#define fx_mod_data     base + 0xf 

	volatile int irq_ok;               /* set by interrupt handler */
        volatile int irq_cnt;              /* ditto */
	char debug;                        /* debugging flags */
	int freemem;                       /* installed RAM, in bytes */ 

	char fw_version[2];                /* major = [0], minor = [1] */
	char hw_version[2];                /* major = [0], minor = [1] */
	char israw;                        /* needs Motorola microcode */
	char has_fx;                       /* has FX processor (Tropez+) */
	char fx_initialized;               /* FX's register pages initialized */
	char prog_status[WF_MAX_PROGRAM];  /* WF_SLOT_* */
	char patch_status[WF_MAX_PATCH];   /* WF_SLOT_* */
	char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */
	int samples_used;                  /* how many */
	char interrupts_are_midi;          /* h/w MPU interrupts enabled ? */
	char rom_samples_rdonly;           /* can we write on ROM samples */
	spinlock_t irq_lock;
	wait_queue_head_t interrupt_sleeper; 
	snd_wavefront_midi_t midi;         /* ICS2115 MIDI interface */
	struct snd_card *card;
};

struct _snd_wavefront_card {
	snd_wavefront_t wavefront;
#ifdef CONFIG_PNP
	struct pnp_dev *wss;
	struct pnp_dev *ctrl;
	struct pnp_dev *mpu;
	struct pnp_dev *synth;
#endif /* CONFIG_PNP */
};

extern void snd_wavefront_internal_interrupt (snd_wavefront_card_t *card);
extern int  snd_wavefront_detect_irq (snd_wavefront_t *dev) ;
extern int  snd_wavefront_check_irq (snd_wavefront_t *dev, int irq);
extern int  snd_wavefront_restart (snd_wavefront_t *dev);
extern int  snd_wavefront_start (snd_wavefront_t *dev);
extern int  snd_wavefront_detect (snd_wavefront_card_t *card);
extern int  snd_wavefront_config_midi (snd_wavefront_t *dev) ;
extern int  snd_wavefront_cmd (snd_wavefront_t *, int, unsigned char *,
			       unsigned char *);

extern int snd_wavefront_synth_ioctl   (struct snd_hwdep *, 
					struct file *,
					unsigned int cmd, 
					unsigned long arg);
extern int  snd_wavefront_synth_open    (struct snd_hwdep *, struct file *);
extern int  snd_wavefront_synth_release (struct snd_hwdep *, struct file *);

/* FX processor - see also yss225.[ch] */

extern int  snd_wavefront_fx_start  (snd_wavefront_t *);
extern int  snd_wavefront_fx_detect (snd_wavefront_t *);
extern int  snd_wavefront_fx_ioctl  (struct snd_hwdep *, 
				     struct file *,
				     unsigned int cmd, 
				     unsigned long arg);
extern int snd_wavefront_fx_open    (struct snd_hwdep *, struct file *);
extern int snd_wavefront_fx_release (struct snd_hwdep *, struct file *);

/* prefix in all snd_printk() delivered messages */

#define LOGNAME "WaveFront: "

#endif  /* __SOUND_SND_WAVEFRONT_H__ */
back to top