1 /* 2 * Driver for Digigram VXpocket V2/440 soundcards 3 * 4 * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 22 #include <sound/driver.h> 23 #include <linux/init.h> 24 #include <linux/moduleparam.h> 25 #include <sound/core.h> 26 #include "vxpocket.h" 27 #include <pcmcia/ciscode.h> 28 #include <pcmcia/cisreg.h> 29 #include <sound/initval.h> 30 31 /* 32 */ 33 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}}"); 38 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]; 43 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."); 52 53 54 /* 55 */ 56 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"; 60 61 62 static int vxpocket_event(event_t event, int priority, event_callback_args_t *args); 63 64 65 /* 66 */ 67 static void vxpocket_release(dev_link_t *link) 68 { 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 } 82 83 /* 84 * destructor, called from snd_card_free_in_thread() 85 */ 86 static int snd_vxpocket_dev_free(struct snd_device *device) 87 { 88 struct vx_core *chip = device->device_data; 89 90 snd_vx_free_firmware(chip); 91 kfree(chip); 92 return 0; 93 } 94 95 96 /* 97 * Hardware information 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, 112 113 /* hardware specs */ 114 .num_codecs = 1, 115 .num_ins = 1, 116 .num_outs = 1, 117 .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, 118 }; 119 120 /* VX-pocket 440 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 */ 129 130 static struct snd_vx_hardware vxp440_hw = { 131 .name = "VXPocket440", 132 .type = VX_TYPE_VXP440, 133 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(struct snd_card *card, int ibl) 146 { 147 client_reg_t client_reg; /* Register with cardmgr */ 148 dev_link_t *link; /* Info for cardmgr */ 149 struct vx_core *chip; 150 struct snd_vxpocket *vxp; 151 int ret; 152 static struct snd_device_ops 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(struct vx_core)); 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(struct vx_core *chip, int port, int irq) 222 { 223 int err; 224 struct snd_card *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 struct vx_core *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 snd_card_set_dev(chip->card, chip->dev); 301 302 if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0) 303 goto failed; 304 305 link->dev = &vxp->node; 306 link->state &= ~DEV_CONFIG_PENDING; 307 kfree(parse); 308 return; 309 310 cs_failed: 311 cs_error(link->handle, last_fn, last_ret); 312 failed: 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; 317 kfree(parse); 318 } 319 320 321 /* 322 * event callback 323 */ 324 static int vxpocket_event(event_t event, int priority, event_callback_args_t *args) 325 { 326 dev_link_t *link = args->client_data; 327 struct vx_core *chip = link->priv; 328 329 switch (event) { 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; 335 break; 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); 340 break; 341 #ifdef CONFIG_PM 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); 348 } 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); 354 break; 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"); 361 if (DEV_OK(link)) { 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); 368 } 369 } 370 snd_printdd(KERN_DEBUG "resume done!\n"); 371 break; 372 #endif 373 } 374 return 0; 375 } 376 377 378 /* 379 */ 380 static dev_link_t *vxpocket_attach(void) 381 { 382 struct snd_card *card; 383 struct snd_vxpocket *vxp; 384 int i; 385 386 /* find an empty slot from the card list */ 387 for (i = 0; i < SNDRV_CARDS; i++) { 388 if (! card_alloc & (1 << i)) 389 break; 390 } 391 if (i >= SNDRV_CARDS) { 392 snd_printk(KERN_ERR "vxpocket: too many cards found\n"); 393 return NULL; 394 } 395 if (! enable[i]) 396 return NULL; /* disabled explicitly */ 397 398 /* ok, create a card instance */ 399 card = snd_card_new(index[i], id[i], THIS_MODULE, 0); 400 if (card == NULL) { 401 snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n"); 402 return NULL; 403 } 404 405 vxp = snd_vxpocket_new(card, ibl[i]); 406 if (! vxp) { 407 snd_card_free(card); 408 return NULL; 409 } 410 411 vxp->index = i; 412 card_alloc |= 1 << i; 413 414 /* Chain drivers */ 415 vxp->link.next = dev_list; 416 dev_list = &vxp->link; 417 418 return &vxp->link; 419 } 420 421 static void vxpocket_detach(dev_link_t *link) 422 { 423 struct snd_vxpocket *vxp; 424 struct vx_core *chip; 425 dev_link_t **linkp; 426 427 if (! link) 428 return; 429 430 vxp = link->priv; 431 chip = (struct vx_core *)vxp; 432 card_alloc &= ~(1 << vxp->index); 433 434 /* Remove the interface data from the linked list */ 435 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) 436 if (*linkp == link) { 437 *linkp = link->next; 438 break; 439 } 440 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); 445 } 446 447 /* 448 * Module entry points 449 */ 450 451 static struct pcmcia_device_id vxp_ids[] = { 452 PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100), 453 PCMCIA_DEVICE_NULL 454 }; 455 MODULE_DEVICE_TABLE(pcmcia, vxp_ids); 456 457 static struct pcmcia_driver vxp_cs_driver = { 458 .owner = THIS_MODULE, 459 .drv = { 460 .name = "snd-vxpocket", 461 }, 462 .attach = vxpocket_attach, 463 .detach = vxpocket_detach, 464 .event = vxpocket_event, 465 .id_table = vxp_ids, 466 }; 467 468 static int __init init_vxpocket(void) 469 { 470 return pcmcia_register_driver(&vxp_cs_driver); 471 } 472 473 static void __exit exit_vxpocket(void) 474 { 475 pcmcia_unregister_driver(&vxp_cs_driver); 476 BUG_ON(dev_list != NULL); 477 } 478 479 module_init(init_vxpocket); 480 module_exit(exit_vxpocket); 481