1 /* 2 * Driver for Sound Core PDAudioCF soundcard 3 * 4 * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz> 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 #include <sound/driver.h> 22 #include <sound/core.h> 23 #include <linux/slab.h> 24 #include <linux/moduleparam.h> 25 #include <pcmcia/version.h> 26 #include <pcmcia/ciscode.h> 27 #include <pcmcia/cisreg.h> 28 #include "pdaudiocf.h" 29 #include <sound/initval.h> 30 #include <linux/init.h> 31 32 /* 33 */ 34 35 #define CARD_NAME "PDAudio-CF" 36 37 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 38 MODULE_DESCRIPTION("Sound Core " CARD_NAME); 39 MODULE_LICENSE("GPL"); 40 MODULE_SUPPORTED_DEVICE("{{Sound Core," CARD_NAME "}}"); 41 42 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 43 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 44 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */ 45 46 module_param_array(index, int, NULL, 0444); 47 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); 48 module_param_array(id, charp, NULL, 0444); 49 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); 50 module_param_array(enable, bool, NULL, 0444); 51 MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); 52 53 /* 54 */ 55 56 static dev_info_t dev_info = "snd-pdaudiocf"; 57 static snd_card_t *card_list[SNDRV_CARDS]; 58 static dev_link_t *dev_list; 59 60 /* 61 * prototypes 62 */ 63 static void pdacf_config(dev_link_t *link); 64 static int pdacf_event(event_t event, int priority, event_callback_args_t *args); 65 static void snd_pdacf_detach(dev_link_t *link); 66 67 static void pdacf_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 } 77 78 /* 79 * destructor 80 */ 81 static int snd_pdacf_free(pdacf_t *pdacf) 82 { 83 dev_link_t *link = &pdacf->link; 84 85 pdacf_release(link); 86 87 /* Break the link with Card Services */ 88 if (link->handle) 89 pcmcia_deregister_client(link->handle); 90 91 card_list[pdacf->index] = NULL; 92 pdacf->card = NULL; 93 94 kfree(pdacf); 95 return 0; 96 } 97 98 static int snd_pdacf_dev_free(snd_device_t *device) 99 { 100 pdacf_t *chip = device->device_data; 101 return snd_pdacf_free(chip); 102 } 103 104 /* 105 * snd_pdacf_attach - attach callback for cs 106 */ 107 static dev_link_t *snd_pdacf_attach(void) 108 { 109 client_reg_t client_reg; /* Register with cardmgr */ 110 dev_link_t *link; /* Info for cardmgr */ 111 int i, ret; 112 pdacf_t *pdacf; 113 snd_card_t *card; 114 static snd_device_ops_t ops = { 115 .dev_free = snd_pdacf_dev_free, 116 }; 117 118 snd_printdd(KERN_DEBUG "pdacf_attach called\n"); 119 /* find an empty slot from the card list */ 120 for (i = 0; i < SNDRV_CARDS; i++) { 121 if (! card_list[i]) 122 break; 123 } 124 if (i >= SNDRV_CARDS) { 125 snd_printk(KERN_ERR "pdacf: too many cards found\n"); 126 return NULL; 127 } 128 if (! enable[i]) 129 return NULL; /* disabled explicitly */ 130 131 /* ok, create a card instance */ 132 card = snd_card_new(index[i], id[i], THIS_MODULE, 0); 133 if (card == NULL) { 134 snd_printk(KERN_ERR "pdacf: cannot create a card instance\n"); 135 return NULL; 136 } 137 138 pdacf = snd_pdacf_create(card); 139 if (! pdacf) 140 return NULL; 141 142 if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops) < 0) { 143 kfree(pdacf); 144 snd_card_free(card); 145 return NULL; 146 } 147 148 pdacf->index = i; 149 card_list[i] = card; 150 151 link = &pdacf->link; 152 link->priv = pdacf; 153 154 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; 155 link->io.NumPorts1 = 16; 156 157 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT | IRQ_FORCED_PULSE; 158 // link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; 159 160 link->irq.IRQInfo1 = 0 /* | IRQ_LEVEL_ID */; 161 link->irq.Handler = pdacf_interrupt; 162 link->irq.Instance = pdacf; 163 link->conf.Attributes = CONF_ENABLE_IRQ; 164 link->conf.IntType = INT_MEMORY_AND_IO; 165 link->conf.ConfigIndex = 1; 166 link->conf.Present = PRESENT_OPTION; 167 168 /* Chain drivers */ 169 link->next = dev_list; 170 dev_list = link; 171 172 /* Register with Card Services */ 173 client_reg.dev_info = &dev_info; 174 client_reg.EventMask = 175 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL 176 #ifdef CONFIG_PM 177 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET 178 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME 179 #endif 180 ; 181 client_reg.event_handler = &pdacf_event; 182 client_reg.Version = 0x0210; 183 client_reg.event_callback_args.client_data = link; 184 185 ret = pcmcia_register_client(&link->handle, &client_reg); 186 if (ret != CS_SUCCESS) { 187 cs_error(link->handle, RegisterClient, ret); 188 snd_pdacf_detach(link); 189 return NULL; 190 } 191 192 return link; 193 } 194 195 196 /** 197 * snd_pdacf_assign_resources - initialize the hardware and card instance. 198 * @port: i/o port for the card 199 * @irq: irq number for the card 200 * 201 * this function assigns the specified port and irq, boot the card, 202 * create pcm and control instances, and initialize the rest hardware. 203 * 204 * returns 0 if successful, or a negative error code. 205 */ 206 static int snd_pdacf_assign_resources(pdacf_t *pdacf, int port, int irq) 207 { 208 int err; 209 snd_card_t *card = pdacf->card; 210 211 snd_printdd(KERN_DEBUG "pdacf assign resources: port = 0x%x, irq = %d\n", port, irq); 212 pdacf->port = port; 213 pdacf->irq = irq; 214 pdacf->chip_status |= PDAUDIOCF_STAT_IS_CONFIGURED; 215 216 err = snd_pdacf_ak4117_create(pdacf); 217 if (err < 0) 218 return err; 219 220 strcpy(card->driver, "PDAudio-CF"); 221 sprintf(card->shortname, "Core Sound %s", card->driver); 222 sprintf(card->longname, "%s at 0x%x, irq %i", 223 card->shortname, port, irq); 224 225 err = snd_pdacf_pcm_new(pdacf); 226 if (err < 0) 227 return err; 228 229 snd_card_set_pm_callback(card, snd_pdacf_suspend, snd_pdacf_resume, pdacf); 230 231 if ((err = snd_card_register(card)) < 0) 232 return err; 233 234 return 0; 235 } 236 237 238 /* 239 * snd_pdacf_detach - detach callback for cs 240 */ 241 static void snd_pdacf_detach(dev_link_t *link) 242 { 243 pdacf_t *chip = link->priv; 244 245 snd_printdd(KERN_DEBUG "pdacf_detach called\n"); 246 /* Remove the interface data from the linked list */ 247 { 248 dev_link_t **linkp; 249 /* Locate device structure */ 250 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) 251 if (*linkp == link) 252 break; 253 if (*linkp) 254 *linkp = link->next; 255 } 256 if (chip->chip_status & PDAUDIOCF_STAT_IS_CONFIGURED) 257 snd_pdacf_powerdown(chip); 258 chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */ 259 snd_card_disconnect(chip->card); 260 snd_card_free_in_thread(chip->card); 261 } 262 263 /* 264 * configuration callback 265 */ 266 267 #define CS_CHECK(fn, ret) \ 268 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) 269 270 static void pdacf_config(dev_link_t *link) 271 { 272 client_handle_t handle = link->handle; 273 pdacf_t *pdacf = link->priv; 274 tuple_t tuple; 275 cisparse_t *parse = NULL; 276 config_info_t conf; 277 u_short buf[32]; 278 int last_fn, last_ret; 279 280 snd_printdd(KERN_DEBUG "pdacf_config called\n"); 281 parse = kmalloc(sizeof(*parse), GFP_KERNEL); 282 if (! parse) { 283 snd_printk(KERN_ERR "pdacf_config: cannot allocate\n"); 284 return; 285 } 286 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 287 tuple.Attributes = 0; 288 tuple.TupleData = (cisdata_t *)buf; 289 tuple.TupleDataMax = sizeof(buf); 290 tuple.TupleOffset = 0; 291 tuple.DesiredTuple = CISTPL_CONFIG; 292 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); 293 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); 294 CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse)); 295 link->conf.ConfigBase = parse->config.base; 296 link->conf.ConfigIndex = 0x5; 297 kfree(parse); 298 299 CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); 300 link->conf.Vcc = conf.Vcc; 301 302 /* Configure card */ 303 link->state |= DEV_CONFIG; 304 305 CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io)); 306 CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); 307 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); 308 309 if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0) 310 goto failed; 311 312 link->dev = &pdacf->node; 313 link->state &= ~DEV_CONFIG_PENDING; 314 return; 315 316 cs_failed: 317 cs_error(link->handle, last_fn, last_ret); 318 failed: 319 pcmcia_release_configuration(link->handle); 320 pcmcia_release_io(link->handle, &link->io); 321 pcmcia_release_irq(link->handle, &link->irq); 322 } 323 324 /* 325 * event callback 326 */ 327 static int pdacf_event(event_t event, int priority, event_callback_args_t *args) 328 { 329 dev_link_t *link = args->client_data; 330 pdacf_t *chip = link->priv; 331 332 switch (event) { 333 case CS_EVENT_CARD_REMOVAL: 334 snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n"); 335 link->state &= ~DEV_PRESENT; 336 if (link->state & DEV_CONFIG) { 337 chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; 338 } 339 break; 340 case CS_EVENT_CARD_INSERTION: 341 snd_printdd(KERN_DEBUG "CARD_INSERTION..\n"); 342 link->state |= DEV_PRESENT; 343 pdacf_config(link); 344 break; 345 #ifdef CONFIG_PM 346 case CS_EVENT_PM_SUSPEND: 347 snd_printdd(KERN_DEBUG "SUSPEND\n"); 348 link->state |= DEV_SUSPEND; 349 if (chip) { 350 snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n"); 351 snd_pdacf_suspend(chip->card, PMSG_SUSPEND); 352 } 353 /* Fall through... */ 354 case CS_EVENT_RESET_PHYSICAL: 355 snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n"); 356 if (link->state & DEV_CONFIG) 357 pcmcia_release_configuration(link->handle); 358 break; 359 case CS_EVENT_PM_RESUME: 360 snd_printdd(KERN_DEBUG "RESUME\n"); 361 link->state &= ~DEV_SUSPEND; 362 /* Fall through... */ 363 case CS_EVENT_CARD_RESET: 364 snd_printdd(KERN_DEBUG "CARD_RESET\n"); 365 if (DEV_OK(link)) { 366 snd_printdd(KERN_DEBUG "requestconfig...\n"); 367 pcmcia_request_configuration(link->handle, &link->conf); 368 if (chip) { 369 snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n"); 370 snd_pdacf_resume(chip->card); 371 } 372 } 373 snd_printdd(KERN_DEBUG "resume done!\n"); 374 break; 375 #endif 376 } 377 return 0; 378 } 379 380 /* 381 * Module entry points 382 */ 383 static struct pcmcia_driver pdacf_cs_driver = { 384 .owner = THIS_MODULE, 385 .drv = { 386 .name = "snd-pdaudiocf", 387 }, 388 .attach = snd_pdacf_attach, 389 .detach = snd_pdacf_detach 390 }; 391 392 static int __init init_pdacf(void) 393 { 394 return pcmcia_register_driver(&pdacf_cs_driver); 395 } 396 397 static void __exit exit_pdacf(void) 398 { 399 pcmcia_unregister_driver(&pdacf_cs_driver); 400 BUG_ON(dev_list != NULL); 401 } 402 403 module_init(init_pdacf); 404 module_exit(exit_pdacf); 405