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