diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-06-30 07:40:51 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-07-28 06:09:56 -0400 |
commit | 6d00a3127972e7853d6296ffc1e72c5b1a23d937 (patch) | |
tree | 6c9018f16ed83400cb3297aa7c1ffea95cc03ff1 /sound/pcmcia/vx/vxpocket.c | |
parent | 82fe0c5803f4c77ffeb4c1c2367defb3dcedad45 (diff) |
[ALSA] Fix and clean-up of vxpocket driver
Documentation,PCMCIA Kconfig,Digigram VX Pocket driver
- Fixed Oops with request_firmware()
- Detect the card type in runtime (vxpoocket v2 or 440)
- snd-vxp440 driver is merged to snd-vxpocket
- Clean up the code
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pcmcia/vx/vxpocket.c')
-rw-r--r-- | sound/pcmcia/vx/vxpocket.c | 427 |
1 files changed, 373 insertions, 54 deletions
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 62d6fa128148..3a82161d3b24 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c | |||
@@ -24,21 +24,17 @@ | |||
24 | #include <linux/moduleparam.h> | 24 | #include <linux/moduleparam.h> |
25 | #include <sound/core.h> | 25 | #include <sound/core.h> |
26 | #include "vxpocket.h" | 26 | #include "vxpocket.h" |
27 | #include <pcmcia/ciscode.h> | ||
28 | #include <pcmcia/cisreg.h> | ||
27 | #include <sound/initval.h> | 29 | #include <sound/initval.h> |
28 | 30 | ||
29 | /* | 31 | /* |
30 | */ | 32 | */ |
31 | 33 | ||
32 | #ifdef COMPILE_VXP440 | ||
33 | #define CARD_NAME "VXPocket440" | ||
34 | #else | ||
35 | #define CARD_NAME "VXPocket" | ||
36 | #endif | ||
37 | |||
38 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | 34 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); |
39 | MODULE_DESCRIPTION("Digigram " CARD_NAME); | 35 | MODULE_DESCRIPTION("Digigram VXPocket"); |
40 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
41 | MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}"); | 37 | MODULE_SUPPORTED_DEVICE("{{Digigram,VXPocket},{Digigram,VXPocket440}}"); |
42 | 38 | ||
43 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 39 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
44 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 40 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
@@ -46,82 +42,405 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */ | |||
46 | static int ibl[SNDRV_CARDS]; | 42 | static int ibl[SNDRV_CARDS]; |
47 | 43 | ||
48 | module_param_array(index, int, NULL, 0444); | 44 | module_param_array(index, int, NULL, 0444); |
49 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); | 45 | MODULE_PARM_DESC(index, "Index value for VXPocket soundcard."); |
50 | module_param_array(id, charp, NULL, 0444); | 46 | module_param_array(id, charp, NULL, 0444); |
51 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); | 47 | MODULE_PARM_DESC(id, "ID string for VXPocket soundcard."); |
52 | module_param_array(enable, bool, NULL, 0444); | 48 | module_param_array(enable, bool, NULL, 0444); |
53 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | 49 | MODULE_PARM_DESC(enable, "Enable VXPocket soundcard."); |
54 | module_param_array(ibl, int, NULL, 0444); | 50 | module_param_array(ibl, int, NULL, 0444); |
55 | MODULE_PARM_DESC(ibl, "Capture IBL size for " CARD_NAME " soundcard."); | 51 | MODULE_PARM_DESC(ibl, "Capture IBL size for VXPocket soundcard."); |
56 | 52 | ||
57 | 53 | ||
58 | /* | 54 | /* |
59 | */ | 55 | */ |
60 | 56 | ||
61 | #ifdef COMPILE_VXP440 | 57 | static unsigned int card_alloc; |
58 | static dev_link_t *dev_list; /* Linked list of devices */ | ||
59 | static dev_info_t dev_info = "snd-vxpocket"; | ||
62 | 60 | ||
63 | /* 1 DSP, 1 sync UER, 1 sync World Clock (NIY) */ | ||
64 | /* SMPTE (NIY) */ | ||
65 | /* 2 stereo analog input (line/micro) */ | ||
66 | /* 2 stereo analog output */ | ||
67 | /* Only output levels can be modified */ | ||
68 | /* UER, but only for the first two inputs and outputs. */ | ||
69 | 61 | ||
70 | #define NUM_CODECS 2 | 62 | static int vxpocket_event(event_t event, int priority, event_callback_args_t *args); |
71 | #define CARD_TYPE VX_TYPE_VXP440 | ||
72 | #define DEV_INFO "snd-vxp440" | ||
73 | 63 | ||
74 | #else | ||
75 | 64 | ||
76 | /* 1 DSP, 1 sync UER */ | 65 | /* |
77 | /* 1 programmable clock (NIY) */ | 66 | */ |
78 | /* 1 stereo analog input (line/micro) */ | 67 | static void vxpocket_release(dev_link_t *link) |
79 | /* 1 stereo analog output */ | 68 | { |
80 | /* Only output levels can be modified */ | 69 | if (link->state & DEV_CONFIG) { |
70 | /* release cs resources */ | ||
71 | pcmcia_release_configuration(link->handle); | ||
72 | pcmcia_release_io(link->handle, &link->io); | ||
73 | pcmcia_release_irq(link->handle, &link->irq); | ||
74 | link->state &= ~DEV_CONFIG; | ||
75 | } | ||
76 | if (link->handle) { | ||
77 | /* Break the link with Card Services */ | ||
78 | pcmcia_deregister_client(link->handle); | ||
79 | link->handle = NULL; | ||
80 | } | ||
81 | } | ||
81 | 82 | ||
82 | #define NUM_CODECS 1 | 83 | /* |
83 | #define CARD_TYPE VX_TYPE_VXPOCKET | 84 | * destructor, called from snd_card_free_in_thread() |
84 | #define DEV_INFO "snd-vxpocket" | 85 | */ |
86 | static int snd_vxpocket_dev_free(snd_device_t *device) | ||
87 | { | ||
88 | vx_core_t *chip = device->device_data; | ||
85 | 89 | ||
86 | #endif | 90 | snd_vx_free_firmware(chip); |
91 | kfree(chip); | ||
92 | return 0; | ||
93 | } | ||
87 | 94 | ||
88 | static dev_info_t dev_info = DEV_INFO; | ||
89 | 95 | ||
90 | static struct snd_vx_hardware vxp_hw = { | 96 | /* |
91 | .name = CARD_NAME, | 97 | * Hardware information |
92 | .type = CARD_TYPE, | 98 | */ |
99 | |||
100 | /* VX-pocket V2 | ||
101 | * | ||
102 | * 1 DSP, 1 sync UER | ||
103 | * 1 programmable clock (NIY) | ||
104 | * 1 stereo analog input (line/micro) | ||
105 | * 1 stereo analog output | ||
106 | * Only output levels can be modified | ||
107 | */ | ||
108 | |||
109 | static struct snd_vx_hardware vxpocket_hw = { | ||
110 | .name = "VXPocket", | ||
111 | .type = VX_TYPE_VXPOCKET, | ||
93 | 112 | ||
94 | /* hardware specs */ | 113 | /* hardware specs */ |
95 | .num_codecs = NUM_CODECS, | 114 | .num_codecs = 1, |
96 | .num_ins = NUM_CODECS, | 115 | .num_ins = 1, |
97 | .num_outs = NUM_CODECS, | 116 | .num_outs = 1, |
98 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, | 117 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, |
99 | }; | 118 | }; |
100 | 119 | ||
101 | static struct snd_vxp_entry hw_entry = { | 120 | /* VX-pocket 440 |
102 | .dev_info = &dev_info, | 121 | * |
122 | * 1 DSP, 1 sync UER, 1 sync World Clock (NIY) | ||
123 | * SMPTE (NIY) | ||
124 | * 2 stereo analog input (line/micro) | ||
125 | * 2 stereo analog output | ||
126 | * Only output levels can be modified | ||
127 | * UER, but only for the first two inputs and outputs. | ||
128 | */ | ||
103 | 129 | ||
104 | /* module parameters */ | 130 | static struct snd_vx_hardware vxp440_hw = { |
105 | .index_table = index, | 131 | .name = "VXPocket440", |
106 | .id_table = id, | 132 | .type = VX_TYPE_VXP440, |
107 | .enable_table = enable, | 133 | |
108 | .ibl = ibl, | 134 | /* hardware specs */ |
135 | .num_codecs = 2, | ||
136 | .num_ins = 2, | ||
137 | .num_outs = 2, | ||
138 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, | ||
139 | }; | ||
140 | |||
141 | |||
142 | /* | ||
143 | * create vxpocket instance | ||
144 | */ | ||
145 | static struct snd_vxpocket *snd_vxpocket_new(snd_card_t *card, int ibl) | ||
146 | { | ||
147 | client_reg_t client_reg; /* Register with cardmgr */ | ||
148 | dev_link_t *link; /* Info for cardmgr */ | ||
149 | vx_core_t *chip; | ||
150 | struct snd_vxpocket *vxp; | ||
151 | int ret; | ||
152 | static snd_device_ops_t ops = { | ||
153 | .dev_free = snd_vxpocket_dev_free, | ||
154 | }; | ||
155 | |||
156 | chip = snd_vx_create(card, &vxpocket_hw, &snd_vxpocket_ops, | ||
157 | sizeof(struct snd_vxpocket) - sizeof(vx_core_t)); | ||
158 | if (! chip) | ||
159 | return NULL; | ||
160 | |||
161 | if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) { | ||
162 | kfree(chip); | ||
163 | return NULL; | ||
164 | } | ||
165 | chip->ibl.size = ibl; | ||
166 | |||
167 | vxp = (struct snd_vxpocket *)chip; | ||
168 | |||
169 | link = &vxp->link; | ||
170 | link->priv = chip; | ||
171 | |||
172 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
173 | link->io.NumPorts1 = 16; | ||
174 | |||
175 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
176 | |||
177 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
178 | link->irq.Handler = &snd_vx_irq_handler; | ||
179 | link->irq.Instance = chip; | ||
180 | |||
181 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
182 | link->conf.Vcc = 50; | ||
183 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
184 | link->conf.ConfigIndex = 1; | ||
185 | link->conf.Present = PRESENT_OPTION; | ||
186 | |||
187 | /* Register with Card Services */ | ||
188 | memset(&client_reg, 0, sizeof(client_reg)); | ||
189 | client_reg.dev_info = &dev_info; | ||
190 | client_reg.EventMask = | ||
191 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ||
192 | #ifdef CONFIG_PM | ||
193 | | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ||
194 | | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME | ||
195 | #endif | ||
196 | ; | ||
197 | client_reg.event_handler = &vxpocket_event; | ||
198 | client_reg.Version = 0x0210; | ||
199 | client_reg.event_callback_args.client_data = link; | ||
200 | |||
201 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
202 | if (ret != CS_SUCCESS) { | ||
203 | cs_error(link->handle, RegisterClient, ret); | ||
204 | return NULL; | ||
205 | } | ||
206 | |||
207 | return vxp; | ||
208 | } | ||
209 | |||
210 | |||
211 | /** | ||
212 | * snd_vxpocket_assign_resources - initialize the hardware and card instance. | ||
213 | * @port: i/o port for the card | ||
214 | * @irq: irq number for the card | ||
215 | * | ||
216 | * this function assigns the specified port and irq, boot the card, | ||
217 | * create pcm and control instances, and initialize the rest hardware. | ||
218 | * | ||
219 | * returns 0 if successful, or a negative error code. | ||
220 | */ | ||
221 | static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq) | ||
222 | { | ||
223 | int err; | ||
224 | snd_card_t *card = chip->card; | ||
225 | struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; | ||
226 | |||
227 | snd_printdd(KERN_DEBUG "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq); | ||
228 | vxp->port = port; | ||
229 | |||
230 | sprintf(card->shortname, "Digigram %s", card->driver); | ||
231 | sprintf(card->longname, "%s at 0x%x, irq %i", | ||
232 | card->shortname, port, irq); | ||
233 | |||
234 | chip->irq = irq; | ||
235 | |||
236 | if ((err = snd_vx_setup_firmware(chip)) < 0) | ||
237 | return err; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | |||
243 | /* | ||
244 | * configuration callback | ||
245 | */ | ||
246 | |||
247 | #define CS_CHECK(fn, ret) \ | ||
248 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
249 | |||
250 | static void vxpocket_config(dev_link_t *link) | ||
251 | { | ||
252 | client_handle_t handle = link->handle; | ||
253 | vx_core_t *chip = link->priv; | ||
254 | struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; | ||
255 | tuple_t tuple; | ||
256 | cisparse_t *parse; | ||
257 | u_short buf[32]; | ||
258 | int last_fn, last_ret; | ||
259 | |||
260 | snd_printdd(KERN_DEBUG "vxpocket_config called\n"); | ||
261 | parse = kmalloc(sizeof(*parse), GFP_KERNEL); | ||
262 | if (! parse) { | ||
263 | snd_printk(KERN_ERR "vx: cannot allocate\n"); | ||
264 | return; | ||
265 | } | ||
266 | tuple.Attributes = 0; | ||
267 | tuple.TupleData = (cisdata_t *)buf; | ||
268 | tuple.TupleDataMax = sizeof(buf); | ||
269 | tuple.TupleOffset = 0; | ||
270 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
271 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
272 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
273 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse)); | ||
274 | link->conf.ConfigBase = parse->config.base; | ||
275 | link->conf.Present = parse->config.rmask[0]; | ||
276 | |||
277 | /* redefine hardware record according to the VERSION1 string */ | ||
278 | tuple.DesiredTuple = CISTPL_VERS_1; | ||
279 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
280 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
281 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse)); | ||
282 | if (! strcmp(parse->version_1.str + parse->version_1.ofs[1], "VX-POCKET")) { | ||
283 | snd_printdd("VX-pocket is detected\n"); | ||
284 | } else { | ||
285 | snd_printdd("VX-pocket 440 is detected\n"); | ||
286 | /* overwrite the hardware information */ | ||
287 | chip->hw = &vxp440_hw; | ||
288 | chip->type = vxp440_hw.type; | ||
289 | strcpy(chip->card->driver, vxp440_hw.name); | ||
290 | } | ||
291 | |||
292 | /* Configure card */ | ||
293 | link->state |= DEV_CONFIG; | ||
294 | |||
295 | CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io)); | ||
296 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); | ||
297 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); | ||
298 | |||
299 | chip->dev = &handle_to_dev(link->handle); | ||
300 | |||
301 | if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0) | ||
302 | goto failed; | ||
303 | |||
304 | link->dev = &vxp->node; | ||
305 | link->state &= ~DEV_CONFIG_PENDING; | ||
306 | kfree(parse); | ||
307 | return; | ||
308 | |||
309 | cs_failed: | ||
310 | cs_error(link->handle, last_fn, last_ret); | ||
311 | failed: | ||
312 | pcmcia_release_configuration(link->handle); | ||
313 | pcmcia_release_io(link->handle, &link->io); | ||
314 | pcmcia_release_irq(link->handle, &link->irq); | ||
315 | link->state &= ~DEV_CONFIG; | ||
316 | kfree(parse); | ||
317 | } | ||
318 | |||
319 | |||
320 | /* | ||
321 | * event callback | ||
322 | */ | ||
323 | static int vxpocket_event(event_t event, int priority, event_callback_args_t *args) | ||
324 | { | ||
325 | dev_link_t *link = args->client_data; | ||
326 | vx_core_t *chip = link->priv; | ||
327 | |||
328 | switch (event) { | ||
329 | case CS_EVENT_CARD_REMOVAL: | ||
330 | snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n"); | ||
331 | link->state &= ~DEV_PRESENT; | ||
332 | if (link->state & DEV_CONFIG) | ||
333 | chip->chip_status |= VX_STAT_IS_STALE; | ||
334 | break; | ||
335 | case CS_EVENT_CARD_INSERTION: | ||
336 | snd_printdd(KERN_DEBUG "CARD_INSERTION..\n"); | ||
337 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
338 | vxpocket_config(link); | ||
339 | break; | ||
340 | #ifdef CONFIG_PM | ||
341 | case CS_EVENT_PM_SUSPEND: | ||
342 | snd_printdd(KERN_DEBUG "SUSPEND\n"); | ||
343 | link->state |= DEV_SUSPEND; | ||
344 | if (chip && chip->card->pm_suspend) { | ||
345 | snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n"); | ||
346 | chip->card->pm_suspend(chip->card, PMSG_SUSPEND); | ||
347 | } | ||
348 | /* Fall through... */ | ||
349 | case CS_EVENT_RESET_PHYSICAL: | ||
350 | snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n"); | ||
351 | if (link->state & DEV_CONFIG) | ||
352 | pcmcia_release_configuration(link->handle); | ||
353 | break; | ||
354 | case CS_EVENT_PM_RESUME: | ||
355 | snd_printdd(KERN_DEBUG "RESUME\n"); | ||
356 | link->state &= ~DEV_SUSPEND; | ||
357 | /* Fall through... */ | ||
358 | case CS_EVENT_CARD_RESET: | ||
359 | snd_printdd(KERN_DEBUG "CARD_RESET\n"); | ||
360 | if (DEV_OK(link)) { | ||
361 | //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; | ||
362 | snd_printdd(KERN_DEBUG "requestconfig...\n"); | ||
363 | pcmcia_request_configuration(link->handle, &link->conf); | ||
364 | if (chip && chip->card->pm_resume) { | ||
365 | snd_printdd(KERN_DEBUG "calling snd_vx_resume\n"); | ||
366 | chip->card->pm_resume(chip->card); | ||
367 | } | ||
368 | } | ||
369 | snd_printdd(KERN_DEBUG "resume done!\n"); | ||
370 | break; | ||
371 | #endif | ||
372 | } | ||
373 | return 0; | ||
374 | } | ||
109 | 375 | ||
110 | /* h/w config */ | ||
111 | .hardware = &vxp_hw, | ||
112 | .ops = &snd_vxpocket_ops, | ||
113 | }; | ||
114 | 376 | ||
115 | /* | 377 | /* |
116 | */ | 378 | */ |
117 | static dev_link_t *vxp_attach(void) | 379 | static dev_link_t *vxp_attach(void) |
118 | { | 380 | { |
119 | return snd_vxpocket_attach(&hw_entry); | 381 | snd_card_t *card; |
382 | struct snd_vxpocket *vxp; | ||
383 | int i; | ||
384 | |||
385 | /* find an empty slot from the card list */ | ||
386 | for (i = 0; i < SNDRV_CARDS; i++) { | ||
387 | if (! card_alloc & (1 << i)) | ||
388 | break; | ||
389 | } | ||
390 | if (i >= SNDRV_CARDS) { | ||
391 | snd_printk(KERN_ERR "vxpocket: too many cards found\n"); | ||
392 | return NULL; | ||
393 | } | ||
394 | if (! enable[i]) | ||
395 | return NULL; /* disabled explicitly */ | ||
396 | |||
397 | /* ok, create a card instance */ | ||
398 | card = snd_card_new(index[i], id[i], THIS_MODULE, 0); | ||
399 | if (card == NULL) { | ||
400 | snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n"); | ||
401 | return NULL; | ||
402 | } | ||
403 | |||
404 | vxp = snd_vxpocket_new(card, ibl[i]); | ||
405 | if (! vxp) { | ||
406 | snd_card_free(card); | ||
407 | return NULL; | ||
408 | } | ||
409 | |||
410 | vxp->index = index[i]; | ||
411 | card_alloc |= 1 << i; | ||
412 | |||
413 | /* Chain drivers */ | ||
414 | vxp->link.next = dev_list; | ||
415 | dev_list = &vxp->link; | ||
416 | |||
417 | return &vxp->link; | ||
120 | } | 418 | } |
121 | 419 | ||
122 | static void vxp_detach(dev_link_t *link) | 420 | static void vxp_detach(dev_link_t *link) |
123 | { | 421 | { |
124 | snd_vxpocket_detach(&hw_entry, link); | 422 | struct snd_vxpocket *vxp; |
423 | vx_core_t *chip; | ||
424 | dev_link_t **linkp; | ||
425 | |||
426 | if (! link) | ||
427 | return; | ||
428 | |||
429 | vxp = link->priv; | ||
430 | chip = (vx_core_t *)vxp; | ||
431 | card_alloc &= ~(1 << vxp->index); | ||
432 | |||
433 | /* Remove the interface data from the linked list */ | ||
434 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
435 | if (*linkp == link) { | ||
436 | *linkp = link->next; | ||
437 | break; | ||
438 | } | ||
439 | |||
440 | chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */ | ||
441 | snd_card_disconnect(chip->card); | ||
442 | vxpocket_release(link); | ||
443 | snd_card_free_in_thread(chip->card); | ||
125 | } | 444 | } |
126 | 445 | ||
127 | /* | 446 | /* |
@@ -137,7 +456,7 @@ MODULE_DEVICE_TABLE(pcmcia, vxp_ids); | |||
137 | static struct pcmcia_driver vxp_cs_driver = { | 456 | static struct pcmcia_driver vxp_cs_driver = { |
138 | .owner = THIS_MODULE, | 457 | .owner = THIS_MODULE, |
139 | .drv = { | 458 | .drv = { |
140 | .name = DEV_INFO, | 459 | .name = "snd-vxpocket", |
141 | }, | 460 | }, |
142 | .attach = vxp_attach, | 461 | .attach = vxp_attach, |
143 | .detach = vxp_detach, | 462 | .detach = vxp_detach, |
@@ -152,7 +471,7 @@ static int __init init_vxpocket(void) | |||
152 | static void __exit exit_vxpocket(void) | 471 | static void __exit exit_vxpocket(void) |
153 | { | 472 | { |
154 | pcmcia_unregister_driver(&vxp_cs_driver); | 473 | pcmcia_unregister_driver(&vxp_cs_driver); |
155 | BUG_ON(hw_entry.dev_list != NULL); | 474 | BUG_ON(dev_list != NULL); |
156 | } | 475 | } |
157 | 476 | ||
158 | module_init(init_vxpocket); | 477 | module_init(init_vxpocket); |