2 * Driver for Digigram VXpocket V2/440 soundcards
4 * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <sound/driver.h>
23 #include <linux/init.h>
24 #include <linux/moduleparam.h>
25 #include <sound/core.h>
27 #include <pcmcia/ciscode.h>
28 #include <pcmcia/cisreg.h>
29 #include <sound/initval.h>
34 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
35 MODULE_DESCRIPTION("Digigram VXPocket");
36 MODULE_LICENSE("GPL");
37 MODULE_SUPPORTED_DEVICE("{{Digigram,VXPocket},{Digigram,VXPocket440}}");
39 static int index
[SNDRV_CARDS
] = SNDRV_DEFAULT_IDX
; /* Index 0-MAX */
40 static char *id
[SNDRV_CARDS
] = SNDRV_DEFAULT_STR
; /* ID for this card */
41 static int enable
[SNDRV_CARDS
] = SNDRV_DEFAULT_ENABLE_PNP
; /* Enable switches */
42 static int ibl
[SNDRV_CARDS
];
44 module_param_array(index
, int, NULL
, 0444);
45 MODULE_PARM_DESC(index
, "Index value for VXPocket soundcard.");
46 module_param_array(id
, charp
, NULL
, 0444);
47 MODULE_PARM_DESC(id
, "ID string for VXPocket soundcard.");
48 module_param_array(enable
, bool, NULL
, 0444);
49 MODULE_PARM_DESC(enable
, "Enable VXPocket soundcard.");
50 module_param_array(ibl
, int, NULL
, 0444);
51 MODULE_PARM_DESC(ibl
, "Capture IBL size for VXPocket soundcard.");
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 static int vxpocket_event(event_t event
, int priority
, event_callback_args_t
*args
);
67 static void vxpocket_release(dev_link_t
*link
)
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
;
77 /* Break the link with Card Services */
78 pcmcia_deregister_client(link
->handle
);
84 * destructor, called from snd_card_free_in_thread()
86 static int snd_vxpocket_dev_free(snd_device_t
*device
)
88 vx_core_t
*chip
= device
->device_data
;
90 snd_vx_free_firmware(chip
);
97 * Hardware information
103 * 1 programmable clock (NIY)
104 * 1 stereo analog input (line/micro)
105 * 1 stereo analog output
106 * Only output levels can be modified
109 static struct snd_vx_hardware vxpocket_hw
= {
111 .type
= VX_TYPE_VXPOCKET
,
117 .output_level_max
= VX_ANALOG_OUT_LEVEL_MAX
,
122 * 1 DSP, 1 sync UER, 1 sync World Clock (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.
130 static struct snd_vx_hardware vxp440_hw
= {
131 .name
= "VXPocket440",
132 .type
= VX_TYPE_VXP440
,
138 .output_level_max
= VX_ANALOG_OUT_LEVEL_MAX
,
143 * create vxpocket instance
145 static struct snd_vxpocket
*snd_vxpocket_new(snd_card_t
*card
, int ibl
)
147 client_reg_t client_reg
; /* Register with cardmgr */
148 dev_link_t
*link
; /* Info for cardmgr */
150 struct snd_vxpocket
*vxp
;
152 static snd_device_ops_t ops
= {
153 .dev_free
= snd_vxpocket_dev_free
,
156 chip
= snd_vx_create(card
, &vxpocket_hw
, &snd_vxpocket_ops
,
157 sizeof(struct snd_vxpocket
) - sizeof(vx_core_t
));
161 if (snd_device_new(card
, SNDRV_DEV_LOWLEVEL
, chip
, &ops
) < 0) {
165 chip
->ibl
.size
= ibl
;
167 vxp
= (struct snd_vxpocket
*)chip
;
172 link
->io
.Attributes1
= IO_DATA_PATH_WIDTH_AUTO
;
173 link
->io
.NumPorts1
= 16;
175 link
->irq
.Attributes
= IRQ_TYPE_EXCLUSIVE
| IRQ_HANDLE_PRESENT
;
177 link
->irq
.IRQInfo1
= IRQ_LEVEL_ID
;
178 link
->irq
.Handler
= &snd_vx_irq_handler
;
179 link
->irq
.Instance
= chip
;
181 link
->conf
.Attributes
= CONF_ENABLE_IRQ
;
183 link
->conf
.IntType
= INT_MEMORY_AND_IO
;
184 link
->conf
.ConfigIndex
= 1;
185 link
->conf
.Present
= PRESENT_OPTION
;
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
193 | CS_EVENT_RESET_PHYSICAL
| CS_EVENT_CARD_RESET
194 | CS_EVENT_PM_SUSPEND
| CS_EVENT_PM_RESUME
197 client_reg
.event_handler
= &vxpocket_event
;
198 client_reg
.Version
= 0x0210;
199 client_reg
.event_callback_args
.client_data
= link
;
201 ret
= pcmcia_register_client(&link
->handle
, &client_reg
);
202 if (ret
!= CS_SUCCESS
) {
203 cs_error(link
->handle
, RegisterClient
, ret
);
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
216 * this function assigns the specified port and irq, boot the card,
217 * create pcm and control instances, and initialize the rest hardware.
219 * returns 0 if successful, or a negative error code.
221 static int snd_vxpocket_assign_resources(vx_core_t
*chip
, int port
, int irq
)
224 snd_card_t
*card
= chip
->card
;
225 struct snd_vxpocket
*vxp
= (struct snd_vxpocket
*)chip
;
227 snd_printdd(KERN_DEBUG
"vxpocket assign resources: port = 0x%x, irq = %d\n", port
, irq
);
230 sprintf(card
->shortname
, "Digigram %s", card
->driver
);
231 sprintf(card
->longname
, "%s at 0x%x, irq %i",
232 card
->shortname
, port
, irq
);
236 if ((err
= snd_vx_setup_firmware(chip
)) < 0)
244 * configuration callback
247 #define CS_CHECK(fn, ret) \
248 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
250 static void vxpocket_config(dev_link_t
*link
)
252 client_handle_t handle
= link
->handle
;
253 vx_core_t
*chip
= link
->priv
;
254 struct snd_vxpocket
*vxp
= (struct snd_vxpocket
*)chip
;
258 int last_fn
, last_ret
;
260 snd_printdd(KERN_DEBUG
"vxpocket_config called\n");
261 parse
= kmalloc(sizeof(*parse
), GFP_KERNEL
);
263 snd_printk(KERN_ERR
"vx: cannot allocate\n");
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];
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");
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
);
293 link
->state
|= DEV_CONFIG
;
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
));
299 chip
->dev
= &handle_to_dev(link
->handle
);
300 snd_card_set_dev(chip
->card
, chip
->dev
);
302 if (snd_vxpocket_assign_resources(chip
, link
->io
.BasePort1
, link
->irq
.AssignedIRQ
) < 0)
305 link
->dev
= &vxp
->node
;
306 link
->state
&= ~DEV_CONFIG_PENDING
;
311 cs_error(link
->handle
, last_fn
, last_ret
);
313 pcmcia_release_configuration(link
->handle
);
314 pcmcia_release_io(link
->handle
, &link
->io
);
315 pcmcia_release_irq(link
->handle
, &link
->irq
);
316 link
->state
&= ~DEV_CONFIG
;
324 static int vxpocket_event(event_t event
, int priority
, event_callback_args_t
*args
)
326 dev_link_t
*link
= args
->client_data
;
327 vx_core_t
*chip
= link
->priv
;
330 case CS_EVENT_CARD_REMOVAL
:
331 snd_printdd(KERN_DEBUG
"CARD_REMOVAL..\n");
332 link
->state
&= ~DEV_PRESENT
;
333 if (link
->state
& DEV_CONFIG
)
334 chip
->chip_status
|= VX_STAT_IS_STALE
;
336 case CS_EVENT_CARD_INSERTION
:
337 snd_printdd(KERN_DEBUG
"CARD_INSERTION..\n");
338 link
->state
|= DEV_PRESENT
| DEV_CONFIG_PENDING
;
339 vxpocket_config(link
);
342 case CS_EVENT_PM_SUSPEND
:
343 snd_printdd(KERN_DEBUG
"SUSPEND\n");
344 link
->state
|= DEV_SUSPEND
;
345 if (chip
&& chip
->card
->pm_suspend
) {
346 snd_printdd(KERN_DEBUG
"snd_vx_suspend calling\n");
347 chip
->card
->pm_suspend(chip
->card
, PMSG_SUSPEND
);
349 /* Fall through... */
350 case CS_EVENT_RESET_PHYSICAL
:
351 snd_printdd(KERN_DEBUG
"RESET_PHYSICAL\n");
352 if (link
->state
& DEV_CONFIG
)
353 pcmcia_release_configuration(link
->handle
);
355 case CS_EVENT_PM_RESUME
:
356 snd_printdd(KERN_DEBUG
"RESUME\n");
357 link
->state
&= ~DEV_SUSPEND
;
358 /* Fall through... */
359 case CS_EVENT_CARD_RESET
:
360 snd_printdd(KERN_DEBUG
"CARD_RESET\n");
362 //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
363 snd_printdd(KERN_DEBUG
"requestconfig...\n");
364 pcmcia_request_configuration(link
->handle
, &link
->conf
);
365 if (chip
&& chip
->card
->pm_resume
) {
366 snd_printdd(KERN_DEBUG
"calling snd_vx_resume\n");
367 chip
->card
->pm_resume(chip
->card
);
370 snd_printdd(KERN_DEBUG
"resume done!\n");
380 static dev_link_t
*vxpocket_attach(void)
383 struct snd_vxpocket
*vxp
;
386 /* find an empty slot from the card list */
387 for (i
= 0; i
< SNDRV_CARDS
; i
++) {
388 if (! card_alloc
& (1 << i
))
391 if (i
>= SNDRV_CARDS
) {
392 snd_printk(KERN_ERR
"vxpocket: too many cards found\n");
396 return NULL
; /* disabled explicitly */
398 /* ok, create a card instance */
399 card
= snd_card_new(index
[i
], id
[i
], THIS_MODULE
, 0);
401 snd_printk(KERN_ERR
"vxpocket: cannot create a card instance\n");
405 vxp
= snd_vxpocket_new(card
, ibl
[i
]);
412 card_alloc
|= 1 << i
;
415 vxp
->link
.next
= dev_list
;
416 dev_list
= &vxp
->link
;
421 static void vxpocket_detach(dev_link_t
*link
)
423 struct snd_vxpocket
*vxp
;
431 chip
= (vx_core_t
*)vxp
;
432 card_alloc
&= ~(1 << vxp
->index
);
434 /* Remove the interface data from the linked list */
435 for (linkp
= &dev_list
; *linkp
; linkp
= &(*linkp
)->next
)
436 if (*linkp
== link
) {
441 chip
->chip_status
|= VX_STAT_IS_STALE
; /* to be sure */
442 snd_card_disconnect(chip
->card
);
443 vxpocket_release(link
);
444 snd_card_free_in_thread(chip
->card
);
448 * Module entry points
451 static struct pcmcia_device_id vxp_ids
[] = {
452 PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100),
455 MODULE_DEVICE_TABLE(pcmcia
, vxp_ids
);
457 static struct pcmcia_driver vxp_cs_driver
= {
458 .owner
= THIS_MODULE
,
460 .name
= "snd-vxpocket",
462 .attach
= vxpocket_attach
,
463 .detach
= vxpocket_detach
,
464 .event
= vxpocket_event
,
468 static int __init
init_vxpocket(void)
470 return pcmcia_register_driver(&vxp_cs_driver
);
473 static void __exit
exit_vxpocket(void)
475 pcmcia_unregister_driver(&vxp_cs_driver
);
476 BUG_ON(dev_list
!= NULL
);
479 module_init(init_vxpocket
);
480 module_exit(exit_vxpocket
);