galaxy.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. /*
  2. * Aztech AZT1605/AZT2316 Driver
  3. * Copyright (C) 2007,2010 Rene Herman
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. #include <linux/kernel.h>
  20. #include <linux/module.h>
  21. #include <linux/isa.h>
  22. #include <linux/delay.h>
  23. #include <linux/io.h>
  24. #include <asm/processor.h>
  25. #include <sound/core.h>
  26. #include <sound/initval.h>
  27. #include <sound/wss.h>
  28. #include <sound/mpu401.h>
  29. #include <sound/opl3.h>
  30. MODULE_DESCRIPTION(CRD_NAME);
  31. MODULE_AUTHOR("Rene Herman");
  32. MODULE_LICENSE("GPL");
  33. static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
  34. static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
  35. static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
  36. module_param_array(index, int, NULL, 0444);
  37. MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
  38. module_param_array(id, charp, NULL, 0444);
  39. MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
  40. module_param_array(enable, bool, NULL, 0444);
  41. MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
  42. static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  43. static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  44. static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  45. static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  46. static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
  47. static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
  48. static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
  49. static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
  50. module_param_array(port, long, NULL, 0444);
  51. MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
  52. module_param_array(wss_port, long, NULL, 0444);
  53. MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
  54. module_param_array(mpu_port, long, NULL, 0444);
  55. MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
  56. module_param_array(fm_port, long, NULL, 0444);
  57. MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
  58. module_param_array(irq, int, NULL, 0444);
  59. MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
  60. module_param_array(mpu_irq, int, NULL, 0444);
  61. MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
  62. module_param_array(dma1, int, NULL, 0444);
  63. MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
  64. module_param_array(dma2, int, NULL, 0444);
  65. MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
  66. /*
  67. * Generic SB DSP support routines
  68. */
  69. #define DSP_PORT_RESET 0x6
  70. #define DSP_PORT_READ 0xa
  71. #define DSP_PORT_COMMAND 0xc
  72. #define DSP_PORT_STATUS 0xc
  73. #define DSP_PORT_DATA_AVAIL 0xe
  74. #define DSP_SIGNATURE 0xaa
  75. #define DSP_COMMAND_GET_VERSION 0xe1
  76. static int dsp_get_byte(void __iomem *port, u8 *val)
  77. {
  78. int loops = 1000;
  79. while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
  80. if (!loops--)
  81. return -EIO;
  82. cpu_relax();
  83. }
  84. *val = ioread8(port + DSP_PORT_READ);
  85. return 0;
  86. }
  87. static int dsp_reset(void __iomem *port)
  88. {
  89. u8 val;
  90. iowrite8(1, port + DSP_PORT_RESET);
  91. udelay(10);
  92. iowrite8(0, port + DSP_PORT_RESET);
  93. if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
  94. return -ENODEV;
  95. return 0;
  96. }
  97. static int dsp_command(void __iomem *port, u8 cmd)
  98. {
  99. int loops = 1000;
  100. while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
  101. if (!loops--)
  102. return -EIO;
  103. cpu_relax();
  104. }
  105. iowrite8(cmd, port + DSP_PORT_COMMAND);
  106. return 0;
  107. }
  108. static int dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
  109. {
  110. int err;
  111. err = dsp_command(port, DSP_COMMAND_GET_VERSION);
  112. if (err < 0)
  113. return err;
  114. err = dsp_get_byte(port, major);
  115. if (err < 0)
  116. return err;
  117. err = dsp_get_byte(port, minor);
  118. if (err < 0)
  119. return err;
  120. return 0;
  121. }
  122. /*
  123. * Generic WSS support routines
  124. */
  125. #define WSS_CONFIG_DMA_0 (1 << 0)
  126. #define WSS_CONFIG_DMA_1 (2 << 0)
  127. #define WSS_CONFIG_DMA_3 (3 << 0)
  128. #define WSS_CONFIG_DUPLEX (1 << 2)
  129. #define WSS_CONFIG_IRQ_7 (1 << 3)
  130. #define WSS_CONFIG_IRQ_9 (2 << 3)
  131. #define WSS_CONFIG_IRQ_10 (3 << 3)
  132. #define WSS_CONFIG_IRQ_11 (4 << 3)
  133. #define WSS_PORT_CONFIG 0
  134. #define WSS_PORT_SIGNATURE 3
  135. #define WSS_SIGNATURE 4
  136. static int wss_detect(void __iomem *wss_port)
  137. {
  138. if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
  139. return -ENODEV;
  140. return 0;
  141. }
  142. static void wss_set_config(void __iomem *wss_port, u8 wss_config)
  143. {
  144. iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
  145. }
  146. /*
  147. * Aztech Sound Galaxy specifics
  148. */
  149. #define GALAXY_PORT_CONFIG 1024
  150. #define CONFIG_PORT_SET 4
  151. #define DSP_COMMAND_GALAXY_8 8
  152. #define GALAXY_COMMAND_GET_TYPE 5
  153. #define DSP_COMMAND_GALAXY_9 9
  154. #define GALAXY_COMMAND_WSSMODE 0
  155. #define GALAXY_COMMAND_SB8MODE 1
  156. #define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE
  157. #define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE
  158. struct snd_galaxy {
  159. void __iomem *port;
  160. void __iomem *config_port;
  161. void __iomem *wss_port;
  162. u32 config;
  163. struct resource *res_port;
  164. struct resource *res_config_port;
  165. struct resource *res_wss_port;
  166. };
  167. static u32 config[SNDRV_CARDS];
  168. static u8 wss_config[SNDRV_CARDS];
  169. static int snd_galaxy_match(struct device *dev, unsigned int n)
  170. {
  171. if (!enable[n])
  172. return 0;
  173. switch (port[n]) {
  174. case SNDRV_AUTO_PORT:
  175. dev_err(dev, "please specify port\n");
  176. return 0;
  177. case 0x220:
  178. config[n] |= GALAXY_CONFIG_SBA_220;
  179. break;
  180. case 0x240:
  181. config[n] |= GALAXY_CONFIG_SBA_240;
  182. break;
  183. case 0x260:
  184. config[n] |= GALAXY_CONFIG_SBA_260;
  185. break;
  186. case 0x280:
  187. config[n] |= GALAXY_CONFIG_SBA_280;
  188. break;
  189. default:
  190. dev_err(dev, "invalid port %#lx\n", port[n]);
  191. return 0;
  192. }
  193. switch (wss_port[n]) {
  194. case SNDRV_AUTO_PORT:
  195. dev_err(dev, "please specify wss_port\n");
  196. return 0;
  197. case 0x530:
  198. config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
  199. break;
  200. case 0x604:
  201. config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
  202. break;
  203. case 0xe80:
  204. config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
  205. break;
  206. case 0xf40:
  207. config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
  208. break;
  209. default:
  210. dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
  211. return 0;
  212. }
  213. switch (irq[n]) {
  214. case SNDRV_AUTO_IRQ:
  215. dev_err(dev, "please specify irq\n");
  216. return 0;
  217. case 7:
  218. wss_config[n] |= WSS_CONFIG_IRQ_7;
  219. break;
  220. case 2:
  221. irq[n] = 9;
  222. case 9:
  223. wss_config[n] |= WSS_CONFIG_IRQ_9;
  224. break;
  225. case 10:
  226. wss_config[n] |= WSS_CONFIG_IRQ_10;
  227. break;
  228. case 11:
  229. wss_config[n] |= WSS_CONFIG_IRQ_11;
  230. break;
  231. default:
  232. dev_err(dev, "invalid IRQ %d\n", irq[n]);
  233. return 0;
  234. }
  235. switch (dma1[n]) {
  236. case SNDRV_AUTO_DMA:
  237. dev_err(dev, "please specify dma1\n");
  238. return 0;
  239. case 0:
  240. wss_config[n] |= WSS_CONFIG_DMA_0;
  241. break;
  242. case 1:
  243. wss_config[n] |= WSS_CONFIG_DMA_1;
  244. break;
  245. case 3:
  246. wss_config[n] |= WSS_CONFIG_DMA_3;
  247. break;
  248. default:
  249. dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
  250. return 0;
  251. }
  252. if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
  253. dma2[n] = -1;
  254. goto mpu;
  255. }
  256. wss_config[n] |= WSS_CONFIG_DUPLEX;
  257. switch (dma2[n]) {
  258. case 0:
  259. break;
  260. case 1:
  261. if (dma1[n] == 0)
  262. break;
  263. default:
  264. dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
  265. return 0;
  266. }
  267. mpu:
  268. switch (mpu_port[n]) {
  269. case SNDRV_AUTO_PORT:
  270. dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
  271. mpu_port[n] = -1;
  272. goto fm;
  273. case 0x300:
  274. config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
  275. break;
  276. case 0x330:
  277. config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
  278. break;
  279. default:
  280. dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
  281. return 0;
  282. }
  283. switch (mpu_irq[n]) {
  284. case SNDRV_AUTO_IRQ:
  285. dev_warn(dev, "mpu_irq not specified: using polling mode\n");
  286. mpu_irq[n] = -1;
  287. break;
  288. case 2:
  289. mpu_irq[n] = 9;
  290. case 9:
  291. config[n] |= GALAXY_CONFIG_MPUIRQ_2;
  292. break;
  293. #ifdef AZT1605
  294. case 3:
  295. config[n] |= GALAXY_CONFIG_MPUIRQ_3;
  296. break;
  297. #endif
  298. case 5:
  299. config[n] |= GALAXY_CONFIG_MPUIRQ_5;
  300. break;
  301. case 7:
  302. config[n] |= GALAXY_CONFIG_MPUIRQ_7;
  303. break;
  304. #ifdef AZT2316
  305. case 10:
  306. config[n] |= GALAXY_CONFIG_MPUIRQ_10;
  307. break;
  308. #endif
  309. default:
  310. dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
  311. return 0;
  312. }
  313. if (mpu_irq[n] == irq[n]) {
  314. dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
  315. return 0;
  316. }
  317. fm:
  318. switch (fm_port[n]) {
  319. case SNDRV_AUTO_PORT:
  320. dev_warn(dev, "fm_port not specified: not using OPL3\n");
  321. fm_port[n] = -1;
  322. break;
  323. case 0x388:
  324. break;
  325. default:
  326. dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
  327. return 0;
  328. }
  329. config[n] |= GALAXY_CONFIG_GAME_ENABLE;
  330. return 1;
  331. }
  332. static int galaxy_init(struct snd_galaxy *galaxy, u8 *type)
  333. {
  334. u8 major;
  335. u8 minor;
  336. int err;
  337. err = dsp_reset(galaxy->port);
  338. if (err < 0)
  339. return err;
  340. err = dsp_get_version(galaxy->port, &major, &minor);
  341. if (err < 0)
  342. return err;
  343. if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
  344. return -ENODEV;
  345. err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
  346. if (err < 0)
  347. return err;
  348. err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
  349. if (err < 0)
  350. return err;
  351. err = dsp_get_byte(galaxy->port, type);
  352. if (err < 0)
  353. return err;
  354. return 0;
  355. }
  356. static int galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
  357. {
  358. int err;
  359. err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
  360. if (err < 0)
  361. return err;
  362. err = dsp_command(galaxy->port, mode);
  363. if (err < 0)
  364. return err;
  365. #ifdef AZT1605
  366. /*
  367. * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
  368. */
  369. err = dsp_reset(galaxy->port);
  370. if (err < 0)
  371. return err;
  372. #endif
  373. return 0;
  374. }
  375. static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
  376. {
  377. u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
  378. int i;
  379. iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
  380. for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
  381. iowrite8(config, galaxy->config_port + i);
  382. config >>= 8;
  383. }
  384. iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
  385. msleep(10);
  386. }
  387. static void galaxy_config(struct snd_galaxy *galaxy, u32 config)
  388. {
  389. int i;
  390. for (i = GALAXY_CONFIG_SIZE; i; i--) {
  391. u8 tmp = ioread8(galaxy->config_port + i - 1);
  392. galaxy->config = (galaxy->config << 8) | tmp;
  393. }
  394. config |= galaxy->config & GALAXY_CONFIG_MASK;
  395. galaxy_set_config(galaxy, config);
  396. }
  397. static int galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
  398. {
  399. int err;
  400. err = wss_detect(galaxy->wss_port);
  401. if (err < 0)
  402. return err;
  403. wss_set_config(galaxy->wss_port, wss_config);
  404. err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
  405. if (err < 0)
  406. return err;
  407. return 0;
  408. }
  409. static void snd_galaxy_free(struct snd_card *card)
  410. {
  411. struct snd_galaxy *galaxy = card->private_data;
  412. if (galaxy->wss_port) {
  413. wss_set_config(galaxy->wss_port, 0);
  414. ioport_unmap(galaxy->wss_port);
  415. release_and_free_resource(galaxy->res_wss_port);
  416. }
  417. if (galaxy->config_port) {
  418. galaxy_set_config(galaxy, galaxy->config);
  419. ioport_unmap(galaxy->config_port);
  420. release_and_free_resource(galaxy->res_config_port);
  421. }
  422. if (galaxy->port) {
  423. ioport_unmap(galaxy->port);
  424. release_and_free_resource(galaxy->res_port);
  425. }
  426. }
  427. static int snd_galaxy_probe(struct device *dev, unsigned int n)
  428. {
  429. struct snd_galaxy *galaxy;
  430. struct snd_wss *chip;
  431. struct snd_card *card;
  432. u8 type;
  433. int err;
  434. err = snd_card_new(dev, index[n], id[n], THIS_MODULE,
  435. sizeof(*galaxy), &card);
  436. if (err < 0)
  437. return err;
  438. card->private_free = snd_galaxy_free;
  439. galaxy = card->private_data;
  440. galaxy->res_port = request_region(port[n], 16, DRV_NAME);
  441. if (!galaxy->res_port) {
  442. dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
  443. port[n] + 15);
  444. err = -EBUSY;
  445. goto error;
  446. }
  447. galaxy->port = ioport_map(port[n], 16);
  448. err = galaxy_init(galaxy, &type);
  449. if (err < 0) {
  450. dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
  451. goto error;
  452. }
  453. dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
  454. galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
  455. 16, DRV_NAME);
  456. if (!galaxy->res_config_port) {
  457. dev_err(dev, "could not grab ports %#lx-%#lx\n",
  458. port[n] + GALAXY_PORT_CONFIG,
  459. port[n] + GALAXY_PORT_CONFIG + 15);
  460. err = -EBUSY;
  461. goto error;
  462. }
  463. galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
  464. galaxy_config(galaxy, config[n]);
  465. galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
  466. if (!galaxy->res_wss_port) {
  467. dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
  468. wss_port[n] + 3);
  469. err = -EBUSY;
  470. goto error;
  471. }
  472. galaxy->wss_port = ioport_map(wss_port[n], 4);
  473. err = galaxy_wss_config(galaxy, wss_config[n]);
  474. if (err < 0) {
  475. dev_err(dev, "could not configure WSS\n");
  476. goto error;
  477. }
  478. strcpy(card->driver, DRV_NAME);
  479. strcpy(card->shortname, DRV_NAME);
  480. sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
  481. card->shortname, port[n], wss_port[n], irq[n], dma1[n],
  482. dma2[n]);
  483. err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
  484. dma2[n], WSS_HW_DETECT, 0, &chip);
  485. if (err < 0)
  486. goto error;
  487. err = snd_wss_pcm(chip, 0);
  488. if (err < 0)
  489. goto error;
  490. err = snd_wss_mixer(chip);
  491. if (err < 0)
  492. goto error;
  493. err = snd_wss_timer(chip, 0);
  494. if (err < 0)
  495. goto error;
  496. if (mpu_port[n] >= 0) {
  497. err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
  498. mpu_port[n], 0, mpu_irq[n], NULL);
  499. if (err < 0)
  500. goto error;
  501. }
  502. if (fm_port[n] >= 0) {
  503. struct snd_opl3 *opl3;
  504. err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
  505. OPL3_HW_AUTO, 0, &opl3);
  506. if (err < 0) {
  507. dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
  508. goto error;
  509. }
  510. err = snd_opl3_timer_new(opl3, 1, 2);
  511. if (err < 0)
  512. goto error;
  513. err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
  514. if (err < 0)
  515. goto error;
  516. }
  517. err = snd_card_register(card);
  518. if (err < 0)
  519. goto error;
  520. dev_set_drvdata(dev, card);
  521. return 0;
  522. error:
  523. snd_card_free(card);
  524. return err;
  525. }
  526. static int snd_galaxy_remove(struct device *dev, unsigned int n)
  527. {
  528. snd_card_free(dev_get_drvdata(dev));
  529. return 0;
  530. }
  531. static struct isa_driver snd_galaxy_driver = {
  532. .match = snd_galaxy_match,
  533. .probe = snd_galaxy_probe,
  534. .remove = snd_galaxy_remove,
  535. .driver = {
  536. .name = DEV_NAME
  537. }
  538. };
  539. static int __init alsa_card_galaxy_init(void)
  540. {
  541. return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
  542. }
  543. static void __exit alsa_card_galaxy_exit(void)
  544. {
  545. isa_unregister_driver(&snd_galaxy_driver);
  546. }
  547. module_init(alsa_card_galaxy_init);
  548. module_exit(alsa_card_galaxy_exit);