diff options
| author | Takashi Iwai <tiwai@suse.de> | 2010-10-25 03:56:32 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2010-10-25 03:56:32 -0400 |
| commit | 79fc84c7e0d2fe89c4e82f3a26fd8b0d13c31703 (patch) | |
| tree | e32a4c267dc1b5950012e18c1e71d8057140f1f5 | |
| parent | f6f94e2ab1b33f0082ac22d71f66385a60d8157f (diff) | |
| parent | 97c44b2dbd0060e2e6bd56236eb638ab02ec7f30 (diff) | |
Merge branch 'topic/misc' into for-linus
81 files changed, 3611 insertions, 1123 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 7f4dcebda9c6..d0eb696d32e8 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
| @@ -300,6 +300,74 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 300 | control correctly. If you have problems regarding this, try | 300 | control correctly. If you have problems regarding this, try |
| 301 | another ALSA compliant mixer (alsamixer works). | 301 | another ALSA compliant mixer (alsamixer works). |
| 302 | 302 | ||
| 303 | Module snd-azt1605 | ||
| 304 | ------------------ | ||
| 305 | |||
| 306 | Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605 | ||
| 307 | chipset. | ||
| 308 | |||
| 309 | port - port # for BASE (0x220,0x240,0x260,0x280) | ||
| 310 | wss_port - port # for WSS (0x530,0x604,0xe80,0xf40) | ||
| 311 | irq - IRQ # for WSS (7,9,10,11) | ||
| 312 | dma1 - DMA # for WSS playback (0,1,3) | ||
| 313 | dma2 - DMA # for WSS capture (0,1), -1 = disabled (default) | ||
| 314 | mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default) | ||
| 315 | mpu_irq - IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default) | ||
| 316 | fm_port - port # for OPL3 (0x388), -1 = disabled (default) | ||
| 317 | |||
| 318 | This module supports multiple cards. It does not support autoprobe: port, | ||
| 319 | wss_port, irq and dma1 have to be specified. The other values are | ||
| 320 | optional. | ||
| 321 | |||
| 322 | "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240) | ||
| 323 | or the value stored in the card's EEPROM for cards that have an EEPROM and | ||
| 324 | their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can | ||
| 325 | be choosen freely from the options enumerated above. | ||
| 326 | |||
| 327 | If dma2 is specified and different from dma1, the card will operate in | ||
| 328 | full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to | ||
| 329 | enable capture since only channels 0 and 1 are available for capture. | ||
| 330 | |||
| 331 | Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0 | ||
| 332 | mpu_port=0x330 mpu_irq=9 fm_port=0x388". | ||
| 333 | |||
| 334 | Whatever IRQ and DMA channels you pick, be sure to reserve them for | ||
| 335 | legacy ISA in your BIOS. | ||
| 336 | |||
| 337 | Module snd-azt2316 | ||
| 338 | ------------------ | ||
| 339 | |||
| 340 | Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316 | ||
| 341 | chipset. | ||
| 342 | |||
| 343 | port - port # for BASE (0x220,0x240,0x260,0x280) | ||
| 344 | wss_port - port # for WSS (0x530,0x604,0xe80,0xf40) | ||
| 345 | irq - IRQ # for WSS (7,9,10,11) | ||
| 346 | dma1 - DMA # for WSS playback (0,1,3) | ||
| 347 | dma2 - DMA # for WSS capture (0,1), -1 = disabled (default) | ||
| 348 | mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default) | ||
| 349 | mpu_irq - IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default) | ||
| 350 | fm_port - port # for OPL3 (0x388), -1 = disabled (default) | ||
| 351 | |||
| 352 | This module supports multiple cards. It does not support autoprobe: port, | ||
| 353 | wss_port, irq and dma1 have to be specified. The other values are | ||
| 354 | optional. | ||
| 355 | |||
| 356 | "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240) | ||
| 357 | or the value stored in the card's EEPROM for cards that have an EEPROM and | ||
| 358 | their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can | ||
| 359 | be choosen freely from the options enumerated above. | ||
| 360 | |||
| 361 | If dma2 is specified and different from dma1, the card will operate in | ||
| 362 | full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to | ||
| 363 | enable capture since only channels 0 and 1 are available for capture. | ||
| 364 | |||
| 365 | Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0 | ||
| 366 | mpu_port=0x330 mpu_irq=9 fm_port=0x388". | ||
| 367 | |||
| 368 | Whatever IRQ and DMA channels you pick, be sure to reserve them for | ||
| 369 | legacy ISA in your BIOS. | ||
| 370 | |||
| 303 | Module snd-aw2 | 371 | Module snd-aw2 |
| 304 | -------------- | 372 | -------------- |
| 305 | 373 | ||
| @@ -1641,20 +1709,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 1641 | 1709 | ||
| 1642 | This card is also known as Audio Excel DSP 16 or Zoltrix AV302. | 1710 | This card is also known as Audio Excel DSP 16 or Zoltrix AV302. |
| 1643 | 1711 | ||
| 1644 | Module snd-sgalaxy | ||
| 1645 | ------------------ | ||
| 1646 | |||
| 1647 | Module for Aztech Sound Galaxy sound card. | ||
| 1648 | |||
| 1649 | sbport - Port # for SB16 interface (0x220,0x240) | ||
| 1650 | wssport - Port # for WSS interface (0x530,0xe80,0xf40,0x604) | ||
| 1651 | irq - IRQ # (7,9,10,11) | ||
| 1652 | dma1 - DMA # | ||
| 1653 | |||
| 1654 | This module supports multiple cards. | ||
| 1655 | |||
| 1656 | The power-management is supported. | ||
| 1657 | |||
| 1658 | Module snd-sscape | 1712 | Module snd-sscape |
| 1659 | ----------------- | 1713 | ----------------- |
| 1660 | 1714 | ||
diff --git a/include/sound/core.h b/include/sound/core.h index 89e0ac17f44a..c129f0813bae 100644 --- a/include/sound/core.h +++ b/include/sound/core.h | |||
| @@ -179,7 +179,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state); | |||
| 179 | #define snd_power_lock(card) do { (void)(card); } while (0) | 179 | #define snd_power_lock(card) do { (void)(card); } while (0) |
| 180 | #define snd_power_unlock(card) do { (void)(card); } while (0) | 180 | #define snd_power_unlock(card) do { (void)(card); } while (0) |
| 181 | static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; } | 181 | static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; } |
| 182 | #define snd_power_get_state(card) SNDRV_CTL_POWER_D0 | 182 | #define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; }) |
| 183 | #define snd_power_change_state(card, state) do { (void)(card); } while (0) | 183 | #define snd_power_change_state(card, state) do { (void)(card); } while (0) |
| 184 | 184 | ||
| 185 | #endif /* CONFIG_PM */ | 185 | #endif /* CONFIG_PM */ |
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 7dc97d12253c..4f865df42f0f 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h | |||
| @@ -438,6 +438,8 @@ | |||
| 438 | #define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */ | 438 | #define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */ |
| 439 | #define CCCA_CURRADDR 0x18000008 | 439 | #define CCCA_CURRADDR 0x18000008 |
| 440 | 440 | ||
| 441 | /* undefine CCR to avoid conflict with the definition for SH */ | ||
| 442 | #undef CCR | ||
| 441 | #define CCR 0x09 /* Cache control register */ | 443 | #define CCR 0x09 /* Cache control register */ |
| 442 | #define CCR_CACHEINVALIDSIZE 0x07190009 | 444 | #define CCR_CACHEINVALIDSIZE 0x07190009 |
| 443 | #define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */ | 445 | #define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */ |
diff --git a/include/sound/jack.h b/include/sound/jack.h index d90b9fa32707..c140fc7cbd3f 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h | |||
| @@ -47,6 +47,9 @@ enum snd_jack_types { | |||
| 47 | SND_JACK_BTN_0 = 0x4000, | 47 | SND_JACK_BTN_0 = 0x4000, |
| 48 | SND_JACK_BTN_1 = 0x2000, | 48 | SND_JACK_BTN_1 = 0x2000, |
| 49 | SND_JACK_BTN_2 = 0x1000, | 49 | SND_JACK_BTN_2 = 0x1000, |
| 50 | SND_JACK_BTN_3 = 0x0800, | ||
| 51 | SND_JACK_BTN_4 = 0x0400, | ||
| 52 | SND_JACK_BTN_5 = 0x0200, | ||
| 50 | }; | 53 | }; |
| 51 | 54 | ||
| 52 | struct snd_jack { | 55 | struct snd_jack { |
| @@ -55,7 +58,7 @@ struct snd_jack { | |||
| 55 | int type; | 58 | int type; |
| 56 | const char *id; | 59 | const char *id; |
| 57 | char name[100]; | 60 | char name[100]; |
| 58 | unsigned int key[3]; /* Keep in sync with definitions above */ | 61 | unsigned int key[6]; /* Keep in sync with definitions above */ |
| 59 | void *private_data; | 62 | void *private_data; |
| 60 | void (*private_free)(struct snd_jack *); | 63 | void (*private_free)(struct snd_jack *); |
| 61 | }; | 64 | }; |
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 85f1c6bf8566..dfd9b76b1853 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
| @@ -278,6 +278,7 @@ struct snd_pcm_runtime { | |||
| 278 | snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ | 278 | snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ |
| 279 | snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ | 279 | snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ |
| 280 | unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ | 280 | unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ |
| 281 | unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */ | ||
| 281 | snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ | 282 | snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ |
| 282 | 283 | ||
| 283 | /* -- HW params -- */ | 284 | /* -- HW params -- */ |
diff --git a/sound/core/init.c b/sound/core/init.c index ec4a50ce5656..2de45fbd70fb 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
| @@ -607,11 +607,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, | |||
| 607 | return -EEXIST; | 607 | return -EEXIST; |
| 608 | } | 608 | } |
| 609 | for (idx = 0; idx < snd_ecards_limit; idx++) { | 609 | for (idx = 0; idx < snd_ecards_limit; idx++) { |
| 610 | if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) | 610 | if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) { |
| 611 | goto __exist; | 611 | if (card == snd_cards[idx]) |
| 612 | goto __ok; | ||
| 613 | else | ||
| 614 | goto __exist; | ||
| 615 | } | ||
| 612 | } | 616 | } |
| 613 | strcpy(card->id, buf1); | 617 | strcpy(card->id, buf1); |
| 614 | snd_info_card_id_change(card); | 618 | snd_info_card_id_change(card); |
| 619 | __ok: | ||
| 615 | mutex_unlock(&snd_card_mutex); | 620 | mutex_unlock(&snd_card_mutex); |
| 616 | 621 | ||
| 617 | return count; | 622 | return count; |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index f50ebf20df96..822dd56993ca 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
| @@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file) | |||
| 77 | struct snd_mixer_oss_file *fmixer; | 77 | struct snd_mixer_oss_file *fmixer; |
| 78 | 78 | ||
| 79 | if (file->private_data) { | 79 | if (file->private_data) { |
| 80 | fmixer = (struct snd_mixer_oss_file *) file->private_data; | 80 | fmixer = file->private_data; |
| 81 | module_put(fmixer->card->module); | 81 | module_put(fmixer->card->module); |
| 82 | snd_card_file_remove(fmixer->card, file); | 82 | snd_card_file_remove(fmixer->card, file); |
| 83 | kfree(fmixer); | 83 | kfree(fmixer); |
| @@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int | |||
| 368 | 368 | ||
| 369 | static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 369 | static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 370 | { | 370 | { |
| 371 | return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg); | 371 | return snd_mixer_oss_ioctl1(file->private_data, cmd, arg); |
| 372 | } | 372 | } |
| 373 | 373 | ||
| 374 | int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) | 374 | int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) |
| @@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, | |||
| 582 | struct snd_mixer_oss_slot *pslot, | 582 | struct snd_mixer_oss_slot *pslot, |
| 583 | int *left, int *right) | 583 | int *left, int *right) |
| 584 | { | 584 | { |
| 585 | struct slot *slot = (struct slot *)pslot->private_data; | 585 | struct slot *slot = pslot->private_data; |
| 586 | 586 | ||
| 587 | *left = *right = 100; | 587 | *left = *right = 100; |
| 588 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { | 588 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { |
| @@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, | |||
| 618 | if (numid == ID_UNKNOWN) | 618 | if (numid == ID_UNKNOWN) |
| 619 | return; | 619 | return; |
| 620 | down_read(&card->controls_rwsem); | 620 | down_read(&card->controls_rwsem); |
| 621 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) | 621 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { |
| 622 | up_read(&card->controls_rwsem); | ||
| 622 | return; | 623 | return; |
| 624 | } | ||
| 623 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 625 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); |
| 624 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 626 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); |
| 625 | if (uinfo == NULL || uctl == NULL) | 627 | if (uinfo == NULL || uctl == NULL) |
| @@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, | |||
| 658 | return; | 660 | return; |
| 659 | down_read(&card->controls_rwsem); | 661 | down_read(&card->controls_rwsem); |
| 660 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { | 662 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { |
| 661 | up_read(&fmixer->card->controls_rwsem); | 663 | up_read(&card->controls_rwsem); |
| 662 | return; | 664 | return; |
| 663 | } | 665 | } |
| 664 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 666 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); |
| @@ -691,7 +693,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, | |||
| 691 | struct snd_mixer_oss_slot *pslot, | 693 | struct snd_mixer_oss_slot *pslot, |
| 692 | int left, int right) | 694 | int left, int right) |
| 693 | { | 695 | { |
| 694 | struct slot *slot = (struct slot *)pslot->private_data; | 696 | struct slot *slot = pslot->private_data; |
| 695 | 697 | ||
| 696 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { | 698 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { |
| 697 | snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); | 699 | snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); |
| @@ -740,7 +742,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer, | |||
| 740 | struct snd_mixer_oss_slot *pslot, | 742 | struct snd_mixer_oss_slot *pslot, |
| 741 | int *active) | 743 | int *active) |
| 742 | { | 744 | { |
| 743 | struct slot *slot = (struct slot *)pslot->private_data; | 745 | struct slot *slot = pslot->private_data; |
| 744 | int left, right; | 746 | int left, right; |
| 745 | 747 | ||
| 746 | left = right = 1; | 748 | left = right = 1; |
| @@ -753,7 +755,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer, | |||
| 753 | struct snd_mixer_oss_slot *pslot, | 755 | struct snd_mixer_oss_slot *pslot, |
| 754 | int *active) | 756 | int *active) |
| 755 | { | 757 | { |
| 756 | struct slot *slot = (struct slot *)pslot->private_data; | 758 | struct slot *slot = pslot->private_data; |
| 757 | int left, right; | 759 | int left, right; |
| 758 | 760 | ||
| 759 | left = right = 1; | 761 | left = right = 1; |
| @@ -766,7 +768,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer, | |||
| 766 | struct snd_mixer_oss_slot *pslot, | 768 | struct snd_mixer_oss_slot *pslot, |
| 767 | int active) | 769 | int active) |
| 768 | { | 770 | { |
| 769 | struct slot *slot = (struct slot *)pslot->private_data; | 771 | struct slot *slot = pslot->private_data; |
| 770 | 772 | ||
| 771 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); | 773 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); |
| 772 | return 0; | 774 | return 0; |
| @@ -776,7 +778,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer, | |||
| 776 | struct snd_mixer_oss_slot *pslot, | 778 | struct snd_mixer_oss_slot *pslot, |
| 777 | int active) | 779 | int active) |
| 778 | { | 780 | { |
| 779 | struct slot *slot = (struct slot *)pslot->private_data; | 781 | struct slot *slot = pslot->private_data; |
| 780 | 782 | ||
| 781 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); | 783 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); |
| 782 | return 0; | 784 | return 0; |
| @@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
| 797 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 799 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); |
| 798 | if (uinfo == NULL || uctl == NULL) { | 800 | if (uinfo == NULL || uctl == NULL) { |
| 799 | err = -ENOMEM; | 801 | err = -ENOMEM; |
| 800 | goto __unlock; | 802 | goto __free_only; |
| 801 | } | 803 | } |
| 802 | down_read(&card->controls_rwsem); | 804 | down_read(&card->controls_rwsem); |
| 803 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); | 805 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); |
| @@ -813,7 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
| 813 | if (!(mixer->mask_recsrc & (1 << idx))) | 815 | if (!(mixer->mask_recsrc & (1 << idx))) |
| 814 | continue; | 816 | continue; |
| 815 | pslot = &mixer->slots[idx]; | 817 | pslot = &mixer->slots[idx]; |
| 816 | slot = (struct slot *)pslot->private_data; | 818 | slot = pslot->private_data; |
| 817 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) | 819 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) |
| 818 | continue; | 820 | continue; |
| 819 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) | 821 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) |
| @@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
| 826 | err = 0; | 828 | err = 0; |
| 827 | __unlock: | 829 | __unlock: |
| 828 | up_read(&card->controls_rwsem); | 830 | up_read(&card->controls_rwsem); |
| 831 | __free_only: | ||
| 829 | kfree(uctl); | 832 | kfree(uctl); |
| 830 | kfree(uinfo); | 833 | kfree(uinfo); |
| 831 | return err; | 834 | return err; |
| @@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
| 847 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 850 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); |
| 848 | if (uinfo == NULL || uctl == NULL) { | 851 | if (uinfo == NULL || uctl == NULL) { |
| 849 | err = -ENOMEM; | 852 | err = -ENOMEM; |
| 850 | goto __unlock; | 853 | goto __free_only; |
| 851 | } | 854 | } |
| 852 | down_read(&card->controls_rwsem); | 855 | down_read(&card->controls_rwsem); |
| 853 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); | 856 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); |
| @@ -861,7 +864,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
| 861 | if (!(mixer->mask_recsrc & (1 << idx))) | 864 | if (!(mixer->mask_recsrc & (1 << idx))) |
| 862 | continue; | 865 | continue; |
| 863 | pslot = &mixer->slots[idx]; | 866 | pslot = &mixer->slots[idx]; |
| 864 | slot = (struct slot *)pslot->private_data; | 867 | slot = pslot->private_data; |
| 865 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) | 868 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) |
| 866 | continue; | 869 | continue; |
| 867 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) | 870 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) |
| @@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
| 880 | err = 0; | 883 | err = 0; |
| 881 | __unlock: | 884 | __unlock: |
| 882 | up_read(&card->controls_rwsem); | 885 | up_read(&card->controls_rwsem); |
| 886 | __free_only: | ||
| 883 | kfree(uctl); | 887 | kfree(uctl); |
| 884 | kfree(uinfo); | 888 | kfree(uinfo); |
| 885 | return err; | 889 | return err; |
| @@ -925,7 +929,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl | |||
| 925 | 929 | ||
| 926 | static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) | 930 | static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) |
| 927 | { | 931 | { |
| 928 | struct slot *p = (struct slot *)chn->private_data; | 932 | struct slot *p = chn->private_data; |
| 929 | if (p) { | 933 | if (p) { |
| 930 | if (p->allocated && p->assigned) { | 934 | if (p->allocated && p->assigned) { |
| 931 | kfree(p->assigned->name); | 935 | kfree(p->assigned->name); |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index ac242a377aea..6b4b1287b314 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
| @@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry, | |||
| 364 | static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry, | 364 | static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry, |
| 365 | struct snd_info_buffer *buffer) | 365 | struct snd_info_buffer *buffer) |
| 366 | { | 366 | { |
| 367 | snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data, | 367 | snd_pcm_proc_info_read(entry->private_data, buffer); |
| 368 | buffer); | ||
| 369 | } | 368 | } |
| 370 | 369 | ||
| 371 | static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, | 370 | static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e23e0e7ab26f..a1707cca9c66 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
| @@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
| 334 | /* delta = "expected next hw_ptr" for in_interrupt != 0 */ | 334 | /* delta = "expected next hw_ptr" for in_interrupt != 0 */ |
| 335 | delta = runtime->hw_ptr_interrupt + runtime->period_size; | 335 | delta = runtime->hw_ptr_interrupt + runtime->period_size; |
| 336 | if (delta > new_hw_ptr) { | 336 | if (delta > new_hw_ptr) { |
| 337 | hw_base += runtime->buffer_size; | 337 | /* check for double acknowledged interrupts */ |
| 338 | if (hw_base >= runtime->boundary) | 338 | hdelta = jiffies - runtime->hw_ptr_jiffies; |
| 339 | hw_base = 0; | 339 | if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { |
| 340 | new_hw_ptr = hw_base + pos; | 340 | hw_base += runtime->buffer_size; |
| 341 | goto __delta; | 341 | if (hw_base >= runtime->boundary) |
| 342 | hw_base = 0; | ||
| 343 | new_hw_ptr = hw_base + pos; | ||
| 344 | goto __delta; | ||
| 345 | } | ||
| 342 | } | 346 | } |
| 343 | } | 347 | } |
| 344 | /* new_hw_ptr might be lower than old_hw_ptr in case when */ | 348 | /* new_hw_ptr might be lower than old_hw_ptr in case when */ |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index d4eb2ef80784..8bc7cb3db330 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
| @@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream, | |||
| 142 | 142 | ||
| 143 | #ifdef RULES_DEBUG | 143 | #ifdef RULES_DEBUG |
| 144 | #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v | 144 | #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v |
| 145 | char *snd_pcm_hw_param_names[] = { | 145 | static const char * const snd_pcm_hw_param_names[] = { |
| 146 | HW_PARAM(ACCESS), | 146 | HW_PARAM(ACCESS), |
| 147 | HW_PARAM(FORMAT), | 147 | HW_PARAM(FORMAT), |
| 148 | HW_PARAM(SUBFORMAT), | 148 | HW_PARAM(SUBFORMAT), |
| @@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) | |||
| 864 | struct snd_pcm_runtime *runtime = substream->runtime; | 864 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 865 | snd_pcm_trigger_tstamp(substream); | 865 | snd_pcm_trigger_tstamp(substream); |
| 866 | runtime->hw_ptr_jiffies = jiffies; | 866 | runtime->hw_ptr_jiffies = jiffies; |
| 867 | runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / | ||
| 868 | runtime->rate; | ||
| 867 | runtime->status->state = state; | 869 | runtime->status->state = state; |
| 868 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 870 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
| 869 | runtime->silence_size > 0) | 871 | runtime->silence_size > 0) |
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 480c38623da8..c8961165277c 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
| @@ -74,6 +74,25 @@ config SND_DUMMY | |||
| 74 | To compile this driver as a module, choose M here: the module | 74 | To compile this driver as a module, choose M here: the module |
| 75 | will be called snd-dummy. | 75 | will be called snd-dummy. |
| 76 | 76 | ||
| 77 | config SND_ALOOP | ||
| 78 | tristate "Generic loopback driver (PCM)" | ||
| 79 | select SND_PCM | ||
| 80 | help | ||
| 81 | Say 'Y' or 'M' to include support for the PCM loopback device. | ||
| 82 | This module returns played samples back to the user space using | ||
| 83 | the standard ALSA PCM device. The devices are routed 0->1 and | ||
| 84 | 1->0, where first number is the playback PCM device and second | ||
| 85 | number is the capture device. Module creates two PCM devices and | ||
| 86 | configured number of substreams (see the pcm_substreams module | ||
| 87 | parameter). | ||
| 88 | |||
| 89 | The looback device allow time sychronization with an external | ||
| 90 | timing source using the time shift universal control (+-20% | ||
| 91 | of system time). | ||
| 92 | |||
| 93 | To compile this driver as a module, choose M here: the module | ||
| 94 | will be called snd-aloop. | ||
| 95 | |||
| 77 | config SND_VIRMIDI | 96 | config SND_VIRMIDI |
| 78 | tristate "Virtual MIDI soundcard" | 97 | tristate "Virtual MIDI soundcard" |
| 79 | depends on SND_SEQUENCER | 98 | depends on SND_SEQUENCER |
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index d4a07f9ff2c7..1a8440c8b138 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | snd-dummy-objs := dummy.o | 6 | snd-dummy-objs := dummy.o |
| 7 | snd-aloop-objs := aloop.o | ||
| 7 | snd-mtpav-objs := mtpav.o | 8 | snd-mtpav-objs := mtpav.o |
| 8 | snd-mts64-objs := mts64.o | 9 | snd-mts64-objs := mts64.o |
| 9 | snd-portman2x4-objs := portman2x4.o | 10 | snd-portman2x4-objs := portman2x4.o |
| @@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o | |||
| 13 | 14 | ||
| 14 | # Toplevel Module Dependency | 15 | # Toplevel Module Dependency |
| 15 | obj-$(CONFIG_SND_DUMMY) += snd-dummy.o | 16 | obj-$(CONFIG_SND_DUMMY) += snd-dummy.o |
| 17 | obj-$(CONFIG_SND_ALOOP) += snd-aloop.o | ||
| 16 | obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o | 18 | obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o |
| 17 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o | 19 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o |
| 18 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o | 20 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o |
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c new file mode 100644 index 000000000000..12b44b0b6777 --- /dev/null +++ b/sound/drivers/aloop.c | |||
| @@ -0,0 +1,1258 @@ | |||
| 1 | /* | ||
| 2 | * Loopback soundcard | ||
| 3 | * | ||
| 4 | * Original code: | ||
| 5 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
| 6 | * | ||
| 7 | * More accurate positioning and full-duplex support: | ||
| 8 | * Copyright (c) Ahmet İnan <ainan at mathematik.uni-freiburg.de> | ||
| 9 | * | ||
| 10 | * Major (almost complete) rewrite: | ||
| 11 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> | ||
| 12 | * | ||
| 13 | * A next major update in 2010 (separate timers for playback and capture): | ||
| 14 | * Copyright (c) Jaroslav Kysela <perex@perex.cz> | ||
| 15 | * | ||
| 16 | * This program is free software; you can redistribute it and/or modify | ||
| 17 | * it under the terms of the GNU General Public License as published by | ||
| 18 | * the Free Software Foundation; either version 2 of the License, or | ||
| 19 | * (at your option) any later version. | ||
| 20 | * | ||
| 21 | * This program is distributed in the hope that it will be useful, | ||
| 22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 24 | * GNU General Public License for more details. | ||
| 25 | * | ||
| 26 | * You should have received a copy of the GNU General Public License | ||
| 27 | * along with this program; if not, write to the Free Software | ||
| 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 29 | * | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <linux/init.h> | ||
| 33 | #include <linux/jiffies.h> | ||
| 34 | #include <linux/slab.h> | ||
| 35 | #include <linux/time.h> | ||
| 36 | #include <linux/wait.h> | ||
| 37 | #include <linux/moduleparam.h> | ||
| 38 | #include <linux/platform_device.h> | ||
| 39 | #include <sound/core.h> | ||
| 40 | #include <sound/control.h> | ||
| 41 | #include <sound/pcm.h> | ||
| 42 | #include <sound/info.h> | ||
| 43 | #include <sound/initval.h> | ||
| 44 | |||
| 45 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
| 46 | MODULE_DESCRIPTION("A loopback soundcard"); | ||
| 47 | MODULE_LICENSE("GPL"); | ||
| 48 | MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}"); | ||
| 49 | |||
| 50 | #define MAX_PCM_SUBSTREAMS 8 | ||
| 51 | |||
| 52 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
| 53 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
| 54 | static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; | ||
| 55 | static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; | ||
| 56 | static int pcm_notify[SNDRV_CARDS]; | ||
| 57 | |||
| 58 | module_param_array(index, int, NULL, 0444); | ||
| 59 | MODULE_PARM_DESC(index, "Index value for loopback soundcard."); | ||
| 60 | module_param_array(id, charp, NULL, 0444); | ||
| 61 | MODULE_PARM_DESC(id, "ID string for loopback soundcard."); | ||
| 62 | module_param_array(enable, bool, NULL, 0444); | ||
| 63 | MODULE_PARM_DESC(enable, "Enable this loopback soundcard."); | ||
| 64 | module_param_array(pcm_substreams, int, NULL, 0444); | ||
| 65 | MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver."); | ||
| 66 | module_param_array(pcm_notify, int, NULL, 0444); | ||
| 67 | MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes."); | ||
| 68 | |||
| 69 | #define NO_PITCH 100000 | ||
| 70 | |||
| 71 | struct loopback_pcm; | ||
| 72 | |||
| 73 | struct loopback_cable { | ||
| 74 | spinlock_t lock; | ||
| 75 | struct loopback_pcm *streams[2]; | ||
| 76 | struct snd_pcm_hardware hw; | ||
| 77 | /* flags */ | ||
| 78 | unsigned int valid; | ||
| 79 | unsigned int running; | ||
| 80 | unsigned int pause; | ||
| 81 | }; | ||
| 82 | |||
| 83 | struct loopback_setup { | ||
| 84 | unsigned int notify: 1; | ||
| 85 | unsigned int rate_shift; | ||
| 86 | unsigned int format; | ||
| 87 | unsigned int rate; | ||
| 88 | unsigned int channels; | ||
| 89 | struct snd_ctl_elem_id active_id; | ||
| 90 | struct snd_ctl_elem_id format_id; | ||
| 91 | struct snd_ctl_elem_id rate_id; | ||
| 92 | struct snd_ctl_elem_id channels_id; | ||
| 93 | }; | ||
| 94 | |||
| 95 | struct loopback { | ||
| 96 | struct snd_card *card; | ||
| 97 | struct mutex cable_lock; | ||
| 98 | struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2]; | ||
| 99 | struct snd_pcm *pcm[2]; | ||
| 100 | struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2]; | ||
| 101 | }; | ||
| 102 | |||
| 103 | struct loopback_pcm { | ||
| 104 | struct loopback *loopback; | ||
| 105 | struct snd_pcm_substream *substream; | ||
| 106 | struct loopback_cable *cable; | ||
| 107 | unsigned int pcm_buffer_size; | ||
| 108 | unsigned int buf_pos; /* position in buffer */ | ||
| 109 | unsigned int silent_size; | ||
| 110 | /* PCM parameters */ | ||
| 111 | unsigned int pcm_period_size; | ||
| 112 | unsigned int pcm_bps; /* bytes per second */ | ||
| 113 | unsigned int pcm_salign; /* bytes per sample * channels */ | ||
| 114 | unsigned int pcm_rate_shift; /* rate shift value */ | ||
| 115 | /* flags */ | ||
| 116 | unsigned int period_update_pending :1; | ||
| 117 | /* timer stuff */ | ||
| 118 | unsigned int irq_pos; /* fractional IRQ position */ | ||
| 119 | unsigned int period_size_frac; | ||
| 120 | unsigned long last_jiffies; | ||
| 121 | struct timer_list timer; | ||
| 122 | }; | ||
| 123 | |||
| 124 | static struct platform_device *devices[SNDRV_CARDS]; | ||
| 125 | |||
| 126 | static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x) | ||
| 127 | { | ||
| 128 | if (dpcm->pcm_rate_shift == NO_PITCH) { | ||
| 129 | x /= HZ; | ||
| 130 | } else { | ||
| 131 | x = div_u64(NO_PITCH * (unsigned long long)x, | ||
| 132 | HZ * (unsigned long long)dpcm->pcm_rate_shift); | ||
| 133 | } | ||
| 134 | return x - (x % dpcm->pcm_salign); | ||
| 135 | } | ||
| 136 | |||
| 137 | static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x) | ||
| 138 | { | ||
| 139 | if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */ | ||
| 140 | return x * HZ; | ||
| 141 | } else { | ||
| 142 | x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ, | ||
| 143 | NO_PITCH); | ||
| 144 | } | ||
| 145 | return x; | ||
| 146 | } | ||
| 147 | |||
| 148 | static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm) | ||
| 149 | { | ||
| 150 | int device = dpcm->substream->pstr->pcm->device; | ||
| 151 | |||
| 152 | if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 153 | device ^= 1; | ||
| 154 | return &dpcm->loopback->setup[dpcm->substream->number][device]; | ||
| 155 | } | ||
| 156 | |||
| 157 | static inline unsigned int get_notify(struct loopback_pcm *dpcm) | ||
| 158 | { | ||
| 159 | return get_setup(dpcm)->notify; | ||
| 160 | } | ||
| 161 | |||
| 162 | static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) | ||
| 163 | { | ||
| 164 | return get_setup(dpcm)->rate_shift; | ||
| 165 | } | ||
| 166 | |||
| 167 | static void loopback_timer_start(struct loopback_pcm *dpcm) | ||
| 168 | { | ||
| 169 | unsigned long tick; | ||
| 170 | unsigned int rate_shift = get_rate_shift(dpcm); | ||
| 171 | |||
| 172 | if (rate_shift != dpcm->pcm_rate_shift) { | ||
| 173 | dpcm->pcm_rate_shift = rate_shift; | ||
| 174 | dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); | ||
| 175 | } | ||
| 176 | if (dpcm->period_size_frac <= dpcm->irq_pos) { | ||
| 177 | dpcm->irq_pos %= dpcm->period_size_frac; | ||
| 178 | dpcm->period_update_pending = 1; | ||
| 179 | } | ||
| 180 | tick = dpcm->period_size_frac - dpcm->irq_pos; | ||
| 181 | tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; | ||
| 182 | dpcm->timer.expires = jiffies + tick; | ||
| 183 | add_timer(&dpcm->timer); | ||
| 184 | } | ||
| 185 | |||
| 186 | static inline void loopback_timer_stop(struct loopback_pcm *dpcm) | ||
| 187 | { | ||
| 188 | del_timer(&dpcm->timer); | ||
| 189 | dpcm->timer.expires = 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) | ||
| 193 | #define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE) | ||
| 194 | #define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE) | ||
| 195 | |||
| 196 | static int loopback_check_format(struct loopback_cable *cable, int stream) | ||
| 197 | { | ||
| 198 | struct snd_pcm_runtime *runtime, *cruntime; | ||
| 199 | struct loopback_setup *setup; | ||
| 200 | struct snd_card *card; | ||
| 201 | int check; | ||
| 202 | |||
| 203 | if (cable->valid != CABLE_VALID_BOTH) { | ||
| 204 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 205 | goto __notify; | ||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> | ||
| 209 | substream->runtime; | ||
| 210 | cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> | ||
| 211 | substream->runtime; | ||
| 212 | check = runtime->format != cruntime->format || | ||
| 213 | runtime->rate != cruntime->rate || | ||
| 214 | runtime->channels != cruntime->channels; | ||
| 215 | if (!check) | ||
| 216 | return 0; | ||
| 217 | if (stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
| 218 | return -EIO; | ||
| 219 | } else { | ||
| 220 | snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> | ||
| 221 | substream, SNDRV_PCM_STATE_DRAINING); | ||
| 222 | __notify: | ||
| 223 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> | ||
| 224 | substream->runtime; | ||
| 225 | setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); | ||
| 226 | card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; | ||
| 227 | if (setup->format != runtime->format) { | ||
| 228 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 229 | &setup->format_id); | ||
| 230 | setup->format = runtime->format; | ||
| 231 | } | ||
| 232 | if (setup->rate != runtime->rate) { | ||
| 233 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 234 | &setup->rate_id); | ||
| 235 | setup->rate = runtime->rate; | ||
| 236 | } | ||
| 237 | if (setup->channels != runtime->channels) { | ||
| 238 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 239 | &setup->channels_id); | ||
| 240 | setup->channels = runtime->channels; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | static void loopback_active_notify(struct loopback_pcm *dpcm) | ||
| 247 | { | ||
| 248 | snd_ctl_notify(dpcm->loopback->card, | ||
| 249 | SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 250 | &get_setup(dpcm)->active_id); | ||
| 251 | } | ||
| 252 | |||
| 253 | static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 254 | { | ||
| 255 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 256 | struct loopback_pcm *dpcm = runtime->private_data; | ||
| 257 | struct loopback_cable *cable = dpcm->cable; | ||
| 258 | int err, stream = 1 << substream->stream; | ||
| 259 | |||
| 260 | switch (cmd) { | ||
| 261 | case SNDRV_PCM_TRIGGER_START: | ||
| 262 | err = loopback_check_format(cable, substream->stream); | ||
| 263 | if (err < 0) | ||
| 264 | return err; | ||
| 265 | dpcm->last_jiffies = jiffies; | ||
| 266 | dpcm->pcm_rate_shift = 0; | ||
| 267 | spin_lock(&cable->lock); | ||
| 268 | cable->running |= stream; | ||
| 269 | cable->pause &= ~stream; | ||
| 270 | spin_unlock(&cable->lock); | ||
| 271 | loopback_timer_start(dpcm); | ||
| 272 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 273 | loopback_active_notify(dpcm); | ||
| 274 | break; | ||
| 275 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 276 | spin_lock(&cable->lock); | ||
| 277 | cable->running &= ~stream; | ||
| 278 | cable->pause &= ~stream; | ||
| 279 | spin_unlock(&cable->lock); | ||
| 280 | loopback_timer_stop(dpcm); | ||
| 281 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 282 | loopback_active_notify(dpcm); | ||
| 283 | break; | ||
| 284 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 285 | spin_lock(&cable->lock); | ||
| 286 | cable->pause |= stream; | ||
| 287 | spin_unlock(&cable->lock); | ||
| 288 | loopback_timer_stop(dpcm); | ||
| 289 | break; | ||
| 290 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 291 | spin_lock(&cable->lock); | ||
| 292 | dpcm->last_jiffies = jiffies; | ||
| 293 | cable->pause &= ~stream; | ||
| 294 | spin_unlock(&cable->lock); | ||
| 295 | loopback_timer_start(dpcm); | ||
| 296 | break; | ||
| 297 | default: | ||
| 298 | return -EINVAL; | ||
| 299 | } | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | |||
| 303 | static void params_change_substream(struct loopback_pcm *dpcm, | ||
| 304 | struct snd_pcm_runtime *runtime) | ||
| 305 | { | ||
| 306 | struct snd_pcm_runtime *dst_runtime; | ||
| 307 | |||
| 308 | if (dpcm == NULL || dpcm->substream == NULL) | ||
| 309 | return; | ||
| 310 | dst_runtime = dpcm->substream->runtime; | ||
| 311 | if (dst_runtime == NULL) | ||
| 312 | return; | ||
| 313 | dst_runtime->hw = dpcm->cable->hw; | ||
| 314 | } | ||
| 315 | |||
| 316 | static void params_change(struct snd_pcm_substream *substream) | ||
| 317 | { | ||
| 318 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 319 | struct loopback_pcm *dpcm = runtime->private_data; | ||
| 320 | struct loopback_cable *cable = dpcm->cable; | ||
| 321 | |||
| 322 | cable->hw.formats = (1ULL << runtime->format); | ||
| 323 | cable->hw.rate_min = runtime->rate; | ||
| 324 | cable->hw.rate_max = runtime->rate; | ||
| 325 | cable->hw.channels_min = runtime->channels; | ||
| 326 | cable->hw.channels_max = runtime->channels; | ||
| 327 | params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK], | ||
| 328 | runtime); | ||
| 329 | params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE], | ||
| 330 | runtime); | ||
| 331 | } | ||
| 332 | |||
| 333 | static int loopback_prepare(struct snd_pcm_substream *substream) | ||
| 334 | { | ||
| 335 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 336 | struct loopback_pcm *dpcm = runtime->private_data; | ||
| 337 | struct loopback_cable *cable = dpcm->cable; | ||
| 338 | int bps, salign; | ||
| 339 | |||
| 340 | salign = (snd_pcm_format_width(runtime->format) * | ||
| 341 | runtime->channels) / 8; | ||
| 342 | bps = salign * runtime->rate; | ||
| 343 | if (bps <= 0 || salign <= 0) | ||
| 344 | return -EINVAL; | ||
| 345 | |||
| 346 | dpcm->buf_pos = 0; | ||
| 347 | dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size); | ||
| 348 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
| 349 | /* clear capture buffer */ | ||
| 350 | dpcm->silent_size = dpcm->pcm_buffer_size; | ||
| 351 | snd_pcm_format_set_silence(runtime->format, runtime->dma_area, | ||
| 352 | runtime->buffer_size * runtime->channels); | ||
| 353 | } | ||
| 354 | |||
| 355 | dpcm->irq_pos = 0; | ||
| 356 | dpcm->period_update_pending = 0; | ||
| 357 | dpcm->pcm_bps = bps; | ||
| 358 | dpcm->pcm_salign = salign; | ||
| 359 | dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); | ||
| 360 | |||
| 361 | mutex_lock(&dpcm->loopback->cable_lock); | ||
| 362 | if (!(cable->valid & ~(1 << substream->stream)) || | ||
| 363 | (get_setup(dpcm)->notify && | ||
| 364 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) | ||
| 365 | params_change(substream); | ||
| 366 | cable->valid |= 1 << substream->stream; | ||
| 367 | mutex_unlock(&dpcm->loopback->cable_lock); | ||
| 368 | |||
| 369 | return 0; | ||
| 370 | } | ||
| 371 | |||
| 372 | static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes) | ||
| 373 | { | ||
| 374 | struct snd_pcm_runtime *runtime = dpcm->substream->runtime; | ||
| 375 | char *dst = runtime->dma_area; | ||
| 376 | unsigned int dst_off = dpcm->buf_pos; | ||
| 377 | |||
| 378 | if (dpcm->silent_size >= dpcm->pcm_buffer_size) | ||
| 379 | return; | ||
| 380 | if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size) | ||
| 381 | bytes = dpcm->pcm_buffer_size - dpcm->silent_size; | ||
| 382 | |||
| 383 | for (;;) { | ||
| 384 | unsigned int size = bytes; | ||
| 385 | if (dst_off + size > dpcm->pcm_buffer_size) | ||
| 386 | size = dpcm->pcm_buffer_size - dst_off; | ||
| 387 | snd_pcm_format_set_silence(runtime->format, dst + dst_off, | ||
| 388 | bytes_to_frames(runtime, size) * | ||
| 389 | runtime->channels); | ||
| 390 | dpcm->silent_size += size; | ||
| 391 | bytes -= size; | ||
| 392 | if (!bytes) | ||
| 393 | break; | ||
| 394 | dst_off = 0; | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | static void copy_play_buf(struct loopback_pcm *play, | ||
| 399 | struct loopback_pcm *capt, | ||
| 400 | unsigned int bytes) | ||
| 401 | { | ||
| 402 | struct snd_pcm_runtime *runtime = play->substream->runtime; | ||
| 403 | char *src = runtime->dma_area; | ||
| 404 | char *dst = capt->substream->runtime->dma_area; | ||
| 405 | unsigned int src_off = play->buf_pos; | ||
| 406 | unsigned int dst_off = capt->buf_pos; | ||
| 407 | unsigned int clear_bytes = 0; | ||
| 408 | |||
| 409 | /* check if playback is draining, trim the capture copy size | ||
| 410 | * when our pointer is at the end of playback ring buffer */ | ||
| 411 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && | ||
| 412 | snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { | ||
| 413 | snd_pcm_uframes_t appl_ptr, appl_ptr1, diff; | ||
| 414 | appl_ptr = appl_ptr1 = runtime->control->appl_ptr; | ||
| 415 | appl_ptr1 -= appl_ptr1 % runtime->buffer_size; | ||
| 416 | appl_ptr1 += play->buf_pos / play->pcm_salign; | ||
| 417 | if (appl_ptr < appl_ptr1) | ||
| 418 | appl_ptr1 -= runtime->buffer_size; | ||
| 419 | diff = (appl_ptr - appl_ptr1) * play->pcm_salign; | ||
| 420 | if (diff < bytes) { | ||
| 421 | clear_bytes = bytes - diff; | ||
| 422 | bytes = diff; | ||
| 423 | } | ||
| 424 | } | ||
| 425 | |||
| 426 | for (;;) { | ||
| 427 | unsigned int size = bytes; | ||
| 428 | if (src_off + size > play->pcm_buffer_size) | ||
| 429 | size = play->pcm_buffer_size - src_off; | ||
| 430 | if (dst_off + size > capt->pcm_buffer_size) | ||
| 431 | size = capt->pcm_buffer_size - dst_off; | ||
| 432 | memcpy(dst + dst_off, src + src_off, size); | ||
| 433 | capt->silent_size = 0; | ||
| 434 | bytes -= size; | ||
| 435 | if (!bytes) | ||
| 436 | break; | ||
| 437 | src_off = (src_off + size) % play->pcm_buffer_size; | ||
| 438 | dst_off = (dst_off + size) % capt->pcm_buffer_size; | ||
| 439 | } | ||
| 440 | |||
| 441 | if (clear_bytes > 0) { | ||
| 442 | clear_capture_buf(capt, clear_bytes); | ||
| 443 | capt->silent_size = 0; | ||
| 444 | } | ||
| 445 | } | ||
| 446 | |||
| 447 | #define BYTEPOS_UPDATE_POSONLY 0 | ||
| 448 | #define BYTEPOS_UPDATE_CLEAR 1 | ||
| 449 | #define BYTEPOS_UPDATE_COPY 2 | ||
| 450 | |||
| 451 | static void loopback_bytepos_update(struct loopback_pcm *dpcm, | ||
| 452 | unsigned int delta, | ||
| 453 | unsigned int cmd) | ||
| 454 | { | ||
| 455 | unsigned int count; | ||
| 456 | unsigned long last_pos; | ||
| 457 | |||
| 458 | last_pos = byte_pos(dpcm, dpcm->irq_pos); | ||
| 459 | dpcm->irq_pos += delta * dpcm->pcm_bps; | ||
| 460 | count = byte_pos(dpcm, dpcm->irq_pos) - last_pos; | ||
| 461 | if (!count) | ||
| 462 | return; | ||
| 463 | if (cmd == BYTEPOS_UPDATE_CLEAR) | ||
| 464 | clear_capture_buf(dpcm, count); | ||
| 465 | else if (cmd == BYTEPOS_UPDATE_COPY) | ||
| 466 | copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK], | ||
| 467 | dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE], | ||
| 468 | count); | ||
| 469 | dpcm->buf_pos += count; | ||
| 470 | dpcm->buf_pos %= dpcm->pcm_buffer_size; | ||
| 471 | if (dpcm->irq_pos >= dpcm->period_size_frac) { | ||
| 472 | dpcm->irq_pos %= dpcm->period_size_frac; | ||
| 473 | dpcm->period_update_pending = 1; | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 477 | static unsigned int loopback_pos_update(struct loopback_cable *cable) | ||
| 478 | { | ||
| 479 | struct loopback_pcm *dpcm_play = | ||
| 480 | cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; | ||
| 481 | struct loopback_pcm *dpcm_capt = | ||
| 482 | cable->streams[SNDRV_PCM_STREAM_CAPTURE]; | ||
| 483 | unsigned long delta_play = 0, delta_capt = 0; | ||
| 484 | unsigned int running; | ||
| 485 | |||
| 486 | spin_lock(&cable->lock); | ||
| 487 | running = cable->running ^ cable->pause; | ||
| 488 | if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { | ||
| 489 | delta_play = jiffies - dpcm_play->last_jiffies; | ||
| 490 | dpcm_play->last_jiffies += delta_play; | ||
| 491 | } | ||
| 492 | |||
| 493 | if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { | ||
| 494 | delta_capt = jiffies - dpcm_capt->last_jiffies; | ||
| 495 | dpcm_capt->last_jiffies += delta_capt; | ||
| 496 | } | ||
| 497 | |||
| 498 | if (delta_play == 0 && delta_capt == 0) { | ||
| 499 | spin_unlock(&cable->lock); | ||
| 500 | return running; | ||
| 501 | } | ||
| 502 | |||
| 503 | if (delta_play > delta_capt) { | ||
| 504 | loopback_bytepos_update(dpcm_play, delta_play - delta_capt, | ||
| 505 | BYTEPOS_UPDATE_POSONLY); | ||
| 506 | delta_play = delta_capt; | ||
| 507 | } else if (delta_play < delta_capt) { | ||
| 508 | loopback_bytepos_update(dpcm_capt, delta_capt - delta_play, | ||
| 509 | BYTEPOS_UPDATE_CLEAR); | ||
| 510 | delta_capt = delta_play; | ||
| 511 | } | ||
| 512 | |||
| 513 | if (delta_play == 0 && delta_capt == 0) { | ||
| 514 | spin_unlock(&cable->lock); | ||
| 515 | return running; | ||
| 516 | } | ||
| 517 | /* note delta_capt == delta_play at this moment */ | ||
| 518 | loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY); | ||
| 519 | loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY); | ||
| 520 | spin_unlock(&cable->lock); | ||
| 521 | return running; | ||
| 522 | } | ||
| 523 | |||
| 524 | static void loopback_timer_function(unsigned long data) | ||
| 525 | { | ||
| 526 | struct loopback_pcm *dpcm = (struct loopback_pcm *)data; | ||
| 527 | unsigned int running; | ||
| 528 | |||
| 529 | running = loopback_pos_update(dpcm->cable); | ||
| 530 | if (running & (1 << dpcm->substream->stream)) { | ||
| 531 | loopback_timer_start(dpcm); | ||
| 532 | if (dpcm->period_update_pending) { | ||
| 533 | dpcm->period_update_pending = 0; | ||
| 534 | snd_pcm_period_elapsed(dpcm->substream); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) | ||
| 540 | { | ||
| 541 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 542 | struct loopback_pcm *dpcm = runtime->private_data; | ||
| 543 | |||
| 544 | loopback_pos_update(dpcm->cable); | ||
| 545 | return bytes_to_frames(runtime, dpcm->buf_pos); | ||
| 546 | } | ||
| 547 | |||
| 548 | static struct snd_pcm_hardware loopback_pcm_hardware = | ||
| 549 | { | ||
| 550 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | | ||
| 551 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), | ||
| 552 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | | ||
| 553 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | | ||
| 554 | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), | ||
| 555 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, | ||
| 556 | .rate_min = 8000, | ||
| 557 | .rate_max = 192000, | ||
| 558 | .channels_min = 1, | ||
| 559 | .channels_max = 32, | ||
| 560 | .buffer_bytes_max = 2 * 1024 * 1024, | ||
| 561 | .period_bytes_min = 64, | ||
| 562 | /* note check overflow in frac_pos() using pcm_rate_shift before | ||
| 563 | changing period_bytes_max value */ | ||
| 564 | .period_bytes_max = 1024 * 1024, | ||
| 565 | .periods_min = 1, | ||
| 566 | .periods_max = 1024, | ||
| 567 | .fifo_size = 0, | ||
| 568 | }; | ||
| 569 | |||
| 570 | static void loopback_runtime_free(struct snd_pcm_runtime *runtime) | ||
| 571 | { | ||
| 572 | struct loopback_pcm *dpcm = runtime->private_data; | ||
| 573 | kfree(dpcm); | ||
| 574 | } | ||
| 575 | |||
| 576 | static int loopback_hw_params(struct snd_pcm_substream *substream, | ||
| 577 | struct snd_pcm_hw_params *params) | ||
| 578 | { | ||
| 579 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
| 580 | } | ||
| 581 | |||
| 582 | static int loopback_hw_free(struct snd_pcm_substream *substream) | ||
| 583 | { | ||
| 584 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 585 | struct loopback_pcm *dpcm = runtime->private_data; | ||
| 586 | struct loopback_cable *cable = dpcm->cable; | ||
| 587 | |||
| 588 | mutex_lock(&dpcm->loopback->cable_lock); | ||
| 589 | cable->valid &= ~(1 << substream->stream); | ||
| 590 | mutex_unlock(&dpcm->loopback->cable_lock); | ||
| 591 | return snd_pcm_lib_free_pages(substream); | ||
| 592 | } | ||
| 593 | |||
| 594 | static unsigned int get_cable_index(struct snd_pcm_substream *substream) | ||
| 595 | { | ||
| 596 | if (!substream->pcm->device) | ||
| 597 | return substream->stream; | ||
| 598 | else | ||
| 599 | return !substream->stream; | ||
| 600 | } | ||
| 601 | |||
| 602 | static int rule_format(struct snd_pcm_hw_params *params, | ||
| 603 | struct snd_pcm_hw_rule *rule) | ||
| 604 | { | ||
| 605 | |||
| 606 | struct snd_pcm_hardware *hw = rule->private; | ||
| 607 | struct snd_mask *maskp = hw_param_mask(params, rule->var); | ||
| 608 | |||
| 609 | maskp->bits[0] &= (u_int32_t)hw->formats; | ||
| 610 | maskp->bits[1] &= (u_int32_t)(hw->formats >> 32); | ||
| 611 | memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */ | ||
| 612 | if (! maskp->bits[0] && ! maskp->bits[1]) | ||
| 613 | return -EINVAL; | ||
| 614 | return 0; | ||
| 615 | } | ||
| 616 | |||
| 617 | static int rule_rate(struct snd_pcm_hw_params *params, | ||
| 618 | struct snd_pcm_hw_rule *rule) | ||
| 619 | { | ||
| 620 | struct snd_pcm_hardware *hw = rule->private; | ||
| 621 | struct snd_interval t; | ||
| 622 | |||
| 623 | t.min = hw->rate_min; | ||
| 624 | t.max = hw->rate_max; | ||
| 625 | t.openmin = t.openmax = 0; | ||
| 626 | t.integer = 0; | ||
| 627 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
| 628 | } | ||
| 629 | |||
| 630 | static int rule_channels(struct snd_pcm_hw_params *params, | ||
| 631 | struct snd_pcm_hw_rule *rule) | ||
| 632 | { | ||
| 633 | struct snd_pcm_hardware *hw = rule->private; | ||
| 634 | struct snd_interval t; | ||
| 635 | |||
| 636 | t.min = hw->channels_min; | ||
| 637 | t.max = hw->channels_max; | ||
| 638 | t.openmin = t.openmax = 0; | ||
| 639 | t.integer = 0; | ||
| 640 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
| 641 | } | ||
| 642 | |||
| 643 | static int loopback_open(struct snd_pcm_substream *substream) | ||
| 644 | { | ||
| 645 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 646 | struct loopback *loopback = substream->private_data; | ||
| 647 | struct loopback_pcm *dpcm; | ||
| 648 | struct loopback_cable *cable; | ||
| 649 | int err = 0; | ||
| 650 | int dev = get_cable_index(substream); | ||
| 651 | |||
| 652 | mutex_lock(&loopback->cable_lock); | ||
| 653 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); | ||
| 654 | if (!dpcm) { | ||
| 655 | err = -ENOMEM; | ||
| 656 | goto unlock; | ||
| 657 | } | ||
| 658 | dpcm->loopback = loopback; | ||
| 659 | dpcm->substream = substream; | ||
| 660 | setup_timer(&dpcm->timer, loopback_timer_function, | ||
| 661 | (unsigned long)dpcm); | ||
| 662 | |||
| 663 | cable = loopback->cables[substream->number][dev]; | ||
| 664 | if (!cable) { | ||
| 665 | cable = kzalloc(sizeof(*cable), GFP_KERNEL); | ||
| 666 | if (!cable) { | ||
| 667 | kfree(dpcm); | ||
| 668 | err = -ENOMEM; | ||
| 669 | goto unlock; | ||
| 670 | } | ||
| 671 | spin_lock_init(&cable->lock); | ||
| 672 | cable->hw = loopback_pcm_hardware; | ||
| 673 | loopback->cables[substream->number][dev] = cable; | ||
| 674 | } | ||
| 675 | dpcm->cable = cable; | ||
| 676 | cable->streams[substream->stream] = dpcm; | ||
| 677 | |||
| 678 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
| 679 | |||
| 680 | /* use dynamic rules based on actual runtime->hw values */ | ||
| 681 | /* note that the default rules created in the PCM midlevel code */ | ||
| 682 | /* are cached -> they do not reflect the actual state */ | ||
| 683 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
| 684 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
| 685 | rule_format, &runtime->hw, | ||
| 686 | SNDRV_PCM_HW_PARAM_FORMAT, -1); | ||
| 687 | if (err < 0) | ||
| 688 | goto unlock; | ||
| 689 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
| 690 | SNDRV_PCM_HW_PARAM_RATE, | ||
| 691 | rule_rate, &runtime->hw, | ||
| 692 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
| 693 | if (err < 0) | ||
| 694 | goto unlock; | ||
| 695 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
| 696 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
| 697 | rule_channels, &runtime->hw, | ||
| 698 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
| 699 | if (err < 0) | ||
| 700 | goto unlock; | ||
| 701 | |||
| 702 | runtime->private_data = dpcm; | ||
| 703 | runtime->private_free = loopback_runtime_free; | ||
| 704 | if (get_notify(dpcm)) | ||
| 705 | runtime->hw = loopback_pcm_hardware; | ||
| 706 | else | ||
| 707 | runtime->hw = cable->hw; | ||
| 708 | unlock: | ||
| 709 | mutex_unlock(&loopback->cable_lock); | ||
| 710 | return err; | ||
| 711 | } | ||
| 712 | |||
| 713 | static int loopback_close(struct snd_pcm_substream *substream) | ||
| 714 | { | ||
| 715 | struct loopback *loopback = substream->private_data; | ||
| 716 | struct loopback_pcm *dpcm = substream->runtime->private_data; | ||
| 717 | struct loopback_cable *cable; | ||
| 718 | int dev = get_cable_index(substream); | ||
| 719 | |||
| 720 | loopback_timer_stop(dpcm); | ||
| 721 | mutex_lock(&loopback->cable_lock); | ||
| 722 | cable = loopback->cables[substream->number][dev]; | ||
| 723 | if (cable->streams[!substream->stream]) { | ||
| 724 | /* other stream is still alive */ | ||
| 725 | cable->streams[substream->stream] = NULL; | ||
| 726 | } else { | ||
| 727 | /* free the cable */ | ||
| 728 | loopback->cables[substream->number][dev] = NULL; | ||
| 729 | kfree(cable); | ||
| 730 | } | ||
| 731 | mutex_unlock(&loopback->cable_lock); | ||
| 732 | return 0; | ||
| 733 | } | ||
| 734 | |||
| 735 | static struct snd_pcm_ops loopback_playback_ops = { | ||
| 736 | .open = loopback_open, | ||
| 737 | .close = loopback_close, | ||
| 738 | .ioctl = snd_pcm_lib_ioctl, | ||
| 739 | .hw_params = loopback_hw_params, | ||
| 740 | .hw_free = loopback_hw_free, | ||
| 741 | .prepare = loopback_prepare, | ||
| 742 | .trigger = loopback_trigger, | ||
| 743 | .pointer = loopback_pointer, | ||
| 744 | }; | ||
| 745 | |||
| 746 | static struct snd_pcm_ops loopback_capture_ops = { | ||
| 747 | .open = loopback_open, | ||
| 748 | .close = loopback_close, | ||
| 749 | .ioctl = snd_pcm_lib_ioctl, | ||
| 750 | .hw_params = loopback_hw_params, | ||
| 751 | .hw_free = loopback_hw_free, | ||
| 752 | .prepare = loopback_prepare, | ||
| 753 | .trigger = loopback_trigger, | ||
| 754 | .pointer = loopback_pointer, | ||
| 755 | }; | ||
| 756 | |||
| 757 | static int __devinit loopback_pcm_new(struct loopback *loopback, | ||
| 758 | int device, int substreams) | ||
| 759 | { | ||
| 760 | struct snd_pcm *pcm; | ||
| 761 | int err; | ||
| 762 | |||
| 763 | err = snd_pcm_new(loopback->card, "Loopback PCM", device, | ||
| 764 | substreams, substreams, &pcm); | ||
| 765 | if (err < 0) | ||
| 766 | return err; | ||
| 767 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops); | ||
| 768 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops); | ||
| 769 | |||
| 770 | pcm->private_data = loopback; | ||
| 771 | pcm->info_flags = 0; | ||
| 772 | strcpy(pcm->name, "Loopback PCM"); | ||
| 773 | |||
| 774 | loopback->pcm[device] = pcm; | ||
| 775 | |||
| 776 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | ||
| 777 | snd_dma_continuous_data(GFP_KERNEL), | ||
| 778 | 0, 2 * 1024 * 1024); | ||
| 779 | return 0; | ||
| 780 | } | ||
| 781 | |||
| 782 | static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol, | ||
| 783 | struct snd_ctl_elem_info *uinfo) | ||
| 784 | { | ||
| 785 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 786 | uinfo->count = 1; | ||
| 787 | uinfo->value.integer.min = 80000; | ||
| 788 | uinfo->value.integer.max = 120000; | ||
| 789 | uinfo->value.integer.step = 1; | ||
| 790 | return 0; | ||
| 791 | } | ||
| 792 | |||
| 793 | static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, | ||
| 794 | struct snd_ctl_elem_value *ucontrol) | ||
| 795 | { | ||
| 796 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
| 797 | |||
| 798 | ucontrol->value.integer.value[0] = | ||
| 799 | loopback->setup[kcontrol->id.subdevice] | ||
| 800 | [kcontrol->id.device].rate_shift; | ||
| 801 | return 0; | ||
| 802 | } | ||
| 803 | |||
| 804 | static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol, | ||
| 805 | struct snd_ctl_elem_value *ucontrol) | ||
| 806 | { | ||
| 807 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
| 808 | unsigned int val; | ||
| 809 | int change = 0; | ||
| 810 | |||
| 811 | val = ucontrol->value.integer.value[0]; | ||
| 812 | if (val < 80000) | ||
| 813 | val = 80000; | ||
| 814 | if (val > 120000) | ||
| 815 | val = 120000; | ||
| 816 | mutex_lock(&loopback->cable_lock); | ||
| 817 | if (val != loopback->setup[kcontrol->id.subdevice] | ||
| 818 | [kcontrol->id.device].rate_shift) { | ||
| 819 | loopback->setup[kcontrol->id.subdevice] | ||
| 820 | [kcontrol->id.device].rate_shift = val; | ||
| 821 | change = 1; | ||
| 822 | } | ||
| 823 | mutex_unlock(&loopback->cable_lock); | ||
| 824 | return change; | ||
| 825 | } | ||
| 826 | |||
| 827 | static int loopback_notify_get(struct snd_kcontrol *kcontrol, | ||
| 828 | struct snd_ctl_elem_value *ucontrol) | ||
| 829 | { | ||
| 830 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
| 831 | |||
| 832 | ucontrol->value.integer.value[0] = | ||
| 833 | loopback->setup[kcontrol->id.subdevice] | ||
| 834 | [kcontrol->id.device].notify; | ||
| 835 | return 0; | ||
| 836 | } | ||
| 837 | |||
| 838 | static int loopback_notify_put(struct snd_kcontrol *kcontrol, | ||
| 839 | struct snd_ctl_elem_value *ucontrol) | ||
| 840 | { | ||
| 841 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
| 842 | unsigned int val; | ||
| 843 | int change = 0; | ||
| 844 | |||
| 845 | val = ucontrol->value.integer.value[0] ? 1 : 0; | ||
| 846 | if (val != loopback->setup[kcontrol->id.subdevice] | ||
| 847 | [kcontrol->id.device].notify) { | ||
| 848 | loopback->setup[kcontrol->id.subdevice] | ||
| 849 | [kcontrol->id.device].notify = val; | ||
| 850 | change = 1; | ||
| 851 | } | ||
| 852 | return change; | ||
| 853 | } | ||
| 854 | |||
| 855 | static int loopback_active_get(struct snd_kcontrol *kcontrol, | ||
| 856 | struct snd_ctl_elem_value *ucontrol) | ||
| 857 | { | ||
| 858 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
| 859 | struct loopback_cable *cable = loopback->cables | ||
| 860 | [kcontrol->id.subdevice][kcontrol->id.device ^ 1]; | ||
| 861 | unsigned int val = 0; | ||
| 862 | |||
| 863 | if (cable != NULL) | ||
| 864 | val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? | ||
| 865 | 1 : 0; | ||
| 866 | ucontrol->value.integer.value[0] = val; | ||
| 867 | return 0; | ||
| 868 | } | ||
| 869 | |||
| 870 | static int loopback_format_info(struct snd_kcontrol *kcontrol, | ||
| 871 | struct snd_ctl_elem_info *uinfo) | ||
| 872 | { | ||
| 873 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 874 | uinfo->count = 1; | ||
| 875 | uinfo->value.integer.min = 0; | ||
| 876 | uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST; | ||
| 877 | uinfo->value.integer.step = 1; | ||
| 878 | return 0; | ||
| 879 | } | ||
| 880 | |||
| 881 | static int loopback_format_get(struct snd_kcontrol *kcontrol, | ||
| 882 | struct snd_ctl_elem_value *ucontrol) | ||
| 883 | { | ||
| 884 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
| 885 | |||
| 886 | ucontrol->value.integer.value[0] = | ||
| 887 | loopback->setup[kcontrol->id.subdevice] | ||
| 888 | [kcontrol->id.device].format; | ||
| 889 | return 0; | ||
| 890 | } | ||
| 891 | |||
| 892 | static int loopback_rate_info(struct snd_kcontrol *kcontrol, | ||
| 893 | struct snd_ctl_elem_info *uinfo) | ||
| 894 | { | ||
| 895 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 896 | uinfo->count = 1; | ||
| 897 | uinfo->value.integer.min = 0; | ||
| 898 | uinfo->value.integer.max = 192000; | ||
| 899 | uinfo->value.integer.step = 1; | ||
| 900 | return 0; | ||
| 901 | } | ||
| 902 | |||
| 903 | static int loopback_rate_get(struct snd_kcontrol *kcontrol, | ||
| 904 | struct snd_ctl_elem_value *ucontrol) | ||
| 905 | { | ||
| 906 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
| 907 | |||
| 908 | ucontrol->value.integer.value[0] = | ||
| 909 | loopback->setup[kcontrol->id.subdevice] | ||
| 910 | [kcontrol->id.device].rate; | ||
| 911 | return 0; | ||
| 912 | } | ||
| 913 | |||
| 914 | static int loopback_channels_info(struct snd_kcontrol *kcontrol, | ||
| 915 | struct snd_ctl_elem_info *uinfo) | ||
| 916 | { | ||
| 917 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 918 | uinfo->count = 1; | ||
| 919 | uinfo->value.integer.min = 1; | ||
| 920 | uinfo->value.integer.max = 1024; | ||
| 921 | uinfo->value.integer.step = 1; | ||
| 922 | return 0; | ||
| 923 | } | ||
| 924 | |||
| 925 | static int loopback_channels_get(struct snd_kcontrol *kcontrol, | ||
| 926 | struct snd_ctl_elem_value *ucontrol) | ||
| 927 | { | ||
| 928 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
| 929 | |||
| 930 | ucontrol->value.integer.value[0] = | ||
| 931 | loopback->setup[kcontrol->id.subdevice] | ||
| 932 | [kcontrol->id.device].channels; | ||
| 933 | return 0; | ||
| 934 | } | ||
| 935 | |||
| 936 | static struct snd_kcontrol_new loopback_controls[] __devinitdata = { | ||
| 937 | { | ||
| 938 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
| 939 | .name = "PCM Rate Shift 100000", | ||
| 940 | .info = loopback_rate_shift_info, | ||
| 941 | .get = loopback_rate_shift_get, | ||
| 942 | .put = loopback_rate_shift_put, | ||
| 943 | }, | ||
| 944 | { | ||
| 945 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
| 946 | .name = "PCM Notify", | ||
| 947 | .info = snd_ctl_boolean_mono_info, | ||
| 948 | .get = loopback_notify_get, | ||
| 949 | .put = loopback_notify_put, | ||
| 950 | }, | ||
| 951 | #define ACTIVE_IDX 2 | ||
| 952 | { | ||
| 953 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
| 954 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
| 955 | .name = "PCM Slave Active", | ||
| 956 | .info = snd_ctl_boolean_mono_info, | ||
| 957 | .get = loopback_active_get, | ||
| 958 | }, | ||
| 959 | #define FORMAT_IDX 3 | ||
| 960 | { | ||
| 961 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
| 962 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
| 963 | .name = "PCM Slave Format", | ||
| 964 | .info = loopback_format_info, | ||
| 965 | .get = loopback_format_get | ||
| 966 | }, | ||
| 967 | #define RATE_IDX 4 | ||
| 968 | { | ||
| 969 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
| 970 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
| 971 | .name = "PCM Slave Rate", | ||
| 972 | .info = loopback_rate_info, | ||
| 973 | .get = loopback_rate_get | ||
| 974 | }, | ||
| 975 | #define CHANNELS_IDX 5 | ||
| 976 | { | ||
| 977 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
| 978 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
| 979 | .name = "PCM Slave Channels", | ||
| 980 | .info = loopback_channels_info, | ||
| 981 | .get = loopback_channels_get | ||
| 982 | } | ||
| 983 | }; | ||
| 984 | |||
| 985 | static int __devinit loopback_mixer_new(struct loopback *loopback, int notify) | ||
| 986 | { | ||
| 987 | struct snd_card *card = loopback->card; | ||
| 988 | struct snd_pcm *pcm; | ||
| 989 | struct snd_kcontrol *kctl; | ||
| 990 | struct loopback_setup *setup; | ||
| 991 | int err, dev, substr, substr_count, idx; | ||
| 992 | |||
| 993 | strcpy(card->mixername, "Loopback Mixer"); | ||
| 994 | for (dev = 0; dev < 2; dev++) { | ||
| 995 | pcm = loopback->pcm[dev]; | ||
| 996 | substr_count = | ||
| 997 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count; | ||
| 998 | for (substr = 0; substr < substr_count; substr++) { | ||
| 999 | setup = &loopback->setup[substr][dev]; | ||
| 1000 | setup->notify = notify; | ||
| 1001 | setup->rate_shift = NO_PITCH; | ||
| 1002 | setup->format = SNDRV_PCM_FORMAT_S16_LE; | ||
| 1003 | setup->rate = 48000; | ||
| 1004 | setup->channels = 2; | ||
| 1005 | for (idx = 0; idx < ARRAY_SIZE(loopback_controls); | ||
| 1006 | idx++) { | ||
| 1007 | kctl = snd_ctl_new1(&loopback_controls[idx], | ||
| 1008 | loopback); | ||
| 1009 | if (!kctl) | ||
| 1010 | return -ENOMEM; | ||
| 1011 | kctl->id.device = dev; | ||
| 1012 | kctl->id.subdevice = substr; | ||
| 1013 | switch (idx) { | ||
| 1014 | case ACTIVE_IDX: | ||
| 1015 | setup->active_id = kctl->id; | ||
| 1016 | break; | ||
| 1017 | case FORMAT_IDX: | ||
| 1018 | setup->format_id = kctl->id; | ||
| 1019 | break; | ||
| 1020 | case RATE_IDX: | ||
| 1021 | setup->rate_id = kctl->id; | ||
| 1022 | break; | ||
| 1023 | case CHANNELS_IDX: | ||
| 1024 | setup->channels_id = kctl->id; | ||
| 1025 | break; | ||
| 1026 | default: | ||
| 1027 | break; | ||
| 1028 | } | ||
| 1029 | err = snd_ctl_add(card, kctl); | ||
| 1030 | if (err < 0) | ||
| 1031 | return err; | ||
| 1032 | } | ||
| 1033 | } | ||
| 1034 | } | ||
| 1035 | return 0; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | #ifdef CONFIG_PROC_FS | ||
| 1039 | |||
| 1040 | static void print_dpcm_info(struct snd_info_buffer *buffer, | ||
| 1041 | struct loopback_pcm *dpcm, | ||
| 1042 | const char *id) | ||
| 1043 | { | ||
| 1044 | snd_iprintf(buffer, " %s\n", id); | ||
| 1045 | if (dpcm == NULL) { | ||
| 1046 | snd_iprintf(buffer, " inactive\n"); | ||
| 1047 | return; | ||
| 1048 | } | ||
| 1049 | snd_iprintf(buffer, " buffer_size:\t%u\n", dpcm->pcm_buffer_size); | ||
| 1050 | snd_iprintf(buffer, " buffer_pos:\t\t%u\n", dpcm->buf_pos); | ||
| 1051 | snd_iprintf(buffer, " silent_size:\t%u\n", dpcm->silent_size); | ||
| 1052 | snd_iprintf(buffer, " period_size:\t%u\n", dpcm->pcm_period_size); | ||
| 1053 | snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps); | ||
| 1054 | snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign); | ||
| 1055 | snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift); | ||
| 1056 | snd_iprintf(buffer, " update_pending:\t%u\n", | ||
| 1057 | dpcm->period_update_pending); | ||
| 1058 | snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); | ||
| 1059 | snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); | ||
| 1060 | snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", | ||
| 1061 | dpcm->last_jiffies, jiffies); | ||
| 1062 | snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | static void print_substream_info(struct snd_info_buffer *buffer, | ||
| 1066 | struct loopback *loopback, | ||
| 1067 | int sub, | ||
| 1068 | int num) | ||
| 1069 | { | ||
| 1070 | struct loopback_cable *cable = loopback->cables[sub][num]; | ||
| 1071 | |||
| 1072 | snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub); | ||
| 1073 | if (cable == NULL) { | ||
| 1074 | snd_iprintf(buffer, " inactive\n"); | ||
| 1075 | return; | ||
| 1076 | } | ||
| 1077 | snd_iprintf(buffer, " valid: %u\n", cable->valid); | ||
| 1078 | snd_iprintf(buffer, " running: %u\n", cable->running); | ||
| 1079 | snd_iprintf(buffer, " pause: %u\n", cable->pause); | ||
| 1080 | print_dpcm_info(buffer, cable->streams[0], "Playback"); | ||
| 1081 | print_dpcm_info(buffer, cable->streams[1], "Capture"); | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | static void print_cable_info(struct snd_info_entry *entry, | ||
| 1085 | struct snd_info_buffer *buffer) | ||
| 1086 | { | ||
| 1087 | struct loopback *loopback = entry->private_data; | ||
| 1088 | int sub, num; | ||
| 1089 | |||
| 1090 | mutex_lock(&loopback->cable_lock); | ||
| 1091 | num = entry->name[strlen(entry->name)-1]; | ||
| 1092 | num = num == '0' ? 0 : 1; | ||
| 1093 | for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++) | ||
| 1094 | print_substream_info(buffer, loopback, sub, num); | ||
| 1095 | mutex_unlock(&loopback->cable_lock); | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | static int __devinit loopback_proc_new(struct loopback *loopback, int cidx) | ||
| 1099 | { | ||
| 1100 | char name[32]; | ||
| 1101 | struct snd_info_entry *entry; | ||
| 1102 | int err; | ||
| 1103 | |||
| 1104 | snprintf(name, sizeof(name), "cable#%d", cidx); | ||
| 1105 | err = snd_card_proc_new(loopback->card, name, &entry); | ||
| 1106 | if (err < 0) | ||
| 1107 | return err; | ||
| 1108 | |||
| 1109 | snd_info_set_text_ops(entry, loopback, print_cable_info); | ||
| 1110 | return 0; | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | #else /* !CONFIG_PROC_FS */ | ||
| 1114 | |||
| 1115 | #define loopback_proc_new(loopback, cidx) do { } while (0) | ||
| 1116 | |||
| 1117 | #endif | ||
| 1118 | |||
| 1119 | static int __devinit loopback_probe(struct platform_device *devptr) | ||
| 1120 | { | ||
| 1121 | struct snd_card *card; | ||
| 1122 | struct loopback *loopback; | ||
| 1123 | int dev = devptr->id; | ||
| 1124 | int err; | ||
| 1125 | |||
| 1126 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, | ||
| 1127 | sizeof(struct loopback), &card); | ||
| 1128 | if (err < 0) | ||
| 1129 | return err; | ||
| 1130 | loopback = card->private_data; | ||
| 1131 | |||
| 1132 | if (pcm_substreams[dev] < 1) | ||
| 1133 | pcm_substreams[dev] = 1; | ||
| 1134 | if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS) | ||
| 1135 | pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; | ||
| 1136 | |||
| 1137 | loopback->card = card; | ||
| 1138 | mutex_init(&loopback->cable_lock); | ||
| 1139 | |||
| 1140 | err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]); | ||
| 1141 | if (err < 0) | ||
| 1142 | goto __nodev; | ||
| 1143 | err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]); | ||
| 1144 | if (err < 0) | ||
| 1145 | goto __nodev; | ||
| 1146 | err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); | ||
| 1147 | if (err < 0) | ||
| 1148 | goto __nodev; | ||
| 1149 | loopback_proc_new(loopback, 0); | ||
| 1150 | loopback_proc_new(loopback, 1); | ||
| 1151 | strcpy(card->driver, "Loopback"); | ||
| 1152 | strcpy(card->shortname, "Loopback"); | ||
| 1153 | sprintf(card->longname, "Loopback %i", dev + 1); | ||
| 1154 | err = snd_card_register(card); | ||
| 1155 | if (!err) { | ||
| 1156 | platform_set_drvdata(devptr, card); | ||
| 1157 | return 0; | ||
| 1158 | } | ||
| 1159 | __nodev: | ||
| 1160 | snd_card_free(card); | ||
| 1161 | return err; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | static int __devexit loopback_remove(struct platform_device *devptr) | ||
| 1165 | { | ||
| 1166 | snd_card_free(platform_get_drvdata(devptr)); | ||
| 1167 | platform_set_drvdata(devptr, NULL); | ||
| 1168 | return 0; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | #ifdef CONFIG_PM | ||
| 1172 | static int loopback_suspend(struct platform_device *pdev, | ||
| 1173 | pm_message_t state) | ||
| 1174 | { | ||
| 1175 | struct snd_card *card = platform_get_drvdata(pdev); | ||
| 1176 | struct loopback *loopback = card->private_data; | ||
| 1177 | |||
| 1178 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
| 1179 | |||
| 1180 | snd_pcm_suspend_all(loopback->pcm[0]); | ||
| 1181 | snd_pcm_suspend_all(loopback->pcm[1]); | ||
| 1182 | return 0; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | static int loopback_resume(struct platform_device *pdev) | ||
| 1186 | { | ||
| 1187 | struct snd_card *card = platform_get_drvdata(pdev); | ||
| 1188 | |||
| 1189 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
| 1190 | return 0; | ||
| 1191 | } | ||
| 1192 | #endif | ||
| 1193 | |||
| 1194 | #define SND_LOOPBACK_DRIVER "snd_aloop" | ||
| 1195 | |||
| 1196 | static struct platform_driver loopback_driver = { | ||
| 1197 | .probe = loopback_probe, | ||
| 1198 | .remove = __devexit_p(loopback_remove), | ||
| 1199 | #ifdef CONFIG_PM | ||
| 1200 | .suspend = loopback_suspend, | ||
| 1201 | .resume = loopback_resume, | ||
| 1202 | #endif | ||
| 1203 | .driver = { | ||
| 1204 | .name = SND_LOOPBACK_DRIVER | ||
| 1205 | }, | ||
| 1206 | }; | ||
| 1207 | |||
| 1208 | static void loopback_unregister_all(void) | ||
| 1209 | { | ||
| 1210 | int i; | ||
| 1211 | |||
| 1212 | for (i = 0; i < ARRAY_SIZE(devices); ++i) | ||
| 1213 | platform_device_unregister(devices[i]); | ||
| 1214 | platform_driver_unregister(&loopback_driver); | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | static int __init alsa_card_loopback_init(void) | ||
| 1218 | { | ||
| 1219 | int i, err, cards; | ||
| 1220 | |||
| 1221 | err = platform_driver_register(&loopback_driver); | ||
| 1222 | if (err < 0) | ||
| 1223 | return err; | ||
| 1224 | |||
| 1225 | |||
| 1226 | cards = 0; | ||
| 1227 | for (i = 0; i < SNDRV_CARDS; i++) { | ||
| 1228 | struct platform_device *device; | ||
| 1229 | if (!enable[i]) | ||
| 1230 | continue; | ||
| 1231 | device = platform_device_register_simple(SND_LOOPBACK_DRIVER, | ||
| 1232 | i, NULL, 0); | ||
| 1233 | if (IS_ERR(device)) | ||
| 1234 | continue; | ||
| 1235 | if (!platform_get_drvdata(device)) { | ||
| 1236 | platform_device_unregister(device); | ||
| 1237 | continue; | ||
| 1238 | } | ||
| 1239 | devices[i] = device; | ||
| 1240 | cards++; | ||
| 1241 | } | ||
| 1242 | if (!cards) { | ||
| 1243 | #ifdef MODULE | ||
| 1244 | printk(KERN_ERR "aloop: No loopback enabled\n"); | ||
| 1245 | #endif | ||
| 1246 | loopback_unregister_all(); | ||
| 1247 | return -ENODEV; | ||
| 1248 | } | ||
| 1249 | return 0; | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | static void __exit alsa_card_loopback_exit(void) | ||
| 1253 | { | ||
| 1254 | loopback_unregister_all(); | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | module_init(alsa_card_loopback_init) | ||
| 1258 | module_exit(alsa_card_loopback_exit) | ||
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 0e631c3221e3..f4cd49336f33 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c | |||
| @@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr) | |||
| 94 | sizeof(struct snd_card_virmidi), &card); | 94 | sizeof(struct snd_card_virmidi), &card); |
| 95 | if (err < 0) | 95 | if (err < 0) |
| 96 | return err; | 96 | return err; |
| 97 | vmidi = (struct snd_card_virmidi *)card->private_data; | 97 | vmidi = card->private_data; |
| 98 | vmidi->card = card; | 98 | vmidi->card = card; |
| 99 | 99 | ||
| 100 | if (midi_devs[dev] > MAX_MIDI_DEVICES) { | 100 | if (midi_devs[dev] > MAX_MIDI_DEVICES) { |
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 42d7844ecd0b..57ccba88700d 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c | |||
| @@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) | |||
| 878 | static void proc_regs_read(struct snd_info_entry *entry, | 878 | static void proc_regs_read(struct snd_info_entry *entry, |
| 879 | struct snd_info_buffer *buffer) | 879 | struct snd_info_buffer *buffer) |
| 880 | { | 880 | { |
| 881 | struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data; | 881 | struct snd_akm4xxx *ak = entry->private_data; |
| 882 | int reg, val, chip; | 882 | int reg, val, chip; |
| 883 | for (chip = 0; chip < ak->num_chips; chip++) { | 883 | for (chip = 0; chip < ak->num_chips; chip++) { |
| 884 | for (reg = 0; reg < ak->total_regs; reg++) { | 884 | for (reg = 0; reg < ak->total_regs; reg++) { |
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index c6990c680796..52064cfa91f3 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
| @@ -77,6 +77,32 @@ config SND_ALS100 | |||
| 77 | To compile this driver as a module, choose M here: the module | 77 | To compile this driver as a module, choose M here: the module |
| 78 | will be called snd-als100. | 78 | will be called snd-als100. |
| 79 | 79 | ||
| 80 | config SND_AZT1605 | ||
| 81 | tristate "Aztech AZT1605 Driver" | ||
| 82 | depends on SND | ||
| 83 | select SND_WSS_LIB | ||
| 84 | select SND_MPU401_UART | ||
| 85 | select SND_OPL3_LIB | ||
| 86 | help | ||
| 87 | Say Y here to include support for Aztech Sound Galaxy cards | ||
| 88 | based on the AZT1605 chipset. | ||
| 89 | |||
| 90 | To compile this driver as a module, choose M here: the module | ||
| 91 | will be called snd-azt1605. | ||
| 92 | |||
| 93 | config SND_AZT2316 | ||
| 94 | tristate "Aztech AZT2316 Driver" | ||
| 95 | depends on SND | ||
| 96 | select SND_WSS_LIB | ||
| 97 | select SND_MPU401_UART | ||
| 98 | select SND_OPL3_LIB | ||
| 99 | help | ||
| 100 | Say Y here to include support for Aztech Sound Galaxy cards | ||
| 101 | based on the AZT2316 chipset. | ||
| 102 | |||
| 103 | To compile this driver as a module, choose M here: the module | ||
| 104 | will be called snd-azt2316. | ||
| 105 | |||
| 80 | config SND_AZT2320 | 106 | config SND_AZT2320 |
| 81 | tristate "Aztech Systems AZT2320" | 107 | tristate "Aztech Systems AZT2320" |
| 82 | depends on PNP | 108 | depends on PNP |
| @@ -351,16 +377,6 @@ config SND_SB16_CSP | |||
| 351 | coprocessor can do variable tasks like various compression and | 377 | coprocessor can do variable tasks like various compression and |
| 352 | decompression algorithms. | 378 | decompression algorithms. |
| 353 | 379 | ||
| 354 | config SND_SGALAXY | ||
| 355 | tristate "Aztech Sound Galaxy" | ||
| 356 | select SND_WSS_LIB | ||
| 357 | help | ||
| 358 | Say Y here to include support for Aztech Sound Galaxy | ||
| 359 | soundcards. | ||
| 360 | |||
| 361 | To compile this driver as a module, choose M here: the module | ||
| 362 | will be called snd-sgalaxy. | ||
| 363 | |||
| 364 | config SND_SSCAPE | 380 | config SND_SSCAPE |
| 365 | tristate "Ensoniq SoundScape driver" | 381 | tristate "Ensoniq SoundScape driver" |
| 366 | select SND_MPU401_UART | 382 | select SND_MPU401_UART |
diff --git a/sound/isa/Makefile b/sound/isa/Makefile index c73d30c4f462..8d781e419e2e 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile | |||
| @@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o | |||
| 10 | snd-es18xx-objs := es18xx.o | 10 | snd-es18xx-objs := es18xx.o |
| 11 | snd-opl3sa2-objs := opl3sa2.o | 11 | snd-opl3sa2-objs := opl3sa2.o |
| 12 | snd-sc6000-objs := sc6000.o | 12 | snd-sc6000-objs := sc6000.o |
| 13 | snd-sgalaxy-objs := sgalaxy.o | ||
| 14 | snd-sscape-objs := sscape.o | 13 | snd-sscape-objs := sscape.o |
| 15 | 14 | ||
| 16 | # Toplevel Module Dependency | 15 | # Toplevel Module Dependency |
| @@ -21,8 +20,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o | |||
| 21 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o | 20 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o |
| 22 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o | 21 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o |
| 23 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o | 22 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o |
| 24 | obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o | ||
| 25 | obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o | 23 | obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o |
| 26 | 24 | ||
| 27 | obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \ | 25 | obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \ |
| 28 | sb/ wavefront/ wss/ | 26 | sb/ wavefront/ wss/ |
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index bbcbf92a8ebe..3cb75bc97699 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c | |||
| @@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard | |||
| 162 | sizeof(struct snd_card_ad1816a), &card); | 162 | sizeof(struct snd_card_ad1816a), &card); |
| 163 | if (error < 0) | 163 | if (error < 0) |
| 164 | return error; | 164 | return error; |
| 165 | acard = (struct snd_card_ad1816a *)card->private_data; | 165 | acard = card->private_data; |
| 166 | 166 | ||
| 167 | if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) { | 167 | if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) { |
| 168 | snd_card_free(card); | 168 | snd_card_free(card); |
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index f7aa637b0d18..aac8dc15c2fe 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c | |||
| @@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev, | |||
| 188 | sizeof(struct snd_card_azt2320), &card); | 188 | sizeof(struct snd_card_azt2320), &card); |
| 189 | if (error < 0) | 189 | if (error < 0) |
| 190 | return error; | 190 | return error; |
| 191 | acard = (struct snd_card_azt2320 *)card->private_data; | 191 | acard = card->private_data; |
| 192 | 192 | ||
| 193 | if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) { | 193 | if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) { |
| 194 | snd_card_free(card); | 194 | snd_card_free(card); |
diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile new file mode 100644 index 000000000000..e307066d4315 --- /dev/null +++ b/sound/isa/galaxy/Makefile | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # | ||
| 2 | # Makefile for ALSA | ||
| 3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> | ||
| 4 | # | ||
| 5 | |||
| 6 | snd-azt1605-objs := azt1605.o | ||
| 7 | snd-azt2316-objs := azt2316.o | ||
| 8 | |||
| 9 | obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o | ||
| 10 | obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o | ||
diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c new file mode 100644 index 000000000000..9a97643cb713 --- /dev/null +++ b/sound/isa/galaxy/azt1605.c | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | /* | ||
| 2 | * Aztech AZT1605 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 | |||
| 20 | #define AZT1605 | ||
| 21 | |||
| 22 | #define CRD_NAME "Aztech AZT1605" | ||
| 23 | #define DRV_NAME "AZT1605" | ||
| 24 | #define DEV_NAME "azt1605" | ||
| 25 | |||
| 26 | #define GALAXY_DSP_MAJOR 2 | ||
| 27 | #define GALAXY_DSP_MINOR 1 | ||
| 28 | |||
| 29 | #define GALAXY_CONFIG_SIZE 3 | ||
| 30 | |||
| 31 | /* | ||
| 32 | * 24-bit config register | ||
| 33 | */ | ||
| 34 | |||
| 35 | #define GALAXY_CONFIG_SBA_220 (0 << 0) | ||
| 36 | #define GALAXY_CONFIG_SBA_240 (1 << 0) | ||
| 37 | #define GALAXY_CONFIG_SBA_260 (2 << 0) | ||
| 38 | #define GALAXY_CONFIG_SBA_280 (3 << 0) | ||
| 39 | #define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 | ||
| 40 | |||
| 41 | #define GALAXY_CONFIG_MPUA_300 (0 << 2) | ||
| 42 | #define GALAXY_CONFIG_MPUA_330 (1 << 2) | ||
| 43 | |||
| 44 | #define GALAXY_CONFIG_MPU_ENABLE (1 << 3) | ||
| 45 | |||
| 46 | #define GALAXY_CONFIG_GAME_ENABLE (1 << 4) | ||
| 47 | |||
| 48 | #define GALAXY_CONFIG_CD_PANASONIC (1 << 5) | ||
| 49 | #define GALAXY_CONFIG_CD_MITSUMI (1 << 6) | ||
| 50 | #define GALAXY_CONFIG_CD_MASK (\ | ||
| 51 | GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI) | ||
| 52 | |||
| 53 | #define GALAXY_CONFIG_UNUSED (1 << 7) | ||
| 54 | #define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED | ||
| 55 | |||
| 56 | #define GALAXY_CONFIG_SBIRQ_2 (1 << 8) | ||
| 57 | #define GALAXY_CONFIG_SBIRQ_3 (1 << 9) | ||
| 58 | #define GALAXY_CONFIG_SBIRQ_5 (1 << 10) | ||
| 59 | #define GALAXY_CONFIG_SBIRQ_7 (1 << 11) | ||
| 60 | |||
| 61 | #define GALAXY_CONFIG_MPUIRQ_2 (1 << 12) | ||
| 62 | #define GALAXY_CONFIG_MPUIRQ_3 (1 << 13) | ||
| 63 | #define GALAXY_CONFIG_MPUIRQ_5 (1 << 14) | ||
| 64 | #define GALAXY_CONFIG_MPUIRQ_7 (1 << 15) | ||
| 65 | |||
| 66 | #define GALAXY_CONFIG_WSSA_530 (0 << 16) | ||
| 67 | #define GALAXY_CONFIG_WSSA_604 (1 << 16) | ||
| 68 | #define GALAXY_CONFIG_WSSA_E80 (2 << 16) | ||
| 69 | #define GALAXY_CONFIG_WSSA_F40 (3 << 16) | ||
| 70 | |||
| 71 | #define GALAXY_CONFIG_WSS_ENABLE (1 << 18) | ||
| 72 | |||
| 73 | #define GALAXY_CONFIG_CDIRQ_11 (1 << 19) | ||
| 74 | #define GALAXY_CONFIG_CDIRQ_12 (1 << 20) | ||
| 75 | #define GALAXY_CONFIG_CDIRQ_15 (1 << 21) | ||
| 76 | #define GALAXY_CONFIG_CDIRQ_MASK (\ | ||
| 77 | GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\ | ||
| 78 | GALAXY_CONFIG_CDIRQ_15) | ||
| 79 | |||
| 80 | #define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22) | ||
| 81 | #define GALAXY_CONFIG_CDDMA_0 (1 << 22) | ||
| 82 | #define GALAXY_CONFIG_CDDMA_1 (2 << 22) | ||
| 83 | #define GALAXY_CONFIG_CDDMA_3 (3 << 22) | ||
| 84 | #define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3 | ||
| 85 | |||
| 86 | #define GALAXY_CONFIG_MASK (\ | ||
| 87 | GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\ | ||
| 88 | GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\ | ||
| 89 | GALAXY_CONFIG_CDDMA_MASK) | ||
| 90 | |||
| 91 | #include "galaxy.c" | ||
diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c new file mode 100644 index 000000000000..189441141df6 --- /dev/null +++ b/sound/isa/galaxy/azt2316.c | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | /* | ||
| 2 | * Aztech 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 | |||
| 20 | #define AZT2316 | ||
| 21 | |||
| 22 | #define CRD_NAME "Aztech AZT2316" | ||
| 23 | #define DRV_NAME "AZT2316" | ||
| 24 | #define DEV_NAME "azt2316" | ||
| 25 | |||
| 26 | #define GALAXY_DSP_MAJOR 3 | ||
| 27 | #define GALAXY_DSP_MINOR 1 | ||
| 28 | |||
| 29 | #define GALAXY_CONFIG_SIZE 4 | ||
| 30 | |||
| 31 | /* | ||
| 32 | * 32-bit config register | ||
| 33 | */ | ||
| 34 | |||
| 35 | #define GALAXY_CONFIG_SBA_220 (0 << 0) | ||
| 36 | #define GALAXY_CONFIG_SBA_240 (1 << 0) | ||
| 37 | #define GALAXY_CONFIG_SBA_260 (2 << 0) | ||
| 38 | #define GALAXY_CONFIG_SBA_280 (3 << 0) | ||
| 39 | #define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 | ||
| 40 | |||
| 41 | #define GALAXY_CONFIG_SBIRQ_2 (1 << 2) | ||
| 42 | #define GALAXY_CONFIG_SBIRQ_5 (1 << 3) | ||
| 43 | #define GALAXY_CONFIG_SBIRQ_7 (1 << 4) | ||
| 44 | #define GALAXY_CONFIG_SBIRQ_10 (1 << 5) | ||
| 45 | |||
| 46 | #define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6) | ||
| 47 | #define GALAXY_CONFIG_SBDMA_0 (1 << 6) | ||
| 48 | #define GALAXY_CONFIG_SBDMA_1 (2 << 6) | ||
| 49 | #define GALAXY_CONFIG_SBDMA_3 (3 << 6) | ||
| 50 | |||
| 51 | #define GALAXY_CONFIG_WSSA_530 (0 << 8) | ||
| 52 | #define GALAXY_CONFIG_WSSA_604 (1 << 8) | ||
| 53 | #define GALAXY_CONFIG_WSSA_E80 (2 << 8) | ||
| 54 | #define GALAXY_CONFIG_WSSA_F40 (3 << 8) | ||
| 55 | |||
| 56 | #define GALAXY_CONFIG_WSS_ENABLE (1 << 10) | ||
| 57 | |||
| 58 | #define GALAXY_CONFIG_GAME_ENABLE (1 << 11) | ||
| 59 | |||
| 60 | #define GALAXY_CONFIG_MPUA_300 (0 << 12) | ||
| 61 | #define GALAXY_CONFIG_MPUA_330 (1 << 12) | ||
| 62 | |||
| 63 | #define GALAXY_CONFIG_MPU_ENABLE (1 << 13) | ||
| 64 | |||
| 65 | #define GALAXY_CONFIG_CDA_310 (0 << 14) | ||
| 66 | #define GALAXY_CONFIG_CDA_320 (1 << 14) | ||
| 67 | #define GALAXY_CONFIG_CDA_340 (2 << 14) | ||
| 68 | #define GALAXY_CONFIG_CDA_350 (3 << 14) | ||
| 69 | #define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350 | ||
| 70 | |||
| 71 | #define GALAXY_CONFIG_CD_DISABLE (0 << 16) | ||
| 72 | #define GALAXY_CONFIG_CD_PANASONIC (1 << 16) | ||
| 73 | #define GALAXY_CONFIG_CD_SONY (2 << 16) | ||
| 74 | #define GALAXY_CONFIG_CD_MITSUMI (3 << 16) | ||
| 75 | #define GALAXY_CONFIG_CD_AZTECH (4 << 16) | ||
| 76 | #define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16) | ||
| 77 | #define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16) | ||
| 78 | #define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16) | ||
| 79 | #define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7 | ||
| 80 | |||
| 81 | #define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20) | ||
| 82 | #define GALAXY_CONFIG_CDDMA8_0 (1 << 20) | ||
| 83 | #define GALAXY_CONFIG_CDDMA8_1 (2 << 20) | ||
| 84 | #define GALAXY_CONFIG_CDDMA8_3 (3 << 20) | ||
| 85 | #define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3 | ||
| 86 | |||
| 87 | #define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22) | ||
| 88 | #define GALAXY_CONFIG_CDDMA16_5 (1 << 22) | ||
| 89 | #define GALAXY_CONFIG_CDDMA16_6 (2 << 22) | ||
| 90 | #define GALAXY_CONFIG_CDDMA16_7 (3 << 22) | ||
| 91 | #define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7 | ||
| 92 | |||
| 93 | #define GALAXY_CONFIG_MPUIRQ_2 (1 << 24) | ||
| 94 | #define GALAXY_CONFIG_MPUIRQ_5 (1 << 25) | ||
| 95 | #define GALAXY_CONFIG_MPUIRQ_7 (1 << 26) | ||
| 96 | #define GALAXY_CONFIG_MPUIRQ_10 (1 << 27) | ||
| 97 | |||
| 98 | #define GALAXY_CONFIG_CDIRQ_5 (1 << 28) | ||
| 99 | #define GALAXY_CONFIG_CDIRQ_11 (1 << 29) | ||
| 100 | #define GALAXY_CONFIG_CDIRQ_12 (1 << 30) | ||
| 101 | #define GALAXY_CONFIG_CDIRQ_15 (1 << 31) | ||
| 102 | #define GALAXY_CONFIG_CDIRQ_MASK (\ | ||
| 103 | GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\ | ||
| 104 | GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15) | ||
| 105 | |||
| 106 | #define GALAXY_CONFIG_MASK (\ | ||
| 107 | GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\ | ||
| 108 | GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\ | ||
| 109 | GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK) | ||
| 110 | |||
| 111 | #include "galaxy.c" | ||
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c new file mode 100644 index 000000000000..ee54df082b9c --- /dev/null +++ b/sound/isa/galaxy/galaxy.c | |||
| @@ -0,0 +1,652 @@ | |||
| 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 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/isa.h> | ||
| 23 | #include <linux/delay.h> | ||
| 24 | #include <linux/io.h> | ||
| 25 | #include <asm/processor.h> | ||
| 26 | #include <sound/core.h> | ||
| 27 | #include <sound/initval.h> | ||
| 28 | #include <sound/wss.h> | ||
| 29 | #include <sound/mpu401.h> | ||
| 30 | #include <sound/opl3.h> | ||
| 31 | |||
| 32 | MODULE_DESCRIPTION(CRD_NAME); | ||
| 33 | MODULE_AUTHOR("Rene Herman"); | ||
| 34 | MODULE_LICENSE("GPL"); | ||
| 35 | |||
| 36 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
| 37 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
| 38 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; | ||
| 39 | |||
| 40 | module_param_array(index, int, NULL, 0444); | ||
| 41 | MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); | ||
| 42 | module_param_array(id, charp, NULL, 0444); | ||
| 43 | MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); | ||
| 44 | module_param_array(enable, bool, NULL, 0444); | ||
| 45 | MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); | ||
| 46 | |||
| 47 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
| 48 | static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
| 49 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
| 50 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
| 51 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
| 52 | static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
| 53 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
| 54 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
| 55 | |||
| 56 | module_param_array(port, long, NULL, 0444); | ||
| 57 | MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); | ||
| 58 | module_param_array(wss_port, long, NULL, 0444); | ||
| 59 | MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver."); | ||
| 60 | module_param_array(mpu_port, long, NULL, 0444); | ||
| 61 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver."); | ||
| 62 | module_param_array(fm_port, long, NULL, 0444); | ||
| 63 | MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver."); | ||
| 64 | module_param_array(irq, int, NULL, 0444); | ||
| 65 | MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); | ||
| 66 | module_param_array(mpu_irq, int, NULL, 0444); | ||
| 67 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver."); | ||
| 68 | module_param_array(dma1, int, NULL, 0444); | ||
| 69 | MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver."); | ||
| 70 | module_param_array(dma2, int, NULL, 0444); | ||
| 71 | MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver."); | ||
| 72 | |||
| 73 | /* | ||
| 74 | * Generic SB DSP support routines | ||
| 75 | */ | ||
| 76 | |||
| 77 | #define DSP_PORT_RESET 0x6 | ||
| 78 | #define DSP_PORT_READ 0xa | ||
| 79 | #define DSP_PORT_COMMAND 0xc | ||
| 80 | #define DSP_PORT_STATUS 0xc | ||
| 81 | #define DSP_PORT_DATA_AVAIL 0xe | ||
| 82 | |||
| 83 | #define DSP_SIGNATURE 0xaa | ||
| 84 | |||
| 85 | #define DSP_COMMAND_GET_VERSION 0xe1 | ||
| 86 | |||
| 87 | static int __devinit dsp_get_byte(void __iomem *port, u8 *val) | ||
| 88 | { | ||
| 89 | int loops = 1000; | ||
| 90 | |||
| 91 | while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) { | ||
| 92 | if (!loops--) | ||
| 93 | return -EIO; | ||
| 94 | cpu_relax(); | ||
| 95 | } | ||
| 96 | *val = ioread8(port + DSP_PORT_READ); | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int __devinit dsp_reset(void __iomem *port) | ||
| 101 | { | ||
| 102 | u8 val; | ||
| 103 | |||
| 104 | iowrite8(1, port + DSP_PORT_RESET); | ||
| 105 | udelay(10); | ||
| 106 | iowrite8(0, port + DSP_PORT_RESET); | ||
| 107 | |||
| 108 | if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE) | ||
| 109 | return -ENODEV; | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int __devinit dsp_command(void __iomem *port, u8 cmd) | ||
| 115 | { | ||
| 116 | int loops = 1000; | ||
| 117 | |||
| 118 | while (ioread8(port + DSP_PORT_STATUS) & 0x80) { | ||
| 119 | if (!loops--) | ||
| 120 | return -EIO; | ||
| 121 | cpu_relax(); | ||
| 122 | } | ||
| 123 | iowrite8(cmd, port + DSP_PORT_COMMAND); | ||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor) | ||
| 128 | { | ||
| 129 | int err; | ||
| 130 | |||
| 131 | err = dsp_command(port, DSP_COMMAND_GET_VERSION); | ||
| 132 | if (err < 0) | ||
| 133 | return err; | ||
| 134 | |||
| 135 | err = dsp_get_byte(port, major); | ||
| 136 | if (err < 0) | ||
| 137 | return err; | ||
| 138 | |||
| 139 | err = dsp_get_byte(port, minor); | ||
| 140 | if (err < 0) | ||
| 141 | return err; | ||
| 142 | |||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* | ||
| 147 | * Generic WSS support routines | ||
| 148 | */ | ||
| 149 | |||
| 150 | #define WSS_CONFIG_DMA_0 (1 << 0) | ||
| 151 | #define WSS_CONFIG_DMA_1 (2 << 0) | ||
| 152 | #define WSS_CONFIG_DMA_3 (3 << 0) | ||
| 153 | #define WSS_CONFIG_DUPLEX (1 << 2) | ||
| 154 | #define WSS_CONFIG_IRQ_7 (1 << 3) | ||
| 155 | #define WSS_CONFIG_IRQ_9 (2 << 3) | ||
| 156 | #define WSS_CONFIG_IRQ_10 (3 << 3) | ||
| 157 | #define WSS_CONFIG_IRQ_11 (4 << 3) | ||
| 158 | |||
| 159 | #define WSS_PORT_CONFIG 0 | ||
| 160 | #define WSS_PORT_SIGNATURE 3 | ||
| 161 | |||
| 162 | #define WSS_SIGNATURE 4 | ||
| 163 | |||
| 164 | static int __devinit wss_detect(void __iomem *wss_port) | ||
| 165 | { | ||
| 166 | if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE) | ||
| 167 | return -ENODEV; | ||
| 168 | |||
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | static void wss_set_config(void __iomem *wss_port, u8 wss_config) | ||
| 173 | { | ||
| 174 | iowrite8(wss_config, wss_port + WSS_PORT_CONFIG); | ||
| 175 | } | ||
| 176 | |||
| 177 | /* | ||
| 178 | * Aztech Sound Galaxy specifics | ||
| 179 | */ | ||
| 180 | |||
| 181 | #define GALAXY_PORT_CONFIG 1024 | ||
| 182 | #define CONFIG_PORT_SET 4 | ||
| 183 | |||
| 184 | #define DSP_COMMAND_GALAXY_8 8 | ||
| 185 | #define GALAXY_COMMAND_GET_TYPE 5 | ||
| 186 | |||
| 187 | #define DSP_COMMAND_GALAXY_9 9 | ||
| 188 | #define GALAXY_COMMAND_WSSMODE 0 | ||
| 189 | #define GALAXY_COMMAND_SB8MODE 1 | ||
| 190 | |||
| 191 | #define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE | ||
| 192 | #define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE | ||
| 193 | |||
| 194 | struct snd_galaxy { | ||
| 195 | void __iomem *port; | ||
| 196 | void __iomem *config_port; | ||
| 197 | void __iomem *wss_port; | ||
| 198 | u32 config; | ||
| 199 | struct resource *res_port; | ||
| 200 | struct resource *res_config_port; | ||
| 201 | struct resource *res_wss_port; | ||
| 202 | }; | ||
| 203 | |||
| 204 | static u32 config[SNDRV_CARDS]; | ||
| 205 | static u8 wss_config[SNDRV_CARDS]; | ||
| 206 | |||
| 207 | static int __devinit snd_galaxy_match(struct device *dev, unsigned int n) | ||
| 208 | { | ||
| 209 | if (!enable[n]) | ||
| 210 | return 0; | ||
| 211 | |||
| 212 | switch (port[n]) { | ||
| 213 | case SNDRV_AUTO_PORT: | ||
| 214 | dev_err(dev, "please specify port\n"); | ||
| 215 | return 0; | ||
| 216 | case 0x220: | ||
| 217 | config[n] |= GALAXY_CONFIG_SBA_220; | ||
| 218 | break; | ||
| 219 | case 0x240: | ||
| 220 | config[n] |= GALAXY_CONFIG_SBA_240; | ||
| 221 | break; | ||
| 222 | case 0x260: | ||
| 223 | config[n] |= GALAXY_CONFIG_SBA_260; | ||
| 224 | break; | ||
| 225 | case 0x280: | ||
| 226 | config[n] |= GALAXY_CONFIG_SBA_280; | ||
| 227 | break; | ||
| 228 | default: | ||
| 229 | dev_err(dev, "invalid port %#lx\n", port[n]); | ||
| 230 | return 0; | ||
| 231 | } | ||
| 232 | |||
| 233 | switch (wss_port[n]) { | ||
| 234 | case SNDRV_AUTO_PORT: | ||
| 235 | dev_err(dev, "please specify wss_port\n"); | ||
| 236 | return 0; | ||
| 237 | case 0x530: | ||
| 238 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530; | ||
| 239 | break; | ||
| 240 | case 0x604: | ||
| 241 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604; | ||
| 242 | break; | ||
| 243 | case 0xe80: | ||
| 244 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80; | ||
| 245 | break; | ||
| 246 | case 0xf40: | ||
| 247 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40; | ||
| 248 | break; | ||
| 249 | default: | ||
| 250 | dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]); | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | switch (irq[n]) { | ||
| 255 | case SNDRV_AUTO_IRQ: | ||
| 256 | dev_err(dev, "please specify irq\n"); | ||
| 257 | return 0; | ||
| 258 | case 7: | ||
| 259 | wss_config[n] |= WSS_CONFIG_IRQ_7; | ||
| 260 | break; | ||
| 261 | case 2: | ||
| 262 | irq[n] = 9; | ||
| 263 | case 9: | ||
| 264 | wss_config[n] |= WSS_CONFIG_IRQ_9; | ||
| 265 | break; | ||
| 266 | case 10: | ||
| 267 | wss_config[n] |= WSS_CONFIG_IRQ_10; | ||
| 268 | break; | ||
| 269 | case 11: | ||
| 270 | wss_config[n] |= WSS_CONFIG_IRQ_11; | ||
| 271 | break; | ||
| 272 | default: | ||
| 273 | dev_err(dev, "invalid IRQ %d\n", irq[n]); | ||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | switch (dma1[n]) { | ||
| 278 | case SNDRV_AUTO_DMA: | ||
| 279 | dev_err(dev, "please specify dma1\n"); | ||
| 280 | return 0; | ||
| 281 | case 0: | ||
| 282 | wss_config[n] |= WSS_CONFIG_DMA_0; | ||
| 283 | break; | ||
| 284 | case 1: | ||
| 285 | wss_config[n] |= WSS_CONFIG_DMA_1; | ||
| 286 | break; | ||
| 287 | case 3: | ||
| 288 | wss_config[n] |= WSS_CONFIG_DMA_3; | ||
| 289 | break; | ||
| 290 | default: | ||
| 291 | dev_err(dev, "invalid playback DMA %d\n", dma1[n]); | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) { | ||
| 296 | dma2[n] = -1; | ||
| 297 | goto mpu; | ||
| 298 | } | ||
| 299 | |||
| 300 | wss_config[n] |= WSS_CONFIG_DUPLEX; | ||
| 301 | switch (dma2[n]) { | ||
| 302 | case 0: | ||
| 303 | break; | ||
| 304 | case 1: | ||
| 305 | if (dma1[n] == 0) | ||
| 306 | break; | ||
| 307 | default: | ||
| 308 | dev_err(dev, "invalid capture DMA %d\n", dma2[n]); | ||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | mpu: | ||
| 313 | switch (mpu_port[n]) { | ||
| 314 | case SNDRV_AUTO_PORT: | ||
| 315 | dev_warn(dev, "mpu_port not specified; not using MPU-401\n"); | ||
| 316 | mpu_port[n] = -1; | ||
| 317 | goto fm; | ||
| 318 | case 0x300: | ||
| 319 | config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300; | ||
| 320 | break; | ||
| 321 | case 0x330: | ||
| 322 | config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330; | ||
| 323 | break; | ||
| 324 | default: | ||
| 325 | dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]); | ||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | switch (mpu_irq[n]) { | ||
| 330 | case SNDRV_AUTO_IRQ: | ||
| 331 | dev_warn(dev, "mpu_irq not specified: using polling mode\n"); | ||
| 332 | mpu_irq[n] = -1; | ||
| 333 | break; | ||
| 334 | case 2: | ||
| 335 | mpu_irq[n] = 9; | ||
| 336 | case 9: | ||
| 337 | config[n] |= GALAXY_CONFIG_MPUIRQ_2; | ||
| 338 | break; | ||
| 339 | #ifdef AZT1605 | ||
| 340 | case 3: | ||
| 341 | config[n] |= GALAXY_CONFIG_MPUIRQ_3; | ||
| 342 | break; | ||
| 343 | #endif | ||
| 344 | case 5: | ||
| 345 | config[n] |= GALAXY_CONFIG_MPUIRQ_5; | ||
| 346 | break; | ||
| 347 | case 7: | ||
| 348 | config[n] |= GALAXY_CONFIG_MPUIRQ_7; | ||
| 349 | break; | ||
| 350 | #ifdef AZT2316 | ||
| 351 | case 10: | ||
| 352 | config[n] |= GALAXY_CONFIG_MPUIRQ_10; | ||
| 353 | break; | ||
| 354 | #endif | ||
| 355 | default: | ||
| 356 | dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]); | ||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | if (mpu_irq[n] == irq[n]) { | ||
| 361 | dev_err(dev, "cannot share IRQ between WSS and MPU-401\n"); | ||
| 362 | return 0; | ||
| 363 | } | ||
| 364 | |||
| 365 | fm: | ||
| 366 | switch (fm_port[n]) { | ||
| 367 | case SNDRV_AUTO_PORT: | ||
| 368 | dev_warn(dev, "fm_port not specified: not using OPL3\n"); | ||
| 369 | fm_port[n] = -1; | ||
| 370 | break; | ||
| 371 | case 0x388: | ||
| 372 | break; | ||
| 373 | default: | ||
| 374 | dev_err(dev, "illegal FM port %#lx\n", fm_port[n]); | ||
| 375 | return 0; | ||
| 376 | } | ||
| 377 | |||
| 378 | config[n] |= GALAXY_CONFIG_GAME_ENABLE; | ||
| 379 | return 1; | ||
| 380 | } | ||
| 381 | |||
| 382 | static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type) | ||
| 383 | { | ||
| 384 | u8 major; | ||
| 385 | u8 minor; | ||
| 386 | int err; | ||
| 387 | |||
| 388 | err = dsp_reset(galaxy->port); | ||
| 389 | if (err < 0) | ||
| 390 | return err; | ||
| 391 | |||
| 392 | err = dsp_get_version(galaxy->port, &major, &minor); | ||
| 393 | if (err < 0) | ||
| 394 | return err; | ||
| 395 | |||
| 396 | if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR) | ||
| 397 | return -ENODEV; | ||
| 398 | |||
| 399 | err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8); | ||
| 400 | if (err < 0) | ||
| 401 | return err; | ||
| 402 | |||
| 403 | err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE); | ||
| 404 | if (err < 0) | ||
| 405 | return err; | ||
| 406 | |||
| 407 | err = dsp_get_byte(galaxy->port, type); | ||
| 408 | if (err < 0) | ||
| 409 | return err; | ||
| 410 | |||
| 411 | return 0; | ||
| 412 | } | ||
| 413 | |||
| 414 | static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode) | ||
| 415 | { | ||
| 416 | int err; | ||
| 417 | |||
| 418 | err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9); | ||
| 419 | if (err < 0) | ||
| 420 | return err; | ||
| 421 | |||
| 422 | err = dsp_command(galaxy->port, mode); | ||
| 423 | if (err < 0) | ||
| 424 | return err; | ||
| 425 | |||
| 426 | #ifdef AZT1605 | ||
| 427 | /* | ||
| 428 | * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again | ||
| 429 | */ | ||
| 430 | err = dsp_reset(galaxy->port); | ||
| 431 | if (err < 0) | ||
| 432 | return err; | ||
| 433 | #endif | ||
| 434 | |||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config) | ||
| 439 | { | ||
| 440 | u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET); | ||
| 441 | int i; | ||
| 442 | |||
| 443 | iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET); | ||
| 444 | for (i = 0; i < GALAXY_CONFIG_SIZE; i++) { | ||
| 445 | iowrite8(config, galaxy->config_port + i); | ||
| 446 | config >>= 8; | ||
| 447 | } | ||
| 448 | iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET); | ||
| 449 | msleep(10); | ||
| 450 | } | ||
| 451 | |||
| 452 | static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config) | ||
| 453 | { | ||
| 454 | int i; | ||
| 455 | |||
| 456 | for (i = GALAXY_CONFIG_SIZE; i; i--) { | ||
| 457 | u8 tmp = ioread8(galaxy->config_port + i - 1); | ||
| 458 | galaxy->config = (galaxy->config << 8) | tmp; | ||
| 459 | } | ||
| 460 | config |= galaxy->config & GALAXY_CONFIG_MASK; | ||
| 461 | galaxy_set_config(galaxy, config); | ||
| 462 | } | ||
| 463 | |||
| 464 | static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config) | ||
| 465 | { | ||
| 466 | int err; | ||
| 467 | |||
| 468 | err = wss_detect(galaxy->wss_port); | ||
| 469 | if (err < 0) | ||
| 470 | return err; | ||
| 471 | |||
| 472 | wss_set_config(galaxy->wss_port, wss_config); | ||
| 473 | |||
| 474 | err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS); | ||
| 475 | if (err < 0) | ||
| 476 | return err; | ||
| 477 | |||
| 478 | return 0; | ||
| 479 | } | ||
| 480 | |||
| 481 | static void snd_galaxy_free(struct snd_card *card) | ||
| 482 | { | ||
| 483 | struct snd_galaxy *galaxy = card->private_data; | ||
| 484 | |||
| 485 | if (galaxy->wss_port) { | ||
| 486 | wss_set_config(galaxy->wss_port, 0); | ||
| 487 | ioport_unmap(galaxy->wss_port); | ||
| 488 | release_and_free_resource(galaxy->res_wss_port); | ||
| 489 | } | ||
| 490 | if (galaxy->config_port) { | ||
| 491 | galaxy_set_config(galaxy, galaxy->config); | ||
| 492 | ioport_unmap(galaxy->config_port); | ||
| 493 | release_and_free_resource(galaxy->res_config_port); | ||
| 494 | } | ||
| 495 | if (galaxy->port) { | ||
| 496 | ioport_unmap(galaxy->port); | ||
| 497 | release_and_free_resource(galaxy->res_port); | ||
| 498 | } | ||
| 499 | } | ||
| 500 | |||
| 501 | static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n) | ||
| 502 | { | ||
| 503 | struct snd_galaxy *galaxy; | ||
| 504 | struct snd_wss *chip; | ||
| 505 | struct snd_card *card; | ||
| 506 | u8 type; | ||
| 507 | int err; | ||
| 508 | |||
| 509 | err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy, | ||
| 510 | &card); | ||
| 511 | if (err < 0) | ||
| 512 | return err; | ||
| 513 | |||
| 514 | snd_card_set_dev(card, dev); | ||
| 515 | |||
| 516 | card->private_free = snd_galaxy_free; | ||
| 517 | galaxy = card->private_data; | ||
| 518 | |||
| 519 | galaxy->res_port = request_region(port[n], 16, DRV_NAME); | ||
| 520 | if (!galaxy->res_port) { | ||
| 521 | dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n], | ||
| 522 | port[n] + 15); | ||
| 523 | err = -EBUSY; | ||
| 524 | goto error; | ||
| 525 | } | ||
| 526 | galaxy->port = ioport_map(port[n], 16); | ||
| 527 | |||
| 528 | err = galaxy_init(galaxy, &type); | ||
| 529 | if (err < 0) { | ||
| 530 | dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]); | ||
| 531 | goto error; | ||
| 532 | } | ||
| 533 | dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]); | ||
| 534 | |||
| 535 | galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG, | ||
| 536 | 16, DRV_NAME); | ||
| 537 | if (!galaxy->res_config_port) { | ||
| 538 | dev_err(dev, "could not grab ports %#lx-%#lx\n", | ||
| 539 | port[n] + GALAXY_PORT_CONFIG, | ||
| 540 | port[n] + GALAXY_PORT_CONFIG + 15); | ||
| 541 | err = -EBUSY; | ||
| 542 | goto error; | ||
| 543 | } | ||
| 544 | galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16); | ||
| 545 | |||
| 546 | galaxy_config(galaxy, config[n]); | ||
| 547 | |||
| 548 | galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME); | ||
| 549 | if (!galaxy->res_wss_port) { | ||
| 550 | dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n], | ||
| 551 | wss_port[n] + 3); | ||
| 552 | err = -EBUSY; | ||
| 553 | goto error; | ||
| 554 | } | ||
| 555 | galaxy->wss_port = ioport_map(wss_port[n], 4); | ||
| 556 | |||
| 557 | err = galaxy_wss_config(galaxy, wss_config[n]); | ||
| 558 | if (err < 0) { | ||
| 559 | dev_err(dev, "could not configure WSS\n"); | ||
| 560 | goto error; | ||
| 561 | } | ||
| 562 | |||
| 563 | strcpy(card->driver, DRV_NAME); | ||
| 564 | strcpy(card->shortname, DRV_NAME); | ||
| 565 | sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d", | ||
| 566 | card->shortname, port[n], wss_port[n], irq[n], dma1[n], | ||
| 567 | dma2[n]); | ||
| 568 | |||
| 569 | err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n], | ||
| 570 | dma2[n], WSS_HW_DETECT, 0, &chip); | ||
| 571 | if (err < 0) | ||
| 572 | goto error; | ||
| 573 | |||
| 574 | err = snd_wss_pcm(chip, 0, NULL); | ||
| 575 | if (err < 0) | ||
| 576 | goto error; | ||
| 577 | |||
| 578 | err = snd_wss_mixer(chip); | ||
| 579 | if (err < 0) | ||
| 580 | goto error; | ||
| 581 | |||
| 582 | err = snd_wss_timer(chip, 0, NULL); | ||
| 583 | if (err < 0) | ||
| 584 | goto error; | ||
| 585 | |||
| 586 | if (mpu_port[n] >= 0) { | ||
| 587 | err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, | ||
| 588 | mpu_port[n], 0, mpu_irq[n], | ||
| 589 | IRQF_DISABLED, NULL); | ||
| 590 | if (err < 0) | ||
| 591 | goto error; | ||
| 592 | } | ||
| 593 | |||
| 594 | if (fm_port[n] >= 0) { | ||
| 595 | struct snd_opl3 *opl3; | ||
| 596 | |||
| 597 | err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2, | ||
| 598 | OPL3_HW_AUTO, 0, &opl3); | ||
| 599 | if (err < 0) { | ||
| 600 | dev_err(dev, "no OPL device at %#lx\n", fm_port[n]); | ||
| 601 | goto error; | ||
| 602 | } | ||
| 603 | err = snd_opl3_timer_new(opl3, 1, 2); | ||
| 604 | if (err < 0) | ||
| 605 | goto error; | ||
| 606 | |||
| 607 | err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); | ||
| 608 | if (err < 0) | ||
| 609 | goto error; | ||
| 610 | } | ||
| 611 | |||
| 612 | err = snd_card_register(card); | ||
| 613 | if (err < 0) | ||
| 614 | goto error; | ||
| 615 | |||
| 616 | dev_set_drvdata(dev, card); | ||
| 617 | return 0; | ||
| 618 | |||
| 619 | error: | ||
| 620 | snd_card_free(card); | ||
| 621 | return err; | ||
| 622 | } | ||
| 623 | |||
| 624 | static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n) | ||
| 625 | { | ||
| 626 | snd_card_free(dev_get_drvdata(dev)); | ||
| 627 | dev_set_drvdata(dev, NULL); | ||
| 628 | return 0; | ||
| 629 | } | ||
| 630 | |||
| 631 | static struct isa_driver snd_galaxy_driver = { | ||
| 632 | .match = snd_galaxy_match, | ||
| 633 | .probe = snd_galaxy_probe, | ||
| 634 | .remove = __devexit_p(snd_galaxy_remove), | ||
| 635 | |||
| 636 | .driver = { | ||
| 637 | .name = DEV_NAME | ||
| 638 | } | ||
| 639 | }; | ||
| 640 | |||
| 641 | static int __init alsa_card_galaxy_init(void) | ||
| 642 | { | ||
| 643 | return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS); | ||
| 644 | } | ||
| 645 | |||
| 646 | static void __exit alsa_card_galaxy_exit(void) | ||
| 647 | { | ||
| 648 | isa_unregister_driver(&snd_galaxy_driver); | ||
| 649 | } | ||
| 650 | |||
| 651 | module_init(alsa_card_galaxy_init); | ||
| 652 | module_exit(alsa_card_galaxy_exit); | ||
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index f26eac8d8110..3e4a58b72913 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c | |||
| @@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip) | |||
| 191 | 191 | ||
| 192 | static void snd_gusmax_free(struct snd_card *card) | 192 | static void snd_gusmax_free(struct snd_card *card) |
| 193 | { | 193 | { |
| 194 | struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data; | 194 | struct snd_gusmax *maxcard = card->private_data; |
| 195 | 195 | ||
| 196 | if (maxcard == NULL) | 196 | if (maxcard == NULL) |
| 197 | return; | 197 | return; |
| @@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) | |||
| 219 | if (err < 0) | 219 | if (err < 0) |
| 220 | return err; | 220 | return err; |
| 221 | card->private_free = snd_gusmax_free; | 221 | card->private_free = snd_gusmax_free; |
| 222 | maxcard = (struct snd_gusmax *)card->private_data; | 222 | maxcard = card->private_data; |
| 223 | maxcard->card = card; | 223 | maxcard->card = card; |
| 224 | maxcard->irq = -1; | 224 | maxcard->irq = -1; |
| 225 | 225 | ||
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 81284a8fa0ce..2259e3f726a7 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c | |||
| @@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id) | |||
| 72 | 72 | ||
| 73 | static void snd_sb8_free(struct snd_card *card) | 73 | static void snd_sb8_free(struct snd_card *card) |
| 74 | { | 74 | { |
| 75 | struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data; | 75 | struct snd_sb8 *acard = card->private_data; |
| 76 | 76 | ||
| 77 | if (acard == NULL) | 77 | if (acard == NULL) |
| 78 | return; | 78 | return; |
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c deleted file mode 100644 index 6fe27b9d9440..000000000000 --- a/sound/isa/sgalaxy.c +++ /dev/null | |||
| @@ -1,369 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Aztech Sound Galaxy cards | ||
| 3 | * Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk. | ||
| 4 | * | ||
| 5 | * I don't have documentation for this card, I based this driver on the | ||
| 6 | * driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/err.h> | ||
| 26 | #include <linux/isa.h> | ||
| 27 | #include <linux/delay.h> | ||
| 28 | #include <linux/time.h> | ||
| 29 | #include <linux/interrupt.h> | ||
| 30 | #include <linux/moduleparam.h> | ||
| 31 | #include <asm/dma.h> | ||
| 32 | #include <sound/core.h> | ||
| 33 | #include <sound/sb.h> | ||
| 34 | #include <sound/wss.h> | ||
| 35 | #include <sound/control.h> | ||
| 36 | #define SNDRV_LEGACY_FIND_FREE_IRQ | ||
| 37 | #define SNDRV_LEGACY_FIND_FREE_DMA | ||
| 38 | #include <sound/initval.h> | ||
| 39 | |||
| 40 | MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>"); | ||
| 41 | MODULE_DESCRIPTION("Aztech Sound Galaxy"); | ||
| 42 | MODULE_LICENSE("GPL"); | ||
| 43 | MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}"); | ||
| 44 | |||
| 45 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
| 46 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
| 47 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
| 48 | static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */ | ||
| 49 | static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */ | ||
| 50 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */ | ||
| 51 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */ | ||
| 52 | |||
| 53 | module_param_array(index, int, NULL, 0444); | ||
| 54 | MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard."); | ||
| 55 | module_param_array(id, charp, NULL, 0444); | ||
| 56 | MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard."); | ||
| 57 | module_param_array(sbport, long, NULL, 0444); | ||
| 58 | MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver."); | ||
| 59 | module_param_array(wssport, long, NULL, 0444); | ||
| 60 | MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver."); | ||
| 61 | module_param_array(irq, int, NULL, 0444); | ||
| 62 | MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver."); | ||
| 63 | module_param_array(dma1, int, NULL, 0444); | ||
| 64 | MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver."); | ||
| 65 | |||
| 66 | #define SGALAXY_AUXC_LEFT 18 | ||
| 67 | #define SGALAXY_AUXC_RIGHT 19 | ||
| 68 | |||
| 69 | #define PFX "sgalaxy: " | ||
| 70 | |||
| 71 | /* | ||
| 72 | |||
| 73 | */ | ||
| 74 | |||
| 75 | #define AD1848P1( port, x ) ( port + c_d_c_AD1848##x ) | ||
| 76 | |||
| 77 | /* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */ | ||
| 78 | /* short time we actually need it.. */ | ||
| 79 | |||
| 80 | static int snd_sgalaxy_sbdsp_reset(unsigned long port) | ||
| 81 | { | ||
| 82 | int i; | ||
| 83 | |||
| 84 | outb(1, SBP1(port, RESET)); | ||
| 85 | udelay(10); | ||
| 86 | outb(0, SBP1(port, RESET)); | ||
| 87 | udelay(30); | ||
| 88 | for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++); | ||
| 89 | if (inb(SBP1(port, READ)) != 0xaa) { | ||
| 90 | snd_printd("sb_reset: failed at 0x%lx!!!\n", port); | ||
| 91 | return -ENODEV; | ||
| 92 | } | ||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port, | ||
| 97 | unsigned char val) | ||
| 98 | { | ||
| 99 | int i; | ||
| 100 | |||
| 101 | for (i = 10000; i; i--) | ||
| 102 | if ((inb(SBP1(port, STATUS)) & 0x80) == 0) { | ||
| 103 | outb(val, SBP1(port, COMMAND)); | ||
| 104 | return 1; | ||
| 105 | } | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id) | ||
| 111 | { | ||
| 112 | return IRQ_NONE; | ||
| 113 | } | ||
| 114 | |||
| 115 | static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma) | ||
| 116 | { | ||
| 117 | static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, | ||
| 118 | 0x10, 0x18, 0x20, -1, -1, -1, -1}; | ||
| 119 | static int dma_bits[] = {1, 2, 0, 3}; | ||
| 120 | int tmp, tmp1; | ||
| 121 | |||
| 122 | if ((tmp = inb(port + 3)) == 0xff) | ||
| 123 | { | ||
| 124 | snd_printdd("I/O address dead (0x%lx)\n", port); | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | #if 0 | ||
| 128 | snd_printdd("WSS signature = 0x%x\n", tmp); | ||
| 129 | #endif | ||
| 130 | |||
| 131 | if ((tmp & 0x3f) != 0x04 && | ||
| 132 | (tmp & 0x3f) != 0x0f && | ||
| 133 | (tmp & 0x3f) != 0x00) { | ||
| 134 | snd_printdd("No WSS signature detected on port 0x%lx\n", | ||
| 135 | port + 3); | ||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | #if 0 | ||
| 140 | snd_printdd(PFX "setting up IRQ/DMA for WSS\n"); | ||
| 141 | #endif | ||
| 142 | |||
| 143 | /* initialize IRQ for WSS codec */ | ||
| 144 | tmp = interrupt_bits[irq % 16]; | ||
| 145 | if (tmp < 0) | ||
| 146 | return -EINVAL; | ||
| 147 | |||
| 148 | if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) { | ||
| 149 | snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq); | ||
| 150 | return -EIO; | ||
| 151 | } | ||
| 152 | |||
| 153 | outb(tmp | 0x40, port); | ||
| 154 | tmp1 = dma_bits[dma % 4]; | ||
| 155 | outb(tmp | tmp1, port); | ||
| 156 | |||
| 157 | free_irq(irq, NULL); | ||
| 158 | |||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma) | ||
| 163 | { | ||
| 164 | #if 0 | ||
| 165 | snd_printdd(PFX "switching to WSS mode\n"); | ||
| 166 | #endif | ||
| 167 | |||
| 168 | /* switch to WSS mode */ | ||
| 169 | snd_sgalaxy_sbdsp_reset(sbport[dev]); | ||
| 170 | |||
| 171 | snd_sgalaxy_sbdsp_command(sbport[dev], 9); | ||
| 172 | snd_sgalaxy_sbdsp_command(sbport[dev], 0); | ||
| 173 | |||
| 174 | udelay(400); | ||
| 175 | return snd_sgalaxy_setup_wss(wssport[dev], irq, dma); | ||
| 176 | } | ||
| 177 | |||
| 178 | static struct snd_kcontrol_new snd_sgalaxy_controls[] = { | ||
| 179 | WSS_DOUBLE("Aux Playback Switch", 0, | ||
| 180 | SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1), | ||
| 181 | WSS_DOUBLE("Aux Playback Volume", 0, | ||
| 182 | SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0) | ||
| 183 | }; | ||
| 184 | |||
| 185 | static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip) | ||
| 186 | { | ||
| 187 | struct snd_card *card = chip->card; | ||
| 188 | struct snd_ctl_elem_id id1, id2; | ||
| 189 | unsigned int idx; | ||
| 190 | int err; | ||
| 191 | |||
| 192 | memset(&id1, 0, sizeof(id1)); | ||
| 193 | memset(&id2, 0, sizeof(id2)); | ||
| 194 | id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
| 195 | /* reassign AUX0 to LINE */ | ||
| 196 | strcpy(id1.name, "Aux Playback Switch"); | ||
| 197 | strcpy(id2.name, "Line Playback Switch"); | ||
| 198 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
| 199 | return err; | ||
| 200 | strcpy(id1.name, "Aux Playback Volume"); | ||
| 201 | strcpy(id2.name, "Line Playback Volume"); | ||
| 202 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
| 203 | return err; | ||
| 204 | /* reassign AUX1 to FM */ | ||
| 205 | strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; | ||
| 206 | strcpy(id2.name, "FM Playback Switch"); | ||
| 207 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
| 208 | return err; | ||
| 209 | strcpy(id1.name, "Aux Playback Volume"); | ||
| 210 | strcpy(id2.name, "FM Playback Volume"); | ||
| 211 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
| 212 | return err; | ||
| 213 | /* build AUX2 input */ | ||
| 214 | for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) { | ||
| 215 | err = snd_ctl_add(card, | ||
| 216 | snd_ctl_new1(&snd_sgalaxy_controls[idx], chip)); | ||
| 217 | if (err < 0) | ||
| 218 | return err; | ||
| 219 | } | ||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev) | ||
| 224 | { | ||
| 225 | if (!enable[dev]) | ||
| 226 | return 0; | ||
| 227 | if (sbport[dev] == SNDRV_AUTO_PORT) { | ||
| 228 | snd_printk(KERN_ERR PFX "specify SB port\n"); | ||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | if (wssport[dev] == SNDRV_AUTO_PORT) { | ||
| 232 | snd_printk(KERN_ERR PFX "specify WSS port\n"); | ||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | return 1; | ||
| 236 | } | ||
| 237 | |||
| 238 | static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev) | ||
| 239 | { | ||
| 240 | static int possible_irqs[] = {7, 9, 10, 11, -1}; | ||
| 241 | static int possible_dmas[] = {1, 3, 0, -1}; | ||
| 242 | int err, xirq, xdma1; | ||
| 243 | struct snd_card *card; | ||
| 244 | struct snd_wss *chip; | ||
| 245 | |||
| 246 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | ||
| 247 | if (err < 0) | ||
| 248 | return err; | ||
| 249 | |||
| 250 | xirq = irq[dev]; | ||
| 251 | if (xirq == SNDRV_AUTO_IRQ) { | ||
| 252 | if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { | ||
| 253 | snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); | ||
| 254 | err = -EBUSY; | ||
| 255 | goto _err; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | xdma1 = dma1[dev]; | ||
| 259 | if (xdma1 == SNDRV_AUTO_DMA) { | ||
| 260 | if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { | ||
| 261 | snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); | ||
| 262 | err = -EBUSY; | ||
| 263 | goto _err; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0) | ||
| 268 | goto _err; | ||
| 269 | |||
| 270 | err = snd_wss_create(card, wssport[dev] + 4, -1, | ||
| 271 | xirq, xdma1, -1, | ||
| 272 | WSS_HW_DETECT, 0, &chip); | ||
| 273 | if (err < 0) | ||
| 274 | goto _err; | ||
| 275 | card->private_data = chip; | ||
| 276 | |||
| 277 | err = snd_wss_pcm(chip, 0, NULL); | ||
| 278 | if (err < 0) { | ||
| 279 | snd_printdd(PFX "error creating new WSS PCM device\n"); | ||
| 280 | goto _err; | ||
| 281 | } | ||
| 282 | err = snd_wss_mixer(chip); | ||
| 283 | if (err < 0) { | ||
| 284 | snd_printdd(PFX "error creating new WSS mixer\n"); | ||
| 285 | goto _err; | ||
| 286 | } | ||
| 287 | if ((err = snd_sgalaxy_mixer(chip)) < 0) { | ||
| 288 | snd_printdd(PFX "the mixer rewrite failed\n"); | ||
| 289 | goto _err; | ||
| 290 | } | ||
| 291 | |||
| 292 | strcpy(card->driver, "Sound Galaxy"); | ||
| 293 | strcpy(card->shortname, "Sound Galaxy"); | ||
| 294 | sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d", | ||
| 295 | wssport[dev], xirq, xdma1); | ||
| 296 | |||
| 297 | snd_card_set_dev(card, devptr); | ||
| 298 | |||
| 299 | if ((err = snd_card_register(card)) < 0) | ||
| 300 | goto _err; | ||
| 301 | |||
| 302 | dev_set_drvdata(devptr, card); | ||
| 303 | return 0; | ||
| 304 | |||
| 305 | _err: | ||
| 306 | snd_card_free(card); | ||
| 307 | return err; | ||
| 308 | } | ||
| 309 | |||
| 310 | static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev) | ||
| 311 | { | ||
| 312 | snd_card_free(dev_get_drvdata(devptr)); | ||
| 313 | dev_set_drvdata(devptr, NULL); | ||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | |||
| 317 | #ifdef CONFIG_PM | ||
| 318 | static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n, | ||
| 319 | pm_message_t state) | ||
| 320 | { | ||
| 321 | struct snd_card *card = dev_get_drvdata(pdev); | ||
| 322 | struct snd_wss *chip = card->private_data; | ||
| 323 | |||
| 324 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
| 325 | chip->suspend(chip); | ||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | static int snd_sgalaxy_resume(struct device *pdev, unsigned int n) | ||
| 330 | { | ||
| 331 | struct snd_card *card = dev_get_drvdata(pdev); | ||
| 332 | struct snd_wss *chip = card->private_data; | ||
| 333 | |||
| 334 | chip->resume(chip); | ||
| 335 | snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]); | ||
| 336 | snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]); | ||
| 337 | |||
| 338 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | #endif | ||
| 342 | |||
| 343 | #define DEV_NAME "sgalaxy" | ||
| 344 | |||
| 345 | static struct isa_driver snd_sgalaxy_driver = { | ||
| 346 | .match = snd_sgalaxy_match, | ||
| 347 | .probe = snd_sgalaxy_probe, | ||
| 348 | .remove = __devexit_p(snd_sgalaxy_remove), | ||
| 349 | #ifdef CONFIG_PM | ||
| 350 | .suspend = snd_sgalaxy_suspend, | ||
| 351 | .resume = snd_sgalaxy_resume, | ||
| 352 | #endif | ||
| 353 | .driver = { | ||
| 354 | .name = DEV_NAME | ||
| 355 | }, | ||
| 356 | }; | ||
| 357 | |||
| 358 | static int __init alsa_card_sgalaxy_init(void) | ||
| 359 | { | ||
| 360 | return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS); | ||
| 361 | } | ||
| 362 | |||
| 363 | static void __exit alsa_card_sgalaxy_exit(void) | ||
| 364 | { | ||
| 365 | isa_unregister_driver(&snd_sgalaxy_driver); | ||
| 366 | } | ||
| 367 | |||
| 368 | module_init(alsa_card_sgalaxy_init) | ||
| 369 | module_exit(alsa_card_sgalaxy_exit) | ||
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index a513651fa149..76c090218073 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig | |||
| @@ -545,11 +545,3 @@ config SOUND_KAHLUA | |||
| 545 | 545 | ||
| 546 | endif # SOUND_OSS | 546 | endif # SOUND_OSS |
| 547 | 547 | ||
| 548 | config SOUND_SH_DAC_AUDIO | ||
| 549 | tristate "SuperH DAC audio support" | ||
| 550 | depends on CPU_SH3 && HIGH_RES_TIMERS | ||
| 551 | |||
| 552 | config SOUND_SH_DAC_AUDIO_CHANNEL | ||
| 553 | int "DAC channel" | ||
| 554 | default "1" | ||
| 555 | depends on SOUND_SH_DAC_AUDIO | ||
diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 567b8a74178a..96f14dcd0cd1 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile | |||
| @@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS) += sound.o | |||
| 9 | 9 | ||
| 10 | # Please leave it as is, cause the link order is significant ! | 10 | # Please leave it as is, cause the link order is significant ! |
| 11 | 11 | ||
| 12 | obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o | ||
| 13 | obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o | 12 | obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o |
| 14 | obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o | 13 | obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o |
| 15 | obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o | 14 | obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o |
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index c6f2621221ba..a8f626d99c5b 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c | |||
| @@ -43,7 +43,6 @@ | |||
| 43 | #include <linux/sound.h> | 43 | #include <linux/sound.h> |
| 44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
| 45 | #include <linux/soundcard.h> | 45 | #include <linux/soundcard.h> |
| 46 | #include <linux/smp_lock.h> | ||
| 47 | #include <linux/init.h> | 46 | #include <linux/init.h> |
| 48 | #include <linux/interrupt.h> | 47 | #include <linux/interrupt.h> |
| 49 | #include <linux/kernel.h> | 48 | #include <linux/kernel.h> |
| @@ -77,6 +76,7 @@ | |||
| 77 | /* Boot options | 76 | /* Boot options |
| 78 | * 0 = no VRA, 1 = use VRA if codec supports it | 77 | * 0 = no VRA, 1 = use VRA if codec supports it |
| 79 | */ | 78 | */ |
| 79 | static DEFINE_MUTEX(au1550_ac97_mutex); | ||
| 80 | static int vra = 1; | 80 | static int vra = 1; |
| 81 | module_param(vra, bool, 0); | 81 | module_param(vra, bool, 0); |
| 82 | MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); | 82 | MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); |
| @@ -171,7 +171,7 @@ au1550_delay(int msec) | |||
| 171 | static u16 | 171 | static u16 |
| 172 | rdcodec(struct ac97_codec *codec, u8 addr) | 172 | rdcodec(struct ac97_codec *codec, u8 addr) |
| 173 | { | 173 | { |
| 174 | struct au1550_state *s = (struct au1550_state *)codec->private_data; | 174 | struct au1550_state *s = codec->private_data; |
| 175 | unsigned long flags; | 175 | unsigned long flags; |
| 176 | u32 cmd, val; | 176 | u32 cmd, val; |
| 177 | u16 data; | 177 | u16 data; |
| @@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr) | |||
| 239 | static void | 239 | static void |
| 240 | wrcodec(struct ac97_codec *codec, u8 addr, u16 data) | 240 | wrcodec(struct ac97_codec *codec, u8 addr, u16 data) |
| 241 | { | 241 | { |
| 242 | struct au1550_state *s = (struct au1550_state *)codec->private_data; | 242 | struct au1550_state *s = codec->private_data; |
| 243 | unsigned long flags; | 243 | unsigned long flags; |
| 244 | u32 cmd, val; | 244 | u32 cmd, val; |
| 245 | int i; | 245 | int i; |
| @@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin) | |||
| 798 | static int | 798 | static int |
| 799 | au1550_open_mixdev(struct inode *inode, struct file *file) | 799 | au1550_open_mixdev(struct inode *inode, struct file *file) |
| 800 | { | 800 | { |
| 801 | lock_kernel(); | 801 | mutex_lock(&au1550_ac97_mutex); |
| 802 | file->private_data = &au1550_state; | 802 | file->private_data = &au1550_state; |
| 803 | unlock_kernel(); | 803 | mutex_unlock(&au1550_ac97_mutex); |
| 804 | return 0; | 804 | return 0; |
| 805 | } | 805 | } |
| 806 | 806 | ||
| @@ -820,13 +820,13 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, | |||
| 820 | static long | 820 | static long |
| 821 | au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) | 821 | au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) |
| 822 | { | 822 | { |
| 823 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 823 | struct au1550_state *s = file->private_data; |
| 824 | struct ac97_codec *codec = s->codec; | 824 | struct ac97_codec *codec = s->codec; |
| 825 | int ret; | 825 | int ret; |
| 826 | 826 | ||
| 827 | lock_kernel(); | 827 | mutex_lock(&au1550_ac97_mutex); |
| 828 | ret = mixdev_ioctl(codec, cmd, arg); | 828 | ret = mixdev_ioctl(codec, cmd, arg); |
| 829 | unlock_kernel(); | 829 | mutex_unlock(&au1550_ac97_mutex); |
| 830 | 830 | ||
| 831 | return ret; | 831 | return ret; |
| 832 | } | 832 | } |
| @@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user) | |||
| 1031 | static ssize_t | 1031 | static ssize_t |
| 1032 | au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) | 1032 | au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) |
| 1033 | { | 1033 | { |
| 1034 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1034 | struct au1550_state *s = file->private_data; |
| 1035 | struct dmabuf *db = &s->dma_adc; | 1035 | struct dmabuf *db = &s->dma_adc; |
| 1036 | DECLARE_WAITQUEUE(wait, current); | 1036 | DECLARE_WAITQUEUE(wait, current); |
| 1037 | ssize_t ret; | 1037 | ssize_t ret; |
| @@ -1111,7 +1111,7 @@ out2: | |||
| 1111 | static ssize_t | 1111 | static ssize_t |
| 1112 | au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) | 1112 | au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) |
| 1113 | { | 1113 | { |
| 1114 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1114 | struct au1550_state *s = file->private_data; |
| 1115 | struct dmabuf *db = &s->dma_dac; | 1115 | struct dmabuf *db = &s->dma_dac; |
| 1116 | DECLARE_WAITQUEUE(wait, current); | 1116 | DECLARE_WAITQUEUE(wait, current); |
| 1117 | ssize_t ret = 0; | 1117 | ssize_t ret = 0; |
| @@ -1211,7 +1211,7 @@ out2: | |||
| 1211 | static unsigned int | 1211 | static unsigned int |
| 1212 | au1550_poll(struct file *file, struct poll_table_struct *wait) | 1212 | au1550_poll(struct file *file, struct poll_table_struct *wait) |
| 1213 | { | 1213 | { |
| 1214 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1214 | struct au1550_state *s = file->private_data; |
| 1215 | unsigned long flags; | 1215 | unsigned long flags; |
| 1216 | unsigned int mask = 0; | 1216 | unsigned int mask = 0; |
| 1217 | 1217 | ||
| @@ -1250,12 +1250,12 @@ au1550_poll(struct file *file, struct poll_table_struct *wait) | |||
| 1250 | static int | 1250 | static int |
| 1251 | au1550_mmap(struct file *file, struct vm_area_struct *vma) | 1251 | au1550_mmap(struct file *file, struct vm_area_struct *vma) |
| 1252 | { | 1252 | { |
| 1253 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1253 | struct au1550_state *s = file->private_data; |
| 1254 | struct dmabuf *db; | 1254 | struct dmabuf *db; |
| 1255 | unsigned long size; | 1255 | unsigned long size; |
| 1256 | int ret = 0; | 1256 | int ret = 0; |
| 1257 | 1257 | ||
| 1258 | lock_kernel(); | 1258 | mutex_lock(&au1550_ac97_mutex); |
| 1259 | mutex_lock(&s->sem); | 1259 | mutex_lock(&s->sem); |
| 1260 | if (vma->vm_flags & VM_WRITE) | 1260 | if (vma->vm_flags & VM_WRITE) |
| 1261 | db = &s->dma_dac; | 1261 | db = &s->dma_dac; |
| @@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 1283 | db->mapped = 1; | 1283 | db->mapped = 1; |
| 1284 | out: | 1284 | out: |
| 1285 | mutex_unlock(&s->sem); | 1285 | mutex_unlock(&s->sem); |
| 1286 | unlock_kernel(); | 1286 | mutex_unlock(&au1550_ac97_mutex); |
| 1287 | return ret; | 1287 | return ret; |
| 1288 | } | 1288 | } |
| 1289 | 1289 | ||
| @@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db) | |||
| 1342 | static int | 1342 | static int |
| 1343 | au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1343 | au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 1344 | { | 1344 | { |
| 1345 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1345 | struct au1550_state *s = file->private_data; |
| 1346 | unsigned long flags; | 1346 | unsigned long flags; |
| 1347 | audio_buf_info abinfo; | 1347 | audio_buf_info abinfo; |
| 1348 | count_info cinfo; | 1348 | count_info cinfo; |
| @@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 1781 | { | 1781 | { |
| 1782 | int ret; | 1782 | int ret; |
| 1783 | 1783 | ||
| 1784 | lock_kernel(); | 1784 | mutex_lock(&au1550_ac97_mutex); |
| 1785 | ret = au1550_ioctl(file, cmd, arg); | 1785 | ret = au1550_ioctl(file, cmd, arg); |
| 1786 | unlock_kernel(); | 1786 | mutex_unlock(&au1550_ac97_mutex); |
| 1787 | 1787 | ||
| 1788 | return ret; | 1788 | return ret; |
| 1789 | } | 1789 | } |
| @@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file) | |||
| 1804 | #endif | 1804 | #endif |
| 1805 | 1805 | ||
| 1806 | file->private_data = s; | 1806 | file->private_data = s; |
| 1807 | lock_kernel(); | 1807 | mutex_lock(&au1550_ac97_mutex); |
| 1808 | /* wait for device to become free */ | 1808 | /* wait for device to become free */ |
| 1809 | mutex_lock(&s->open_mutex); | 1809 | mutex_lock(&s->open_mutex); |
| 1810 | while (s->open_mode & file->f_mode) { | 1810 | while (s->open_mode & file->f_mode) { |
| @@ -1861,21 +1861,21 @@ au1550_open(struct inode *inode, struct file *file) | |||
| 1861 | out: | 1861 | out: |
| 1862 | mutex_unlock(&s->open_mutex); | 1862 | mutex_unlock(&s->open_mutex); |
| 1863 | out2: | 1863 | out2: |
| 1864 | unlock_kernel(); | 1864 | mutex_unlock(&au1550_ac97_mutex); |
| 1865 | return ret; | 1865 | return ret; |
| 1866 | } | 1866 | } |
| 1867 | 1867 | ||
| 1868 | static int | 1868 | static int |
| 1869 | au1550_release(struct inode *inode, struct file *file) | 1869 | au1550_release(struct inode *inode, struct file *file) |
| 1870 | { | 1870 | { |
| 1871 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1871 | struct au1550_state *s = file->private_data; |
| 1872 | 1872 | ||
| 1873 | lock_kernel(); | 1873 | mutex_lock(&au1550_ac97_mutex); |
| 1874 | 1874 | ||
| 1875 | if (file->f_mode & FMODE_WRITE) { | 1875 | if (file->f_mode & FMODE_WRITE) { |
| 1876 | unlock_kernel(); | 1876 | mutex_unlock(&au1550_ac97_mutex); |
| 1877 | drain_dac(s, file->f_flags & O_NONBLOCK); | 1877 | drain_dac(s, file->f_flags & O_NONBLOCK); |
| 1878 | lock_kernel(); | 1878 | mutex_lock(&au1550_ac97_mutex); |
| 1879 | } | 1879 | } |
| 1880 | 1880 | ||
| 1881 | mutex_lock(&s->open_mutex); | 1881 | mutex_lock(&s->open_mutex); |
| @@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file) | |||
| 1892 | s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); | 1892 | s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); |
| 1893 | mutex_unlock(&s->open_mutex); | 1893 | mutex_unlock(&s->open_mutex); |
| 1894 | wake_up(&s->open_wait); | 1894 | wake_up(&s->open_wait); |
| 1895 | unlock_kernel(); | 1895 | mutex_unlock(&au1550_ac97_mutex); |
| 1896 | return 0; | 1896 | return 0; |
| 1897 | } | 1897 | } |
| 1898 | 1898 | ||
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 6ecd41abb066..87e2c72651f5 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c | |||
| @@ -181,7 +181,7 @@ | |||
| 181 | #include <linux/init.h> | 181 | #include <linux/init.h> |
| 182 | #include <linux/soundcard.h> | 182 | #include <linux/soundcard.h> |
| 183 | #include <linux/poll.h> | 183 | #include <linux/poll.h> |
| 184 | #include <linux/smp_lock.h> | 184 | #include <linux/mutex.h> |
| 185 | 185 | ||
| 186 | #include <asm/uaccess.h> | 186 | #include <asm/uaccess.h> |
| 187 | 187 | ||
| @@ -194,6 +194,7 @@ | |||
| 194 | * Declarations | 194 | * Declarations |
| 195 | */ | 195 | */ |
| 196 | 196 | ||
| 197 | static DEFINE_MUTEX(dmasound_core_mutex); | ||
| 197 | int dmasound_catchRadius = 0; | 198 | int dmasound_catchRadius = 0; |
| 198 | module_param(dmasound_catchRadius, int, 0); | 199 | module_param(dmasound_catchRadius, int, 0); |
| 199 | 200 | ||
| @@ -323,22 +324,22 @@ static struct { | |||
| 323 | 324 | ||
| 324 | static int mixer_open(struct inode *inode, struct file *file) | 325 | static int mixer_open(struct inode *inode, struct file *file) |
| 325 | { | 326 | { |
| 326 | lock_kernel(); | 327 | mutex_lock(&dmasound_core_mutex); |
| 327 | if (!try_module_get(dmasound.mach.owner)) { | 328 | if (!try_module_get(dmasound.mach.owner)) { |
| 328 | unlock_kernel(); | 329 | mutex_unlock(&dmasound_core_mutex); |
| 329 | return -ENODEV; | 330 | return -ENODEV; |
| 330 | } | 331 | } |
| 331 | mixer.busy = 1; | 332 | mixer.busy = 1; |
| 332 | unlock_kernel(); | 333 | mutex_unlock(&dmasound_core_mutex); |
| 333 | return 0; | 334 | return 0; |
| 334 | } | 335 | } |
| 335 | 336 | ||
| 336 | static int mixer_release(struct inode *inode, struct file *file) | 337 | static int mixer_release(struct inode *inode, struct file *file) |
| 337 | { | 338 | { |
| 338 | lock_kernel(); | 339 | mutex_lock(&dmasound_core_mutex); |
| 339 | mixer.busy = 0; | 340 | mixer.busy = 0; |
| 340 | module_put(dmasound.mach.owner); | 341 | module_put(dmasound.mach.owner); |
| 341 | unlock_kernel(); | 342 | mutex_unlock(&dmasound_core_mutex); |
| 342 | return 0; | 343 | return 0; |
| 343 | } | 344 | } |
| 344 | 345 | ||
| @@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | |||
| 370 | { | 371 | { |
| 371 | int ret; | 372 | int ret; |
| 372 | 373 | ||
| 373 | lock_kernel(); | 374 | mutex_lock(&dmasound_core_mutex); |
| 374 | ret = mixer_ioctl(file, cmd, arg); | 375 | ret = mixer_ioctl(file, cmd, arg); |
| 375 | unlock_kernel(); | 376 | mutex_unlock(&dmasound_core_mutex); |
| 376 | 377 | ||
| 377 | return ret; | 378 | return ret; |
| 378 | } | 379 | } |
| @@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file) | |||
| 752 | { | 753 | { |
| 753 | int rc; | 754 | int rc; |
| 754 | 755 | ||
| 755 | lock_kernel(); | 756 | mutex_lock(&dmasound_core_mutex); |
| 756 | if (!try_module_get(dmasound.mach.owner)) { | 757 | if (!try_module_get(dmasound.mach.owner)) { |
| 757 | unlock_kernel(); | 758 | mutex_unlock(&dmasound_core_mutex); |
| 758 | return -ENODEV; | 759 | return -ENODEV; |
| 759 | } | 760 | } |
| 760 | 761 | ||
| @@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file) | |||
| 799 | sound_set_format(AFMT_MU_LAW); | 800 | sound_set_format(AFMT_MU_LAW); |
| 800 | } | 801 | } |
| 801 | #endif | 802 | #endif |
| 802 | unlock_kernel(); | 803 | mutex_unlock(&dmasound_core_mutex); |
| 803 | return 0; | 804 | return 0; |
| 804 | out: | 805 | out: |
| 805 | module_put(dmasound.mach.owner); | 806 | module_put(dmasound.mach.owner); |
| 806 | unlock_kernel(); | 807 | mutex_unlock(&dmasound_core_mutex); |
| 807 | return rc; | 808 | return rc; |
| 808 | } | 809 | } |
| 809 | 810 | ||
| @@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file) | |||
| 869 | { | 870 | { |
| 870 | int rc = 0; | 871 | int rc = 0; |
| 871 | 872 | ||
| 872 | lock_kernel(); | 873 | mutex_lock(&dmasound_core_mutex); |
| 873 | 874 | ||
| 874 | if (file->f_mode & FMODE_WRITE) { | 875 | if (file->f_mode & FMODE_WRITE) { |
| 875 | if (write_sq.busy) | 876 | if (write_sq.busy) |
| @@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file) | |||
| 900 | write_sq_wake_up(file); /* checks f_mode */ | 901 | write_sq_wake_up(file); /* checks f_mode */ |
| 901 | #endif /* blocking open() */ | 902 | #endif /* blocking open() */ |
| 902 | 903 | ||
| 903 | unlock_kernel(); | 904 | mutex_unlock(&dmasound_core_mutex); |
| 904 | 905 | ||
| 905 | return rc; | 906 | return rc; |
| 906 | } | 907 | } |
| @@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | |||
| 1141 | { | 1142 | { |
| 1142 | int ret; | 1143 | int ret; |
| 1143 | 1144 | ||
| 1144 | lock_kernel(); | 1145 | mutex_lock(&dmasound_core_mutex); |
| 1145 | ret = sq_ioctl(file, cmd, arg); | 1146 | ret = sq_ioctl(file, cmd, arg); |
| 1146 | unlock_kernel(); | 1147 | mutex_unlock(&dmasound_core_mutex); |
| 1147 | 1148 | ||
| 1148 | return ret; | 1149 | return ret; |
| 1149 | } | 1150 | } |
| @@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file) | |||
| 1257 | int len = 0; | 1258 | int len = 0; |
| 1258 | int ret; | 1259 | int ret; |
| 1259 | 1260 | ||
| 1260 | lock_kernel(); | 1261 | mutex_lock(&dmasound_core_mutex); |
| 1261 | ret = -EBUSY; | 1262 | ret = -EBUSY; |
| 1262 | if (state.busy) | 1263 | if (state.busy) |
| 1263 | goto out; | 1264 | goto out; |
| @@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ; | |||
| 1329 | state.len = len; | 1330 | state.len = len; |
| 1330 | ret = 0; | 1331 | ret = 0; |
| 1331 | out: | 1332 | out: |
| 1332 | unlock_kernel(); | 1333 | mutex_unlock(&dmasound_core_mutex); |
| 1333 | return ret; | 1334 | return ret; |
| 1334 | } | 1335 | } |
| 1335 | 1336 | ||
| 1336 | static int state_release(struct inode *inode, struct file *file) | 1337 | static int state_release(struct inode *inode, struct file *file) |
| 1337 | { | 1338 | { |
| 1338 | lock_kernel(); | 1339 | mutex_lock(&dmasound_core_mutex); |
| 1339 | state.busy = 0; | 1340 | state.busy = 0; |
| 1340 | module_put(dmasound.mach.owner); | 1341 | module_put(dmasound.mach.owner); |
| 1341 | unlock_kernel(); | 1342 | mutex_unlock(&dmasound_core_mutex); |
| 1342 | return 0; | 1343 | return 0; |
| 1343 | } | 1344 | } |
| 1344 | 1345 | ||
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index 2e48b17667d0..b4c1eb504c22 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c | |||
| @@ -39,7 +39,7 @@ | |||
| 39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
| 40 | #include <linux/init.h> | 40 | #include <linux/init.h> |
| 41 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
| 42 | #include <linux/smp_lock.h> | 42 | #include <linux/mutex.h> |
| 43 | #include <linux/gfp.h> | 43 | #include <linux/gfp.h> |
| 44 | #include <asm/irq.h> | 44 | #include <asm/irq.h> |
| 45 | #include <asm/io.h> | 45 | #include <asm/io.h> |
| @@ -79,6 +79,7 @@ | |||
| 79 | dev.rec_sample_rate / \ | 79 | dev.rec_sample_rate / \ |
| 80 | dev.rec_channels) | 80 | dev.rec_channels) |
| 81 | 81 | ||
| 82 | static DEFINE_MUTEX(msnd_pinnacle_mutex); | ||
| 82 | static multisound_dev_t dev; | 83 | static multisound_dev_t dev; |
| 83 | 84 | ||
| 84 | #ifndef HAVE_DSPCODEH | 85 | #ifndef HAVE_DSPCODEH |
| @@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 651 | 652 | ||
| 652 | ret = -EINVAL; | 653 | ret = -EINVAL; |
| 653 | 654 | ||
| 654 | lock_kernel(); | 655 | mutex_lock(&msnd_pinnacle_mutex); |
| 655 | if (minor == dev.dsp_minor) | 656 | if (minor == dev.dsp_minor) |
| 656 | ret = dsp_ioctl(file, cmd, arg); | 657 | ret = dsp_ioctl(file, cmd, arg); |
| 657 | else if (minor == dev.mixer_minor) | 658 | else if (minor == dev.mixer_minor) |
| 658 | ret = mixer_ioctl(cmd, arg); | 659 | ret = mixer_ioctl(cmd, arg); |
| 659 | unlock_kernel(); | 660 | mutex_unlock(&msnd_pinnacle_mutex); |
| 660 | 661 | ||
| 661 | return ret; | 662 | return ret; |
| 662 | } | 663 | } |
| @@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file) | |||
| 761 | int minor = iminor(inode); | 762 | int minor = iminor(inode); |
| 762 | int err = 0; | 763 | int err = 0; |
| 763 | 764 | ||
| 764 | lock_kernel(); | 765 | mutex_lock(&msnd_pinnacle_mutex); |
| 765 | if (minor == dev.dsp_minor) { | 766 | if (minor == dev.dsp_minor) { |
| 766 | if ((file->f_mode & FMODE_WRITE && | 767 | if ((file->f_mode & FMODE_WRITE && |
| 767 | test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || | 768 | test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || |
| @@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file) | |||
| 791 | } else | 792 | } else |
| 792 | err = -EINVAL; | 793 | err = -EINVAL; |
| 793 | out: | 794 | out: |
| 794 | unlock_kernel(); | 795 | mutex_unlock(&msnd_pinnacle_mutex); |
| 795 | return err; | 796 | return err; |
| 796 | } | 797 | } |
| 797 | 798 | ||
| @@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file) | |||
| 800 | int minor = iminor(inode); | 801 | int minor = iminor(inode); |
| 801 | int err = 0; | 802 | int err = 0; |
| 802 | 803 | ||
| 803 | lock_kernel(); | 804 | mutex_lock(&msnd_pinnacle_mutex); |
| 804 | if (minor == dev.dsp_minor) | 805 | if (minor == dev.dsp_minor) |
| 805 | err = dsp_release(file); | 806 | err = dsp_release(file); |
| 806 | else if (minor == dev.mixer_minor) { | 807 | else if (minor == dev.mixer_minor) { |
| 807 | /* nothing */ | 808 | /* nothing */ |
| 808 | } else | 809 | } else |
| 809 | err = -EINVAL; | 810 | err = -EINVAL; |
| 810 | unlock_kernel(); | 811 | mutex_unlock(&msnd_pinnacle_mutex); |
| 811 | return err; | 812 | return err; |
| 812 | } | 813 | } |
| 813 | 814 | ||
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c deleted file mode 100644 index 479e3025a8a3..000000000000 --- a/sound/oss/sh_dac_audio.c +++ /dev/null | |||
| @@ -1,325 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * sound/oss/sh_dac_audio.c | ||
| 3 | * | ||
| 4 | * SH DAC based sound :( | ||
| 5 | * | ||
| 6 | * Copyright (C) 2004,2005 Andriy Skulysh | ||
| 7 | * | ||
| 8 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 9 | * License. See the file "COPYING" in the main directory of this archive | ||
| 10 | * for more details. | ||
| 11 | */ | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/sched.h> | ||
| 15 | #include <linux/linkage.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | #include <linux/fs.h> | ||
| 18 | #include <linux/sound.h> | ||
| 19 | #include <linux/smp_lock.h> | ||
| 20 | #include <linux/soundcard.h> | ||
| 21 | #include <linux/interrupt.h> | ||
| 22 | #include <linux/hrtimer.h> | ||
| 23 | #include <asm/io.h> | ||
| 24 | #include <asm/uaccess.h> | ||
| 25 | #include <asm/irq.h> | ||
| 26 | #include <asm/delay.h> | ||
| 27 | #include <asm/clock.h> | ||
| 28 | #include <cpu/dac.h> | ||
| 29 | #include <asm/machvec.h> | ||
| 30 | #include <mach/hp6xx.h> | ||
| 31 | #include <asm/hd64461.h> | ||
| 32 | |||
| 33 | #define MODNAME "sh_dac_audio" | ||
| 34 | |||
| 35 | #define BUFFER_SIZE 48000 | ||
| 36 | |||
| 37 | static int rate; | ||
| 38 | static int empty; | ||
| 39 | static char *data_buffer, *buffer_begin, *buffer_end; | ||
| 40 | static int in_use, device_major; | ||
| 41 | static struct hrtimer hrtimer; | ||
| 42 | static ktime_t wakeups_per_second; | ||
| 43 | |||
| 44 | static void dac_audio_start_timer(void) | ||
| 45 | { | ||
| 46 | hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void dac_audio_stop_timer(void) | ||
| 50 | { | ||
| 51 | hrtimer_cancel(&hrtimer); | ||
| 52 | } | ||
| 53 | |||
| 54 | static void dac_audio_reset(void) | ||
| 55 | { | ||
| 56 | dac_audio_stop_timer(); | ||
| 57 | buffer_begin = buffer_end = data_buffer; | ||
| 58 | empty = 1; | ||
| 59 | } | ||
| 60 | |||
| 61 | static void dac_audio_sync(void) | ||
| 62 | { | ||
| 63 | while (!empty) | ||
| 64 | schedule(); | ||
| 65 | } | ||
| 66 | |||
| 67 | static void dac_audio_start(void) | ||
| 68 | { | ||
| 69 | if (mach_is_hp6xx()) { | ||
| 70 | u16 v = __raw_readw(HD64461_GPADR); | ||
| 71 | v &= ~HD64461_GPADR_SPEAKER; | ||
| 72 | __raw_writew(v, HD64461_GPADR); | ||
| 73 | } | ||
| 74 | |||
| 75 | sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
| 76 | } | ||
| 77 | static void dac_audio_stop(void) | ||
| 78 | { | ||
| 79 | dac_audio_stop_timer(); | ||
| 80 | |||
| 81 | if (mach_is_hp6xx()) { | ||
| 82 | u16 v = __raw_readw(HD64461_GPADR); | ||
| 83 | v |= HD64461_GPADR_SPEAKER; | ||
| 84 | __raw_writew(v, HD64461_GPADR); | ||
| 85 | } | ||
| 86 | |||
| 87 | sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
| 88 | sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
| 89 | } | ||
| 90 | |||
| 91 | static void dac_audio_set_rate(void) | ||
| 92 | { | ||
| 93 | wakeups_per_second = ktime_set(0, 1000000000 / rate); | ||
| 94 | } | ||
| 95 | |||
| 96 | static int dac_audio_ioctl(struct file *file, | ||
| 97 | unsigned int cmd, unsigned long arg) | ||
| 98 | { | ||
| 99 | int val; | ||
| 100 | |||
| 101 | switch (cmd) { | ||
| 102 | case OSS_GETVERSION: | ||
| 103 | return put_user(SOUND_VERSION, (int *)arg); | ||
| 104 | |||
| 105 | case SNDCTL_DSP_SYNC: | ||
| 106 | dac_audio_sync(); | ||
| 107 | return 0; | ||
| 108 | |||
| 109 | case SNDCTL_DSP_RESET: | ||
| 110 | dac_audio_reset(); | ||
| 111 | return 0; | ||
| 112 | |||
| 113 | case SNDCTL_DSP_GETFMTS: | ||
| 114 | return put_user(AFMT_U8, (int *)arg); | ||
| 115 | |||
| 116 | case SNDCTL_DSP_SETFMT: | ||
| 117 | return put_user(AFMT_U8, (int *)arg); | ||
| 118 | |||
| 119 | case SNDCTL_DSP_NONBLOCK: | ||
| 120 | spin_lock(&file->f_lock); | ||
| 121 | file->f_flags |= O_NONBLOCK; | ||
| 122 | spin_unlock(&file->f_lock); | ||
| 123 | return 0; | ||
| 124 | |||
| 125 | case SNDCTL_DSP_GETCAPS: | ||
| 126 | return 0; | ||
| 127 | |||
| 128 | case SOUND_PCM_WRITE_RATE: | ||
| 129 | val = *(int *)arg; | ||
| 130 | if (val > 0) { | ||
| 131 | rate = val; | ||
| 132 | dac_audio_set_rate(); | ||
| 133 | } | ||
| 134 | return put_user(rate, (int *)arg); | ||
| 135 | |||
| 136 | case SNDCTL_DSP_STEREO: | ||
| 137 | return put_user(0, (int *)arg); | ||
| 138 | |||
| 139 | case SOUND_PCM_WRITE_CHANNELS: | ||
| 140 | return put_user(1, (int *)arg); | ||
| 141 | |||
| 142 | case SNDCTL_DSP_SETDUPLEX: | ||
| 143 | return -EINVAL; | ||
| 144 | |||
| 145 | case SNDCTL_DSP_PROFILE: | ||
| 146 | return -EINVAL; | ||
| 147 | |||
| 148 | case SNDCTL_DSP_GETBLKSIZE: | ||
| 149 | return put_user(BUFFER_SIZE, (int *)arg); | ||
| 150 | |||
| 151 | case SNDCTL_DSP_SETFRAGMENT: | ||
| 152 | return 0; | ||
| 153 | |||
| 154 | default: | ||
| 155 | printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n", | ||
| 156 | cmd); | ||
| 157 | return -EINVAL; | ||
| 158 | } | ||
| 159 | return -EINVAL; | ||
| 160 | } | ||
| 161 | |||
| 162 | static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | ||
| 163 | { | ||
| 164 | int ret; | ||
| 165 | |||
| 166 | lock_kernel(); | ||
| 167 | ret = dac_audio_ioctl(file, cmd, arg); | ||
| 168 | unlock_kernel(); | ||
| 169 | |||
| 170 | return ret; | ||
| 171 | } | ||
| 172 | |||
| 173 | static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count, | ||
| 174 | loff_t * ppos) | ||
| 175 | { | ||
| 176 | int free; | ||
| 177 | int nbytes; | ||
| 178 | |||
| 179 | if (!count) { | ||
| 180 | dac_audio_sync(); | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | free = buffer_begin - buffer_end; | ||
| 185 | |||
| 186 | if (free < 0) | ||
| 187 | free += BUFFER_SIZE; | ||
| 188 | if ((free == 0) && (empty)) | ||
| 189 | free = BUFFER_SIZE; | ||
| 190 | if (count > free) | ||
| 191 | count = free; | ||
| 192 | if (buffer_begin > buffer_end) { | ||
| 193 | if (copy_from_user((void *)buffer_end, buf, count)) | ||
| 194 | return -EFAULT; | ||
| 195 | |||
| 196 | buffer_end += count; | ||
| 197 | } else { | ||
| 198 | nbytes = data_buffer + BUFFER_SIZE - buffer_end; | ||
| 199 | if (nbytes > count) { | ||
| 200 | if (copy_from_user((void *)buffer_end, buf, count)) | ||
| 201 | return -EFAULT; | ||
| 202 | buffer_end += count; | ||
| 203 | } else { | ||
| 204 | if (copy_from_user((void *)buffer_end, buf, nbytes)) | ||
| 205 | return -EFAULT; | ||
| 206 | if (copy_from_user | ||
| 207 | ((void *)data_buffer, buf + nbytes, count - nbytes)) | ||
| 208 | return -EFAULT; | ||
| 209 | buffer_end = data_buffer + count - nbytes; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | if (empty) { | ||
| 214 | empty = 0; | ||
| 215 | dac_audio_start_timer(); | ||
| 216 | } | ||
| 217 | |||
| 218 | return count; | ||
| 219 | } | ||
| 220 | |||
| 221 | static ssize_t dac_audio_read(struct file *file, char *buf, size_t count, | ||
| 222 | loff_t * ppos) | ||
| 223 | { | ||
| 224 | return -EINVAL; | ||
| 225 | } | ||
| 226 | |||
| 227 | static int dac_audio_open(struct inode *inode, struct file *file) | ||
| 228 | { | ||
| 229 | if (file->f_mode & FMODE_READ) | ||
| 230 | return -ENODEV; | ||
| 231 | |||
| 232 | lock_kernel(); | ||
| 233 | if (in_use) { | ||
| 234 | unlock_kernel(); | ||
| 235 | return -EBUSY; | ||
| 236 | } | ||
| 237 | |||
| 238 | in_use = 1; | ||
| 239 | |||
| 240 | dac_audio_start(); | ||
| 241 | unlock_kernel(); | ||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | |||
| 245 | static int dac_audio_release(struct inode *inode, struct file *file) | ||
| 246 | { | ||
| 247 | dac_audio_sync(); | ||
| 248 | dac_audio_stop(); | ||
| 249 | in_use = 0; | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | const struct file_operations dac_audio_fops = { | ||
| 255 | .read = dac_audio_read, | ||
| 256 | .write = dac_audio_write, | ||
| 257 | .unlocked_ioctl = dac_audio_unlocked_ioctl, | ||
| 258 | .open = dac_audio_open, | ||
| 259 | .release = dac_audio_release, | ||
| 260 | }; | ||
| 261 | |||
| 262 | static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) | ||
| 263 | { | ||
| 264 | if (!empty) { | ||
| 265 | sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
| 266 | buffer_begin++; | ||
| 267 | |||
| 268 | if (buffer_begin == data_buffer + BUFFER_SIZE) | ||
| 269 | buffer_begin = data_buffer; | ||
| 270 | if (buffer_begin == buffer_end) | ||
| 271 | empty = 1; | ||
| 272 | } | ||
| 273 | |||
| 274 | if (!empty) | ||
| 275 | hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); | ||
| 276 | |||
| 277 | return HRTIMER_NORESTART; | ||
| 278 | } | ||
| 279 | |||
| 280 | static int __init dac_audio_init(void) | ||
| 281 | { | ||
| 282 | if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) { | ||
| 283 | printk(KERN_ERR "Cannot register dsp device"); | ||
| 284 | return device_major; | ||
| 285 | } | ||
| 286 | |||
| 287 | in_use = 0; | ||
| 288 | |||
| 289 | data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); | ||
| 290 | if (data_buffer == NULL) | ||
| 291 | return -ENOMEM; | ||
| 292 | |||
| 293 | dac_audio_reset(); | ||
| 294 | rate = 8000; | ||
| 295 | dac_audio_set_rate(); | ||
| 296 | |||
| 297 | /* Today: High Resolution Timer driven DAC playback. | ||
| 298 | * The timer callback gets called once per sample. Ouch. | ||
| 299 | * | ||
| 300 | * Future: A much better approach would be to use the | ||
| 301 | * SH7720 CMT+DMAC+DAC hardware combination like this: | ||
| 302 | * - Program sample rate using CMT0 or CMT1 | ||
| 303 | * - Program DMAC to use CMT for timing and output to DAC | ||
| 304 | * - Play sound using DMAC, let CPU sleep. | ||
| 305 | * - While at it, rewrite this driver to use ALSA. | ||
| 306 | */ | ||
| 307 | |||
| 308 | hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
| 309 | hrtimer.function = sh_dac_audio_timer; | ||
| 310 | |||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | static void __exit dac_audio_exit(void) | ||
| 315 | { | ||
| 316 | unregister_sound_dsp(device_major); | ||
| 317 | kfree((void *)data_buffer); | ||
| 318 | } | ||
| 319 | |||
| 320 | module_init(dac_audio_init); | ||
| 321 | module_exit(dac_audio_exit); | ||
| 322 | |||
| 323 | MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua"); | ||
| 324 | MODULE_DESCRIPTION("SH DAC sound driver"); | ||
| 325 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 07f803e6d203..46c0d03dbecc 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c | |||
| @@ -40,7 +40,7 @@ | |||
| 40 | #include <linux/major.h> | 40 | #include <linux/major.h> |
| 41 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
| 42 | #include <linux/proc_fs.h> | 42 | #include <linux/proc_fs.h> |
| 43 | #include <linux/smp_lock.h> | 43 | #include <linux/mutex.h> |
| 44 | #include <linux/module.h> | 44 | #include <linux/module.h> |
| 45 | #include <linux/mm.h> | 45 | #include <linux/mm.h> |
| 46 | #include <linux/device.h> | 46 | #include <linux/device.h> |
| @@ -56,6 +56,7 @@ | |||
| 56 | * Table for permanently allocated memory (used when unloading the module) | 56 | * Table for permanently allocated memory (used when unloading the module) |
| 57 | */ | 57 | */ |
| 58 | void * sound_mem_blocks[MAX_MEM_BLOCKS]; | 58 | void * sound_mem_blocks[MAX_MEM_BLOCKS]; |
| 59 | static DEFINE_MUTEX(soundcard_mutex); | ||
| 59 | int sound_nblocks = 0; | 60 | int sound_nblocks = 0; |
| 60 | 61 | ||
| 61 | /* Persistent DMA buffers */ | 62 | /* Persistent DMA buffers */ |
| @@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof | |||
| 151 | * big one anyway, we might as well bandage here.. | 152 | * big one anyway, we might as well bandage here.. |
| 152 | */ | 153 | */ |
| 153 | 154 | ||
| 154 | lock_kernel(); | 155 | mutex_lock(&soundcard_mutex); |
| 155 | 156 | ||
| 156 | DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); | 157 | DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); |
| 157 | switch (dev & 0x0f) { | 158 | switch (dev & 0x0f) { |
| @@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof | |||
| 169 | case SND_DEV_MIDIN: | 170 | case SND_DEV_MIDIN: |
| 170 | ret = MIDIbuf_read(dev, file, buf, count); | 171 | ret = MIDIbuf_read(dev, file, buf, count); |
| 171 | } | 172 | } |
| 172 | unlock_kernel(); | 173 | mutex_unlock(&soundcard_mutex); |
| 173 | return ret; | 174 | return ret; |
| 174 | } | 175 | } |
| 175 | 176 | ||
| @@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou | |||
| 178 | int dev = iminor(file->f_path.dentry->d_inode); | 179 | int dev = iminor(file->f_path.dentry->d_inode); |
| 179 | int ret = -EINVAL; | 180 | int ret = -EINVAL; |
| 180 | 181 | ||
| 181 | lock_kernel(); | 182 | mutex_lock(&soundcard_mutex); |
| 182 | DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); | 183 | DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); |
| 183 | switch (dev & 0x0f) { | 184 | switch (dev & 0x0f) { |
| 184 | case SND_DEV_SEQ: | 185 | case SND_DEV_SEQ: |
| @@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou | |||
| 196 | ret = MIDIbuf_write(dev, file, buf, count); | 197 | ret = MIDIbuf_write(dev, file, buf, count); |
| 197 | break; | 198 | break; |
| 198 | } | 199 | } |
| 199 | unlock_kernel(); | 200 | mutex_unlock(&soundcard_mutex); |
| 200 | return ret; | 201 | return ret; |
| 201 | } | 202 | } |
| 202 | 203 | ||
| @@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file) | |||
| 210 | printk(KERN_ERR "Invalid minor device %d\n", dev); | 211 | printk(KERN_ERR "Invalid minor device %d\n", dev); |
| 211 | return -ENXIO; | 212 | return -ENXIO; |
| 212 | } | 213 | } |
| 213 | lock_kernel(); | 214 | mutex_lock(&soundcard_mutex); |
| 214 | switch (dev & 0x0f) { | 215 | switch (dev & 0x0f) { |
| 215 | case SND_DEV_CTL: | 216 | case SND_DEV_CTL: |
| 216 | dev >>= 4; | 217 | dev >>= 4; |
| @@ -247,15 +248,15 @@ static int sound_open(struct inode *inode, struct file *file) | |||
| 247 | retval = -ENXIO; | 248 | retval = -ENXIO; |
| 248 | } | 249 | } |
| 249 | 250 | ||
| 250 | unlock_kernel(); | 251 | mutex_unlock(&soundcard_mutex); |
| 251 | return 0; | 252 | return retval; |
| 252 | } | 253 | } |
| 253 | 254 | ||
| 254 | static int sound_release(struct inode *inode, struct file *file) | 255 | static int sound_release(struct inode *inode, struct file *file) |
| 255 | { | 256 | { |
| 256 | int dev = iminor(inode); | 257 | int dev = iminor(inode); |
| 257 | 258 | ||
| 258 | lock_kernel(); | 259 | mutex_lock(&soundcard_mutex); |
| 259 | DEB(printk("sound_release(dev=%d)\n", dev)); | 260 | DEB(printk("sound_release(dev=%d)\n", dev)); |
| 260 | switch (dev & 0x0f) { | 261 | switch (dev & 0x0f) { |
| 261 | case SND_DEV_CTL: | 262 | case SND_DEV_CTL: |
| @@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file) | |||
| 280 | default: | 281 | default: |
| 281 | printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); | 282 | printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); |
| 282 | } | 283 | } |
| 283 | unlock_kernel(); | 284 | mutex_unlock(&soundcard_mutex); |
| 284 | 285 | ||
| 285 | return 0; | 286 | return 0; |
| 286 | } | 287 | } |
| @@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 354 | if (cmd == OSS_GETVERSION) | 355 | if (cmd == OSS_GETVERSION) |
| 355 | return __put_user(SOUND_VERSION, (int __user *)p); | 356 | return __put_user(SOUND_VERSION, (int __user *)p); |
| 356 | 357 | ||
| 357 | lock_kernel(); | 358 | mutex_lock(&soundcard_mutex); |
| 358 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ | 359 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ |
| 359 | (dev & 0x0f) != SND_DEV_CTL) { | 360 | (dev & 0x0f) != SND_DEV_CTL) { |
| 360 | dtype = dev & 0x0f; | 361 | dtype = dev & 0x0f; |
| @@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 369 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); | 370 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); |
| 370 | break; | 371 | break; |
| 371 | } | 372 | } |
| 372 | unlock_kernel(); | 373 | mutex_unlock(&soundcard_mutex); |
| 373 | return ret; | 374 | return ret; |
| 374 | } | 375 | } |
| 375 | 376 | ||
| @@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 399 | break; | 400 | break; |
| 400 | 401 | ||
| 401 | } | 402 | } |
| 402 | unlock_kernel(); | 403 | mutex_unlock(&soundcard_mutex); |
| 403 | return ret; | 404 | return ret; |
| 404 | } | 405 | } |
| 405 | 406 | ||
| @@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 439 | printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); | 440 | printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); |
| 440 | return -EINVAL; | 441 | return -EINVAL; |
| 441 | } | 442 | } |
| 442 | lock_kernel(); | 443 | mutex_lock(&soundcard_mutex); |
| 443 | if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ | 444 | if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ |
| 444 | dmap = audio_devs[dev]->dmap_out; | 445 | dmap = audio_devs[dev]->dmap_out; |
| 445 | else if (vma->vm_flags & VM_READ) | 446 | else if (vma->vm_flags & VM_READ) |
| 446 | dmap = audio_devs[dev]->dmap_in; | 447 | dmap = audio_devs[dev]->dmap_in; |
| 447 | else { | 448 | else { |
| 448 | printk(KERN_ERR "Sound: Undefined mmap() access\n"); | 449 | printk(KERN_ERR "Sound: Undefined mmap() access\n"); |
| 449 | unlock_kernel(); | 450 | mutex_unlock(&soundcard_mutex); |
| 450 | return -EINVAL; | 451 | return -EINVAL; |
| 451 | } | 452 | } |
| 452 | 453 | ||
| 453 | if (dmap == NULL) { | 454 | if (dmap == NULL) { |
| 454 | printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); | 455 | printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); |
| 455 | unlock_kernel(); | 456 | mutex_unlock(&soundcard_mutex); |
| 456 | return -EIO; | 457 | return -EIO; |
| 457 | } | 458 | } |
| 458 | if (dmap->raw_buf == NULL) { | 459 | if (dmap->raw_buf == NULL) { |
| 459 | printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); | 460 | printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); |
| 460 | unlock_kernel(); | 461 | mutex_unlock(&soundcard_mutex); |
| 461 | return -EIO; | 462 | return -EIO; |
| 462 | } | 463 | } |
| 463 | if (dmap->mapping_flags) { | 464 | if (dmap->mapping_flags) { |
| 464 | printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); | 465 | printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); |
| 465 | unlock_kernel(); | 466 | mutex_unlock(&soundcard_mutex); |
| 466 | return -EIO; | 467 | return -EIO; |
| 467 | } | 468 | } |
| 468 | if (vma->vm_pgoff != 0) { | 469 | if (vma->vm_pgoff != 0) { |
| 469 | printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); | 470 | printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); |
| 470 | unlock_kernel(); | 471 | mutex_unlock(&soundcard_mutex); |
| 471 | return -EINVAL; | 472 | return -EINVAL; |
| 472 | } | 473 | } |
| 473 | size = vma->vm_end - vma->vm_start; | 474 | size = vma->vm_end - vma->vm_start; |
| @@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 478 | if (remap_pfn_range(vma, vma->vm_start, | 479 | if (remap_pfn_range(vma, vma->vm_start, |
| 479 | virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, | 480 | virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, |
| 480 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) { | 481 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) { |
| 481 | unlock_kernel(); | 482 | mutex_unlock(&soundcard_mutex); |
| 482 | return -EAGAIN; | 483 | return -EAGAIN; |
| 483 | } | 484 | } |
| 484 | 485 | ||
| @@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 490 | memset(dmap->raw_buf, | 491 | memset(dmap->raw_buf, |
| 491 | dmap->neutral_byte, | 492 | dmap->neutral_byte, |
| 492 | dmap->bytes_in_use); | 493 | dmap->bytes_in_use); |
| 493 | unlock_kernel(); | 494 | mutex_unlock(&soundcard_mutex); |
| 494 | return 0; | 495 | return 0; |
| 495 | } | 496 | } |
| 496 | 497 | ||
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index b15840ad2527..44357d877a27 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c | |||
| @@ -68,7 +68,6 @@ | |||
| 68 | #include <linux/delay.h> | 68 | #include <linux/delay.h> |
| 69 | #include <linux/sound.h> | 69 | #include <linux/sound.h> |
| 70 | #include <linux/slab.h> | 70 | #include <linux/slab.h> |
| 71 | #include <linux/smp_lock.h> | ||
| 72 | #include <linux/soundcard.h> | 71 | #include <linux/soundcard.h> |
| 73 | #include <linux/ac97_codec.h> | 72 | #include <linux/ac97_codec.h> |
| 74 | #include <linux/pci.h> | 73 | #include <linux/pci.h> |
| @@ -94,6 +93,7 @@ | |||
| 94 | 93 | ||
| 95 | struct cs4297a_state; | 94 | struct cs4297a_state; |
| 96 | 95 | ||
| 96 | static DEFINE_MUTEX(swarm_cs4297a_mutex); | ||
| 97 | static void stop_dac(struct cs4297a_state *s); | 97 | static void stop_dac(struct cs4297a_state *s); |
| 98 | static void stop_adc(struct cs4297a_state *s); | 98 | static void stop_adc(struct cs4297a_state *s); |
| 99 | static void start_dac(struct cs4297a_state *s); | 99 | static void start_dac(struct cs4297a_state *s); |
| @@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) | |||
| 1535 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, | 1535 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, |
| 1536 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); | 1536 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); |
| 1537 | 1537 | ||
| 1538 | lock_kernel(); | 1538 | mutex_lock(&swarm_cs4297a_mutex); |
| 1539 | list_for_each(entry, &cs4297a_devs) | 1539 | list_for_each(entry, &cs4297a_devs) |
| 1540 | { | 1540 | { |
| 1541 | s = list_entry(entry, struct cs4297a_state, list); | 1541 | s = list_entry(entry, struct cs4297a_state, list); |
| @@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) | |||
| 1547 | CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, | 1547 | CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, |
| 1548 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); | 1548 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); |
| 1549 | 1549 | ||
| 1550 | unlock_kernel(); | 1550 | mutex_unlock(&swarm_cs4297a_mutex); |
| 1551 | return -ENODEV; | 1551 | return -ENODEV; |
| 1552 | } | 1552 | } |
| 1553 | VALIDATE_STATE(s); | 1553 | VALIDATE_STATE(s); |
| @@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) | |||
| 1555 | 1555 | ||
| 1556 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, | 1556 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, |
| 1557 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); | 1557 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); |
| 1558 | unlock_kernel(); | 1558 | mutex_unlock(&swarm_cs4297a_mutex); |
| 1559 | 1559 | ||
| 1560 | return nonseekable_open(inode, file); | 1560 | return nonseekable_open(inode, file); |
| 1561 | } | 1561 | } |
| @@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file, | |||
| 1575 | unsigned int cmd, unsigned long arg) | 1575 | unsigned int cmd, unsigned long arg) |
| 1576 | { | 1576 | { |
| 1577 | int ret; | 1577 | int ret; |
| 1578 | lock_kernel(); | 1578 | mutex_lock(&swarm_cs4297a_mutex); |
| 1579 | ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, | 1579 | ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, |
| 1580 | arg); | 1580 | arg); |
| 1581 | unlock_kernel(); | 1581 | mutex_unlock(&swarm_cs4297a_mutex); |
| 1582 | return ret; | 1582 | return ret; |
| 1583 | } | 1583 | } |
| 1584 | 1584 | ||
| @@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | |||
| 2350 | { | 2350 | { |
| 2351 | int ret; | 2351 | int ret; |
| 2352 | 2352 | ||
| 2353 | lock_kernel(); | 2353 | mutex_lock(&swarm_cs4297a_mutex); |
| 2354 | ret = cs4297a_ioctl(file, cmd, arg); | 2354 | ret = cs4297a_ioctl(file, cmd, arg); |
| 2355 | unlock_kernel(); | 2355 | mutex_unlock(&swarm_cs4297a_mutex); |
| 2356 | 2356 | ||
| 2357 | return ret; | 2357 | return ret; |
| 2358 | } | 2358 | } |
| @@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file) | |||
| 2509 | { | 2509 | { |
| 2510 | int ret; | 2510 | int ret; |
| 2511 | 2511 | ||
| 2512 | lock_kernel(); | 2512 | mutex_lock(&swarm_cs4297a_mutex); |
| 2513 | ret = cs4297a_open(inode, file); | 2513 | ret = cs4297a_open(inode, file); |
| 2514 | unlock_kernel(); | 2514 | mutex_unlock(&swarm_cs4297a_mutex); |
| 2515 | 2515 | ||
| 2516 | return ret; | 2516 | return ret; |
| 2517 | } | 2517 | } |
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 8cd73cdd88af..643f1113b1d8 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c | |||
| @@ -145,7 +145,6 @@ | |||
| 145 | #include <linux/init.h> | 145 | #include <linux/init.h> |
| 146 | 146 | ||
| 147 | #include <linux/spinlock.h> | 147 | #include <linux/spinlock.h> |
| 148 | #include <linux/smp_lock.h> | ||
| 149 | #include <linux/wait.h> | 148 | #include <linux/wait.h> |
| 150 | #include <linux/interrupt.h> | 149 | #include <linux/interrupt.h> |
| 151 | #include <linux/mutex.h> | 150 | #include <linux/mutex.h> |
| @@ -160,6 +159,7 @@ | |||
| 160 | 159 | ||
| 161 | #ifdef VWSND_DEBUG | 160 | #ifdef VWSND_DEBUG |
| 162 | 161 | ||
| 162 | static DEFINE_MUTEX(vwsnd_mutex); | ||
| 163 | static int shut_up = 1; | 163 | static int shut_up = 1; |
| 164 | 164 | ||
| 165 | /* | 165 | /* |
| @@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file, | |||
| 2891 | vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; | 2891 | vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; |
| 2892 | int ret; | 2892 | int ret; |
| 2893 | 2893 | ||
| 2894 | lock_kernel(); | 2894 | mutex_lock(&vwsnd_mutex); |
| 2895 | mutex_lock(&devc->io_mutex); | 2895 | mutex_lock(&devc->io_mutex); |
| 2896 | ret = vwsnd_audio_do_ioctl(file, cmd, arg); | 2896 | ret = vwsnd_audio_do_ioctl(file, cmd, arg); |
| 2897 | mutex_unlock(&devc->io_mutex); | 2897 | mutex_unlock(&devc->io_mutex); |
| 2898 | unlock_kernel(); | 2898 | mutex_unlock(&vwsnd_mutex); |
| 2899 | 2899 | ||
| 2900 | return ret; | 2900 | return ret; |
| 2901 | } | 2901 | } |
| @@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
| 2922 | 2922 | ||
| 2923 | DBGE("(inode=0x%p, file=0x%p)\n", inode, file); | 2923 | DBGE("(inode=0x%p, file=0x%p)\n", inode, file); |
| 2924 | 2924 | ||
| 2925 | lock_kernel(); | 2925 | mutex_lock(&vwsnd_mutex); |
| 2926 | INC_USE_COUNT; | 2926 | INC_USE_COUNT; |
| 2927 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) | 2927 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) |
| 2928 | if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) | 2928 | if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) |
| @@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
| 2930 | 2930 | ||
| 2931 | if (devc == NULL) { | 2931 | if (devc == NULL) { |
| 2932 | DEC_USE_COUNT; | 2932 | DEC_USE_COUNT; |
| 2933 | unlock_kernel(); | 2933 | mutex_unlock(&vwsnd_mutex); |
| 2934 | return -ENODEV; | 2934 | return -ENODEV; |
| 2935 | } | 2935 | } |
| 2936 | 2936 | ||
| @@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
| 2939 | mutex_unlock(&devc->open_mutex); | 2939 | mutex_unlock(&devc->open_mutex); |
| 2940 | if (file->f_flags & O_NONBLOCK) { | 2940 | if (file->f_flags & O_NONBLOCK) { |
| 2941 | DEC_USE_COUNT; | 2941 | DEC_USE_COUNT; |
| 2942 | unlock_kernel(); | 2942 | mutex_unlock(&vwsnd_mutex); |
| 2943 | return -EBUSY; | 2943 | return -EBUSY; |
| 2944 | } | 2944 | } |
| 2945 | interruptible_sleep_on(&devc->open_wait); | 2945 | interruptible_sleep_on(&devc->open_wait); |
| 2946 | if (signal_pending(current)) { | 2946 | if (signal_pending(current)) { |
| 2947 | DEC_USE_COUNT; | 2947 | DEC_USE_COUNT; |
| 2948 | unlock_kernel(); | 2948 | mutex_unlock(&vwsnd_mutex); |
| 2949 | return -ERESTARTSYS; | 2949 | return -ERESTARTSYS; |
| 2950 | } | 2950 | } |
| 2951 | mutex_lock(&devc->open_mutex); | 2951 | mutex_lock(&devc->open_mutex); |
| @@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
| 2998 | 2998 | ||
| 2999 | file->private_data = devc; | 2999 | file->private_data = devc; |
| 3000 | DBGRV(); | 3000 | DBGRV(); |
| 3001 | unlock_kernel(); | 3001 | mutex_unlock(&vwsnd_mutex); |
| 3002 | return 0; | 3002 | return 0; |
| 3003 | } | 3003 | } |
| 3004 | 3004 | ||
| @@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) | |||
| 3012 | vwsnd_port_t *wport = NULL, *rport = NULL; | 3012 | vwsnd_port_t *wport = NULL, *rport = NULL; |
| 3013 | int err = 0; | 3013 | int err = 0; |
| 3014 | 3014 | ||
| 3015 | lock_kernel(); | 3015 | mutex_lock(&vwsnd_mutex); |
| 3016 | mutex_lock(&devc->io_mutex); | 3016 | mutex_lock(&devc->io_mutex); |
| 3017 | { | 3017 | { |
| 3018 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); | 3018 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); |
| @@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) | |||
| 3040 | wake_up(&devc->open_wait); | 3040 | wake_up(&devc->open_wait); |
| 3041 | DEC_USE_COUNT; | 3041 | DEC_USE_COUNT; |
| 3042 | DBGR(); | 3042 | DBGR(); |
| 3043 | unlock_kernel(); | 3043 | mutex_unlock(&vwsnd_mutex); |
| 3044 | return err; | 3044 | return err; |
| 3045 | } | 3045 | } |
| 3046 | 3046 | ||
| @@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file) | |||
| 3068 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); | 3068 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); |
| 3069 | 3069 | ||
| 3070 | INC_USE_COUNT; | 3070 | INC_USE_COUNT; |
| 3071 | lock_kernel(); | 3071 | mutex_lock(&vwsnd_mutex); |
| 3072 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) | 3072 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) |
| 3073 | if (devc->mixer_minor == iminor(inode)) | 3073 | if (devc->mixer_minor == iminor(inode)) |
| 3074 | break; | 3074 | break; |
| 3075 | 3075 | ||
| 3076 | if (devc == NULL) { | 3076 | if (devc == NULL) { |
| 3077 | DEC_USE_COUNT; | 3077 | DEC_USE_COUNT; |
| 3078 | unlock_kernel(); | 3078 | mutex_unlock(&vwsnd_mutex); |
| 3079 | return -ENODEV; | 3079 | return -ENODEV; |
| 3080 | } | 3080 | } |
| 3081 | file->private_data = devc; | 3081 | file->private_data = devc; |
| 3082 | unlock_kernel(); | 3082 | mutex_unlock(&vwsnd_mutex); |
| 3083 | return 0; | 3083 | return 0; |
| 3084 | } | 3084 | } |
| 3085 | 3085 | ||
| @@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file, | |||
| 3223 | 3223 | ||
| 3224 | DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); | 3224 | DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); |
| 3225 | 3225 | ||
| 3226 | lock_kernel(); | 3226 | mutex_lock(&vwsnd_mutex); |
| 3227 | mutex_lock(&devc->mix_mutex); | 3227 | mutex_lock(&devc->mix_mutex); |
| 3228 | { | 3228 | { |
| 3229 | if ((cmd & ~nrmask) == MIXER_READ(0)) | 3229 | if ((cmd & ~nrmask) == MIXER_READ(0)) |
| @@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file, | |||
| 3234 | retval = -EINVAL; | 3234 | retval = -EINVAL; |
| 3235 | } | 3235 | } |
| 3236 | mutex_unlock(&devc->mix_mutex); | 3236 | mutex_unlock(&devc->mix_mutex); |
| 3237 | unlock_kernel(); | 3237 | mutex_unlock(&vwsnd_mutex); |
| 3238 | return retval; | 3238 | return retval; |
| 3239 | } | 3239 | } |
| 3240 | 3240 | ||
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index e7a8cd058efb..12e34653b8a8 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
| @@ -207,12 +207,12 @@ config SND_CMIPCI | |||
| 207 | 207 | ||
| 208 | config SND_OXYGEN_LIB | 208 | config SND_OXYGEN_LIB |
| 209 | tristate | 209 | tristate |
| 210 | select SND_PCM | ||
| 211 | select SND_MPU401_UART | ||
| 212 | 210 | ||
| 213 | config SND_OXYGEN | 211 | config SND_OXYGEN |
| 214 | tristate "C-Media 8788 (Oxygen)" | 212 | tristate "C-Media 8788 (Oxygen)" |
| 215 | select SND_OXYGEN_LIB | 213 | select SND_OXYGEN_LIB |
| 214 | select SND_PCM | ||
| 215 | select SND_MPU401_UART | ||
| 216 | help | 216 | help |
| 217 | Say Y here to include support for sound cards based on the | 217 | Say Y here to include support for sound cards based on the |
| 218 | C-Media CMI8788 (Oxygen HD Audio) chip: | 218 | C-Media CMI8788 (Oxygen HD Audio) chip: |
| @@ -581,6 +581,8 @@ config SND_HDSPM | |||
| 581 | config SND_HIFIER | 581 | config SND_HIFIER |
| 582 | tristate "TempoTec HiFier Fantasia" | 582 | tristate "TempoTec HiFier Fantasia" |
| 583 | select SND_OXYGEN_LIB | 583 | select SND_OXYGEN_LIB |
| 584 | select SND_PCM | ||
| 585 | select SND_MPU401_UART | ||
| 584 | help | 586 | help |
| 585 | Say Y here to include support for the MediaTek/TempoTec HiFier | 587 | Say Y here to include support for the MediaTek/TempoTec HiFier |
| 586 | Fantasia sound card. | 588 | Fantasia sound card. |
| @@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM | |||
| 815 | will be called snd-via82xx-modem. | 817 | will be called snd-via82xx-modem. |
| 816 | 818 | ||
| 817 | config SND_VIRTUOSO | 819 | config SND_VIRTUOSO |
| 818 | tristate "Asus Virtuoso 100/200 (Xonar)" | 820 | tristate "Asus Virtuoso 66/100/200 (Xonar)" |
| 819 | select SND_OXYGEN_LIB | 821 | select SND_OXYGEN_LIB |
| 822 | select SND_PCM | ||
| 823 | select SND_MPU401_UART | ||
| 824 | select SND_JACK if INPUT=y || INPUT=SND | ||
| 820 | help | 825 | help |
| 821 | Say Y here to include support for sound cards based on the | 826 | Say Y here to include support for sound cards based on the |
| 822 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, | 827 | Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, |
| 823 | Essence ST (Deluxe), and Essence STX. | 828 | Essence ST (Deluxe), and Essence STX. |
| 824 | Support for the DS is experimental. | 829 | Support for the HDAV1.3 (Deluxe) is incomplete; for the |
| 825 | Support for the HDAV1.3 (Deluxe) is very experimental. | 830 | HDAV1.3 Slim and Xense, missing. |
| 826 | 831 | ||
| 827 | To compile this driver as a module, choose M here: the module | 832 | To compile this driver as a module, choose M here: the module |
| 828 | will be called snd-virtuoso. | 833 | will be called snd-virtuoso. |
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c index c92f493d341e..557c782ae4fc 100644 --- a/sound/pci/au88x0/au88x0_mixer.c +++ b/sound/pci/au88x0/au88x0_mixer.c | |||
| @@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex) | |||
| 23 | if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0) | 23 | if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0) |
| 24 | return err; | 24 | return err; |
| 25 | memset(&ac97, 0, sizeof(ac97)); | 25 | memset(&ac97, 0, sizeof(ac97)); |
| 26 | // Intialize AC97 codec stuff. | 26 | // Initialize AC97 codec stuff. |
| 27 | ac97.private_data = vortex; | 27 | ac97.private_data = vortex; |
| 28 | ac97.scaps = AC97_SCAP_NO_SPDIF; | 28 | ac97.scaps = AC97_SCAP_NO_SPDIF; |
| 29 | err = snd_ac97_mixer(pbus, &ac97, &vortex->codec); | 29 | err = snd_ac97_mixer(pbus, &ac97, &vortex->codec); |
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 14b8d9a91aae..f19c11077255 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h | |||
| @@ -670,8 +670,9 @@ struct snd_ca0106_details { | |||
| 670 | gpio_type = 2 -> shared side-out/line-in. */ | 670 | gpio_type = 2 -> shared side-out/line-in. */ |
| 671 | int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume | 671 | int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume |
| 672 | controls, phone, mic, line-in and aux. */ | 672 | controls, phone, mic, line-in and aux. */ |
| 673 | int spi_dac; /* spi_dac=1 adds the mute switch for each analog | 673 | u16 spi_dac; /* spi_dac = 0 -> no spi interface for DACs |
| 674 | output, front, rear, etc. */ | 674 | spi_dac = 0x<front><rear><center-lfe><side> |
| 675 | -> specifies DAC id for each channel pair. */ | ||
| 675 | }; | 676 | }; |
| 676 | 677 | ||
| 677 | // definition of the chip-specific record | 678 | // definition of the chip-specific record |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 0a3d3d6e77b4..d2d12c08f937 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
| @@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
| 227 | .name = "Audigy SE [SB0570]", | 227 | .name = "Audigy SE [SB0570]", |
| 228 | .gpio_type = 1, | 228 | .gpio_type = 1, |
| 229 | .i2c_adc = 1, | 229 | .i2c_adc = 1, |
| 230 | .spi_dac = 1 } , | 230 | .spi_dac = 0x4021 } , |
| 231 | /* New Audigy LS. Has a different DAC. */ | 231 | /* New Audigy LS. Has a different DAC. */ |
| 232 | /* SB0570: | 232 | /* SB0570: |
| 233 | * CTRL:CA0106-DAT | 233 | * CTRL:CA0106-DAT |
| @@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
| 238 | .name = "Audigy SE OEM [SB0570a]", | 238 | .name = "Audigy SE OEM [SB0570a]", |
| 239 | .gpio_type = 1, | 239 | .gpio_type = 1, |
| 240 | .i2c_adc = 1, | 240 | .i2c_adc = 1, |
| 241 | .spi_dac = 1 } , | 241 | .spi_dac = 0x4021 } , |
| 242 | /* Sound Blaster 5.1vx | ||
| 243 | * Tested: Playback on front, rear, center/lfe speakers | ||
| 244 | * Not-Tested: Capture | ||
| 245 | */ | ||
| 246 | { .serial = 0x10041102, | ||
| 247 | .name = "Sound Blaster 5.1vx [SB1070]", | ||
| 248 | .gpio_type = 1, | ||
| 249 | .i2c_adc = 0, | ||
| 250 | .spi_dac = 0x0124 | ||
| 251 | } , | ||
| 242 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ | 252 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ |
| 243 | /* SB0438 | 253 | /* SB0438 |
| 244 | * CTRL:CA0106-DAT | 254 | * CTRL:CA0106-DAT |
| @@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
| 254 | .name = "MSI K8N Diamond MB", | 264 | .name = "MSI K8N Diamond MB", |
| 255 | .gpio_type = 2, | 265 | .gpio_type = 2, |
| 256 | .i2c_adc = 1, | 266 | .i2c_adc = 1, |
| 257 | .spi_dac = 1 } , | 267 | .spi_dac = 0x4021 } , |
| 258 | /* Giga-byte GA-G1975X mobo | 268 | /* Giga-byte GA-G1975X mobo |
| 259 | * Novell bnc#395807 | 269 | * Novell bnc#395807 |
| 260 | */ | 270 | */ |
| @@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime) | |||
| 483 | } | 493 | } |
| 484 | 494 | ||
| 485 | static const int spi_dacd_reg[] = { | 495 | static const int spi_dacd_reg[] = { |
| 486 | [PCM_FRONT_CHANNEL] = SPI_DACD4_REG, | 496 | SPI_DACD0_REG, |
| 487 | [PCM_REAR_CHANNEL] = SPI_DACD0_REG, | 497 | SPI_DACD1_REG, |
| 488 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG, | 498 | SPI_DACD2_REG, |
| 489 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG, | 499 | 0, |
| 500 | SPI_DACD4_REG, | ||
| 490 | }; | 501 | }; |
| 491 | static const int spi_dacd_bit[] = { | 502 | static const int spi_dacd_bit[] = { |
| 492 | [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT, | 503 | SPI_DACD0_BIT, |
| 493 | [PCM_REAR_CHANNEL] = SPI_DACD0_BIT, | 504 | SPI_DACD1_BIT, |
| 494 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT, | 505 | SPI_DACD2_BIT, |
| 495 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, | 506 | 0, |
| 507 | SPI_DACD4_BIT, | ||
| 496 | }; | 508 | }; |
| 497 | 509 | ||
| 498 | static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) | 510 | static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) |
| @@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) | |||
| 504 | } | 516 | } |
| 505 | } | 517 | } |
| 506 | 518 | ||
| 519 | static int snd_ca0106_channel_dac(struct snd_ca0106_details *details, | ||
| 520 | int channel_id) | ||
| 521 | { | ||
| 522 | switch (channel_id) { | ||
| 523 | case PCM_FRONT_CHANNEL: | ||
| 524 | return (details->spi_dac & 0xf000) >> (4 * 3); | ||
| 525 | case PCM_REAR_CHANNEL: | ||
| 526 | return (details->spi_dac & 0x0f00) >> (4 * 2); | ||
| 527 | case PCM_CENTER_LFE_CHANNEL: | ||
| 528 | return (details->spi_dac & 0x00f0) >> (4 * 1); | ||
| 529 | case PCM_UNKNOWN_CHANNEL: | ||
| 530 | return (details->spi_dac & 0x000f) >> (4 * 0); | ||
| 531 | default: | ||
| 532 | snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n", | ||
| 533 | channel_id); | ||
| 534 | } | ||
| 535 | return 0; | ||
| 536 | } | ||
| 537 | |||
| 538 | static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id, | ||
| 539 | int power) | ||
| 540 | { | ||
| 541 | if (chip->details->spi_dac) { | ||
| 542 | const int dac = snd_ca0106_channel_dac(chip->details, | ||
| 543 | channel_id); | ||
| 544 | const int reg = spi_dacd_reg[dac]; | ||
| 545 | const int bit = spi_dacd_bit[dac]; | ||
| 546 | |||
| 547 | if (power) | ||
| 548 | /* Power up */ | ||
| 549 | chip->spi_dac_reg[reg] &= ~bit; | ||
| 550 | else | ||
| 551 | /* Power down */ | ||
| 552 | chip->spi_dac_reg[reg] |= bit; | ||
| 553 | return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | ||
| 554 | } | ||
| 555 | return 0; | ||
| 556 | } | ||
| 557 | |||
| 507 | /* open_playback callback */ | 558 | /* open_playback callback */ |
| 508 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, | 559 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, |
| 509 | int channel_id) | 560 | int channel_id) |
| @@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr | |||
| 543 | return err; | 594 | return err; |
| 544 | snd_pcm_set_sync(substream); | 595 | snd_pcm_set_sync(substream); |
| 545 | 596 | ||
| 546 | if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) { | 597 | /* Front channel dac should already be on */ |
| 547 | const int reg = spi_dacd_reg[channel_id]; | 598 | if (channel_id != PCM_FRONT_CHANNEL) { |
| 548 | 599 | err = snd_ca0106_pcm_power_dac(chip, channel_id, 1); | |
| 549 | /* Power up dac */ | ||
| 550 | chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; | ||
| 551 | err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | ||
| 552 | if (err < 0) | 600 | if (err < 0) |
| 553 | return err; | 601 | return err; |
| 554 | } | 602 | } |
| @@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) | |||
| 568 | 616 | ||
| 569 | restore_spdif_bits(chip, epcm->channel_id); | 617 | restore_spdif_bits(chip, epcm->channel_id); |
| 570 | 618 | ||
| 571 | if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { | 619 | /* Front channel dac should stay on */ |
| 572 | const int reg = spi_dacd_reg[epcm->channel_id]; | 620 | if (epcm->channel_id != PCM_FRONT_CHANNEL) { |
| 573 | 621 | int err; | |
| 574 | /* Power down DAC */ | 622 | err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0); |
| 575 | chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id]; | 623 | if (err < 0) |
| 576 | snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | 624 | return err; |
| 577 | } | 625 | } |
| 626 | |||
| 578 | /* FIXME: maybe zero others */ | 627 | /* FIXME: maybe zero others */ |
| 579 | return 0; | 628 | return 0; |
| 580 | } | 629 | } |
| @@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream) | |||
| 1002 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 1051 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
| 1003 | struct snd_pcm_runtime *runtime = substream->runtime; | 1052 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 1004 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 1053 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
| 1005 | snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; | 1054 | unsigned int ptr, prev_ptr; |
| 1006 | int channel = epcm->channel_id; | 1055 | int channel = epcm->channel_id; |
| 1056 | int timeout = 10; | ||
| 1007 | 1057 | ||
| 1008 | if (!epcm->running) | 1058 | if (!epcm->running) |
| 1009 | return 0; | 1059 | return 0; |
| 1010 | 1060 | ||
| 1011 | ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1061 | prev_ptr = -1; |
| 1012 | ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1062 | do { |
| 1013 | ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1063 | ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); |
| 1014 | if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1064 | ptr = (ptr >> 3) * runtime->period_size; |
| 1015 | ptr2 = bytes_to_frames(runtime, ptr1); | 1065 | ptr += bytes_to_frames(runtime, |
| 1016 | ptr2+= (ptr4 >> 3) * runtime->period_size; | 1066 | snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel)); |
| 1017 | ptr=ptr2; | 1067 | if (ptr >= runtime->buffer_size) |
| 1018 | if (ptr >= runtime->buffer_size) | 1068 | ptr -= runtime->buffer_size; |
| 1019 | ptr -= runtime->buffer_size; | 1069 | if (prev_ptr == ptr) |
| 1020 | /* | 1070 | return ptr; |
| 1021 | printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " | 1071 | prev_ptr = ptr; |
| 1022 | "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", | 1072 | } while (--timeout); |
| 1023 | ptr1, ptr2, ptr, (int)runtime->buffer_size, | 1073 | snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n"); |
| 1024 | (int)runtime->period_size, (int)runtime->frame_bits, | 1074 | return 0; |
| 1025 | (int)runtime->rate); | ||
| 1026 | */ | ||
| 1027 | return ptr; | ||
| 1028 | } | 1075 | } |
| 1029 | 1076 | ||
| 1030 | /* pointer_capture callback */ | 1077 | /* pointer_capture callback */ |
| @@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = { | |||
| 1362 | SPI_REG(12, 0x00), | 1409 | SPI_REG(12, 0x00), |
| 1363 | SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), | 1410 | SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), |
| 1364 | SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), | 1411 | SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), |
| 1365 | SPI_REG(SPI_DACD4_REG, 0x00), | 1412 | SPI_REG(SPI_DACD4_REG, SPI_DACD4_BIT), |
| 1366 | }; | 1413 | }; |
| 1367 | 1414 | ||
| 1368 | static unsigned int i2c_adc_init[][2] = { | 1415 | static unsigned int i2c_adc_init[][2] = { |
| @@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) | |||
| 1541 | /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ | 1588 | /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ |
| 1542 | } | 1589 | } |
| 1543 | 1590 | ||
| 1544 | if (chip->details->spi_dac == 1) { | 1591 | if (chip->details->spi_dac) { |
| 1545 | /* The SB0570 use SPI to control DAC. */ | 1592 | /* The SB0570 use SPI to control DAC. */ |
| 1546 | int size, n; | 1593 | int size, n; |
| 1547 | 1594 | ||
| @@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) | |||
| 1553 | if (reg < ARRAY_SIZE(chip->spi_dac_reg)) | 1600 | if (reg < ARRAY_SIZE(chip->spi_dac_reg)) |
| 1554 | chip->spi_dac_reg[reg] = spi_dac_init[n]; | 1601 | chip->spi_dac_reg[reg] = spi_dac_init[n]; |
| 1555 | } | 1602 | } |
| 1603 | |||
| 1604 | /* Enable front dac only */ | ||
| 1605 | snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1); | ||
| 1556 | } | 1606 | } |
| 1557 | } | 1607 | } |
| 1558 | 1608 | ||
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 85fd315d9999..630aa4998189 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
| @@ -676,28 +676,65 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = | |||
| 676 | I2C_VOLUME("Aux Capture Volume", 3), | 676 | I2C_VOLUME("Aux Capture Volume", 3), |
| 677 | }; | 677 | }; |
| 678 | 678 | ||
| 679 | #define SPI_SWITCH(xname,reg,bit) \ | 679 | static const int spi_dmute_reg[] = { |
| 680 | { \ | 680 | SPI_DMUTE0_REG, |
| 681 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 681 | SPI_DMUTE1_REG, |
| 682 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 682 | SPI_DMUTE2_REG, |
| 683 | .info = spi_mute_info, \ | 683 | 0, |
| 684 | .get = spi_mute_get, \ | 684 | SPI_DMUTE4_REG, |
| 685 | .put = spi_mute_put, \ | 685 | }; |
| 686 | .private_value = (reg<<SPI_REG_SHIFT) | (bit) \ | 686 | static const int spi_dmute_bit[] = { |
| 687 | } | 687 | SPI_DMUTE0_BIT, |
| 688 | 688 | SPI_DMUTE1_BIT, | |
| 689 | static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[] | 689 | SPI_DMUTE2_BIT, |
| 690 | __devinitdata = { | 690 | 0, |
| 691 | SPI_SWITCH("Analog Front Playback Switch", | 691 | SPI_DMUTE4_BIT, |
| 692 | SPI_DMUTE4_REG, SPI_DMUTE4_BIT), | ||
| 693 | SPI_SWITCH("Analog Rear Playback Switch", | ||
| 694 | SPI_DMUTE0_REG, SPI_DMUTE0_BIT), | ||
| 695 | SPI_SWITCH("Analog Center/LFE Playback Switch", | ||
| 696 | SPI_DMUTE2_REG, SPI_DMUTE2_BIT), | ||
| 697 | SPI_SWITCH("Analog Side Playback Switch", | ||
| 698 | SPI_DMUTE1_REG, SPI_DMUTE1_BIT), | ||
| 699 | }; | 692 | }; |
| 700 | 693 | ||
| 694 | static struct snd_kcontrol_new __devinit | ||
| 695 | snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details, | ||
| 696 | int channel_id) | ||
| 697 | { | ||
| 698 | struct snd_kcontrol_new spi_switch = {0}; | ||
| 699 | int reg, bit; | ||
| 700 | int dac_id; | ||
| 701 | |||
| 702 | spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
| 703 | spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
| 704 | spi_switch.info = spi_mute_info; | ||
| 705 | spi_switch.get = spi_mute_get; | ||
| 706 | spi_switch.put = spi_mute_put; | ||
| 707 | |||
| 708 | switch (channel_id) { | ||
| 709 | case PCM_FRONT_CHANNEL: | ||
| 710 | spi_switch.name = "Analog Front Playback Switch"; | ||
| 711 | dac_id = (details->spi_dac & 0xf000) >> (4 * 3); | ||
| 712 | break; | ||
| 713 | case PCM_REAR_CHANNEL: | ||
| 714 | spi_switch.name = "Analog Rear Playback Switch"; | ||
| 715 | dac_id = (details->spi_dac & 0x0f00) >> (4 * 2); | ||
| 716 | break; | ||
| 717 | case PCM_CENTER_LFE_CHANNEL: | ||
| 718 | spi_switch.name = "Analog Center/LFE Playback Switch"; | ||
| 719 | dac_id = (details->spi_dac & 0x00f0) >> (4 * 1); | ||
| 720 | break; | ||
| 721 | case PCM_UNKNOWN_CHANNEL: | ||
| 722 | spi_switch.name = "Analog Side Playback Switch"; | ||
| 723 | dac_id = (details->spi_dac & 0x000f) >> (4 * 0); | ||
| 724 | break; | ||
| 725 | default: | ||
| 726 | /* Unused channel */ | ||
| 727 | spi_switch.name = NULL; | ||
| 728 | dac_id = 0; | ||
| 729 | } | ||
| 730 | reg = spi_dmute_reg[dac_id]; | ||
| 731 | bit = spi_dmute_bit[dac_id]; | ||
| 732 | |||
| 733 | spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit; | ||
| 734 | |||
| 735 | return spi_switch; | ||
| 736 | } | ||
| 737 | |||
| 701 | static int __devinit remove_ctl(struct snd_card *card, const char *name) | 738 | static int __devinit remove_ctl(struct snd_card *card, const char *name) |
| 702 | { | 739 | { |
| 703 | struct snd_ctl_elem_id id; | 740 | struct snd_ctl_elem_id id; |
| @@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
| 832 | if (err < 0) | 869 | if (err < 0) |
| 833 | return err; | 870 | return err; |
| 834 | } | 871 | } |
| 835 | if (emu->details->spi_dac == 1) | 872 | if (emu->details->spi_dac) { |
| 836 | ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls); | 873 | int i; |
| 874 | for (i = 0;; i++) { | ||
| 875 | struct snd_kcontrol_new ctl; | ||
| 876 | ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i); | ||
| 877 | if (!ctl.name) | ||
| 878 | break; | ||
| 879 | err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu)); | ||
| 880 | if (err < 0) | ||
| 881 | return err; | ||
| 882 | } | ||
| 883 | } | ||
| 837 | 884 | ||
| 838 | /* Create virtual master controls */ | 885 | /* Create virtual master controls */ |
| 839 | vmaster = snd_ctl_make_virtual_master("Master Playback Volume", | 886 | vmaster = snd_ctl_make_virtual_master("Master Playback Volume", |
| @@ -845,7 +892,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
| 845 | return err; | 892 | return err; |
| 846 | add_slaves(card, vmaster, slave_vols); | 893 | add_slaves(card, vmaster, slave_vols); |
| 847 | 894 | ||
| 848 | if (emu->details->spi_dac == 1) { | 895 | if (emu->details->spi_dac) { |
| 849 | vmaster = snd_ctl_make_virtual_master("Master Playback Switch", | 896 | vmaster = snd_ctl_make_virtual_master("Master Playback Switch", |
| 850 | NULL); | 897 | NULL); |
| 851 | if (!vmaster) | 898 | if (!vmaster) |
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 8578c70c61f2..bab564824efe 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c | |||
| @@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input = | |||
| 321 | 321 | ||
| 322 | static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) | 322 | static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) |
| 323 | { | 323 | { |
| 324 | struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data; | 324 | struct snd_emu10k1_midi *midi = rmidi->private_data; |
| 325 | midi->interrupt = NULL; | 325 | midi->interrupt = NULL; |
| 326 | midi->rmidi = NULL; | 326 | midi->rmidi = NULL; |
| 327 | } | 327 | } |
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index d216362626d0..712c1710f9a2 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c | |||
| @@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) | |||
| 563 | case ICE1712_SUBDEVICE_DELTA1010E: | 563 | case ICE1712_SUBDEVICE_DELTA1010E: |
| 564 | case ICE1712_SUBDEVICE_DELTA1010LT: | 564 | case ICE1712_SUBDEVICE_DELTA1010LT: |
| 565 | case ICE1712_SUBDEVICE_MEDIASTATION: | 565 | case ICE1712_SUBDEVICE_MEDIASTATION: |
| 566 | case ICE1712_SUBDEVICE_EDIROLDA2496: | ||
| 566 | ice->num_total_dacs = 8; | 567 | ice->num_total_dacs = 8; |
| 567 | ice->num_total_adcs = 8; | 568 | ice->num_total_adcs = 8; |
| 568 | break; | 569 | break; |
| @@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) | |||
| 635 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice); | 636 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice); |
| 636 | break; | 637 | break; |
| 637 | case ICE1712_SUBDEVICE_DELTA1010LT: | 638 | case ICE1712_SUBDEVICE_DELTA1010LT: |
| 639 | case ICE1712_SUBDEVICE_EDIROLDA2496: | ||
| 638 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice); | 640 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice); |
| 639 | break; | 641 | break; |
| 640 | case ICE1712_SUBDEVICE_DELTA66: | 642 | case ICE1712_SUBDEVICE_DELTA66: |
| @@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) | |||
| 734 | case ICE1712_SUBDEVICE_DELTA66: | 736 | case ICE1712_SUBDEVICE_DELTA66: |
| 735 | case ICE1712_SUBDEVICE_VX442: | 737 | case ICE1712_SUBDEVICE_VX442: |
| 736 | case ICE1712_SUBDEVICE_DELTA66E: | 738 | case ICE1712_SUBDEVICE_DELTA66E: |
| 739 | case ICE1712_SUBDEVICE_EDIROLDA2496: | ||
| 737 | err = snd_ice1712_akm4xxx_build_controls(ice); | 740 | err = snd_ice1712_akm4xxx_build_controls(ice); |
| 738 | if (err < 0) | 741 | if (err < 0) |
| 739 | return err; | 742 | return err; |
| @@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { | |||
| 813 | .chip_init = snd_ice1712_delta_init, | 816 | .chip_init = snd_ice1712_delta_init, |
| 814 | .build_controls = snd_ice1712_delta_add_controls, | 817 | .build_controls = snd_ice1712_delta_add_controls, |
| 815 | }, | 818 | }, |
| 819 | { | ||
| 820 | .subvendor = ICE1712_SUBDEVICE_EDIROLDA2496, | ||
| 821 | .name = "Edirol DA2496", | ||
| 822 | .model = "da2496", | ||
| 823 | .chip_init = snd_ice1712_delta_init, | ||
| 824 | .build_controls = snd_ice1712_delta_add_controls, | ||
| 825 | }, | ||
| 816 | { } /* terminator */ | 826 | { } /* terminator */ |
| 817 | }; | 827 | }; |
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index f7f14df81f26..1a0ac6cd6501 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h | |||
| @@ -34,7 +34,8 @@ | |||
| 34 | "{MidiMan M Audio,Delta 410},"\ | 34 | "{MidiMan M Audio,Delta 410},"\ |
| 35 | "{MidiMan M Audio,Audiophile 24/96},"\ | 35 | "{MidiMan M Audio,Audiophile 24/96},"\ |
| 36 | "{Digigram,VX442},"\ | 36 | "{Digigram,VX442},"\ |
| 37 | "{Lionstracs,Mediastation}," | 37 | "{Lionstracs,Mediastation},"\ |
| 38 | "{Edirol,DA2496}," | ||
| 38 | 39 | ||
| 39 | #define ICE1712_SUBDEVICE_DELTA1010 0x121430d6 | 40 | #define ICE1712_SUBDEVICE_DELTA1010 0x121430d6 |
| 40 | #define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6 | 41 | #define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6 |
| @@ -47,6 +48,7 @@ | |||
| 47 | #define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6 | 48 | #define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6 |
| 48 | #define ICE1712_SUBDEVICE_VX442 0x12143cd6 | 49 | #define ICE1712_SUBDEVICE_VX442 0x12143cd6 |
| 49 | #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 | 50 | #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 |
| 51 | #define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010 | ||
| 50 | 52 | ||
| 51 | /* entry point */ | 53 | /* entry point */ |
| 52 | extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; | 54 | extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 6bc3f91b7281..cdb873f5da50 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
| @@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = { | |||
| 638 | */ | 638 | */ |
| 639 | static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 639 | static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
| 640 | { | 640 | { |
| 641 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 641 | struct snd_ice1712 *ice = entry->private_data; |
| 642 | char line[64]; | 642 | char line[64]; |
| 643 | unsigned int reg, val; | 643 | unsigned int reg, val; |
| 644 | mutex_lock(&ice->gpio_mutex); | 644 | mutex_lock(&ice->gpio_mutex); |
| @@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf | |||
| 653 | 653 | ||
| 654 | static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 654 | static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
| 655 | { | 655 | { |
| 656 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 656 | struct snd_ice1712 *ice = entry->private_data; |
| 657 | int reg, val; | 657 | int reg, val; |
| 658 | 658 | ||
| 659 | mutex_lock(&ice->gpio_mutex); | 659 | mutex_lock(&ice->gpio_mutex); |
| @@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice) | |||
| 676 | 676 | ||
| 677 | static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 677 | static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
| 678 | { | 678 | { |
| 679 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 679 | struct snd_ice1712 *ice = entry->private_data; |
| 680 | int reg, val; | 680 | int reg, val; |
| 681 | 681 | ||
| 682 | mutex_lock(&ice->gpio_mutex); | 682 | mutex_lock(&ice->gpio_mutex); |
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 2a8e5cd8f2d8..e36ddb94c382 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
| @@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice) | |||
| 654 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, | 654 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, |
| 655 | struct snd_info_buffer *buffer) | 655 | struct snd_info_buffer *buffer) |
| 656 | { | 656 | { |
| 657 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 657 | struct snd_ice1712 *ice = entry->private_data; |
| 658 | int reg, val; | 658 | int reg, val; |
| 659 | /* registers 0x0 - 0x14 */ | 659 | /* registers 0x0 - 0x14 */ |
| 660 | for (reg = 0; reg <= 0x15; reg++) { | 660 | for (reg = 0; reg <= 0x15; reg++) { |
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 6c0a11adb2a8..98a8eb3c92f7 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
| @@ -79,6 +79,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { | |||
| 79 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, | 79 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, |
| 80 | { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF }, | 80 | { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF }, |
| 81 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, | 81 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, |
| 82 | { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF }, | ||
| 82 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, | 83 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, |
| 83 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, | 84 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, |
| 84 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, | 85 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, |
| @@ -505,7 +506,8 @@ static const struct oxygen_model model_generic = { | |||
| 505 | PLAYBACK_2_TO_AC97_1 | | 506 | PLAYBACK_2_TO_AC97_1 | |
| 506 | CAPTURE_0_FROM_I2S_1 | | 507 | CAPTURE_0_FROM_I2S_1 | |
| 507 | CAPTURE_1_FROM_SPDIF | | 508 | CAPTURE_1_FROM_SPDIF | |
| 508 | CAPTURE_2_FROM_AC97_1, | 509 | CAPTURE_2_FROM_AC97_1 | |
| 510 | AC97_CD_INPUT, | ||
| 509 | .dac_channels = 8, | 511 | .dac_channels = 8, |
| 510 | .dac_volume_min = 0, | 512 | .dac_volume_min = 0, |
| 511 | .dac_volume_max = 255, | 513 | .dac_volume_max = 255, |
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index a3409edcfb50..7d5222caa0a9 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | /* CAPTURE_3_FROM_I2S_3 not implemented */ | 34 | /* CAPTURE_3_FROM_I2S_3 not implemented */ |
| 35 | #define MIDI_OUTPUT 0x0800 | 35 | #define MIDI_OUTPUT 0x0800 |
| 36 | #define MIDI_INPUT 0x1000 | 36 | #define MIDI_INPUT 0x1000 |
| 37 | #define AC97_CD_INPUT 0x2000 | ||
| 37 | 38 | ||
| 38 | enum { | 39 | enum { |
| 39 | CONTROL_SPDIF_PCM, | 40 | CONTROL_SPDIF_PCM, |
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 7e93cf884437..e5ebe56fb0c5 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
| @@ -308,25 +308,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip, | |||
| 308 | } | 308 | } |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | static void pci_bridge_magic(void) | 311 | static void configure_pcie_bridge(struct pci_dev *pci) |
| 312 | { | 312 | { |
| 313 | struct pci_dev *pci = NULL; | 313 | enum { PEX811X, PI7C9X110 }; |
| 314 | static const struct pci_device_id bridge_ids[] = { | ||
| 315 | { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X }, | ||
| 316 | { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X }, | ||
| 317 | { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 }, | ||
| 318 | { } | ||
| 319 | }; | ||
| 320 | struct pci_dev *bridge; | ||
| 321 | const struct pci_device_id *id; | ||
| 314 | u32 tmp; | 322 | u32 tmp; |
| 315 | 323 | ||
| 316 | for (;;) { | 324 | if (!pci->bus || !pci->bus->self) |
| 317 | /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */ | 325 | return; |
| 318 | pci = pci_get_device(0x12d8, 0xe110, pci); | 326 | bridge = pci->bus->self; |
| 319 | if (!pci) | 327 | |
| 320 | break; | 328 | id = pci_match_id(bridge_ids, bridge); |
| 321 | /* | 329 | if (!id) |
| 322 | * ... configure its secondary internal arbiter to park to | 330 | return; |
| 323 | * the secondary port, instead of to the last master. | 331 | |
| 324 | */ | 332 | switch (id->driver_data) { |
| 325 | if (!pci_read_config_dword(pci, 0x40, &tmp)) { | 333 | case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */ |
| 326 | tmp |= 1; | 334 | pci_read_config_dword(bridge, 0x48, &tmp); |
| 327 | pci_write_config_dword(pci, 0x40, tmp); | 335 | tmp |= 1; /* enable blind prefetching */ |
| 328 | } | 336 | tmp |= 1 << 11; /* enable beacon generation */ |
| 329 | /* Why? Try asking C-Media. */ | 337 | pci_write_config_dword(bridge, 0x48, tmp); |
| 338 | |||
| 339 | pci_write_config_dword(bridge, 0x84, 0x0c); | ||
| 340 | pci_read_config_dword(bridge, 0x88, &tmp); | ||
| 341 | tmp &= ~(7 << 27); | ||
| 342 | tmp |= 2 << 27; /* set prefetch size to 128 bytes */ | ||
| 343 | pci_write_config_dword(bridge, 0x88, tmp); | ||
| 344 | break; | ||
| 345 | |||
| 346 | case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */ | ||
| 347 | pci_read_config_dword(bridge, 0x40, &tmp); | ||
| 348 | tmp |= 1; /* park the PCI arbiter to the sound chip */ | ||
| 349 | pci_write_config_dword(bridge, 0x40, tmp); | ||
| 350 | break; | ||
| 330 | } | 351 | } |
| 331 | } | 352 | } |
| 332 | 353 | ||
| @@ -613,7 +634,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
| 613 | snd_card_set_dev(card, &pci->dev); | 634 | snd_card_set_dev(card, &pci->dev); |
| 614 | card->private_free = oxygen_card_free; | 635 | card->private_free = oxygen_card_free; |
| 615 | 636 | ||
| 616 | pci_bridge_magic(); | 637 | configure_pcie_bridge(pci); |
| 617 | oxygen_init(chip); | 638 | oxygen_init(chip); |
| 618 | chip->model.init(chip); | 639 | chip->model.init(chip); |
| 619 | 640 | ||
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index f375b8a27862..2849b36f5f7e 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
| @@ -708,7 +708,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, | |||
| 708 | .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \ | 708 | .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \ |
| 709 | } | 709 | } |
| 710 | 710 | ||
| 711 | static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0); | 711 | static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0); |
| 712 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); | 712 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); |
| 713 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); | 713 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); |
| 714 | 714 | ||
| @@ -972,6 +972,9 @@ static int add_controls(struct oxygen *chip, | |||
| 972 | if (!strcmp(template.name, "Stereo Upmixing") && | 972 | if (!strcmp(template.name, "Stereo Upmixing") && |
| 973 | chip->model.dac_channels == 2) | 973 | chip->model.dac_channels == 2) |
| 974 | continue; | 974 | continue; |
| 975 | if (!strncmp(template.name, "CD Capture ", 11) && | ||
| 976 | !(chip->model.device_config & AC97_CD_INPUT)) | ||
| 977 | continue; | ||
| 975 | if (!strcmp(template.name, "Master Playback Volume") && | 978 | if (!strcmp(template.name, "Master Playback Volume") && |
| 976 | chip->model.dac_tlv) { | 979 | chip->model.dac_tlv) { |
| 977 | template.tlv.p = chip->model.dac_tlv; | 980 | template.tlv.p = chip->model.dac_tlv; |
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 9dff6954c397..814667442eb0 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
| @@ -56,8 +56,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { | |||
| 56 | .channels_max = 2, | 56 | .channels_max = 2, |
| 57 | .buffer_bytes_max = BUFFER_BYTES_MAX, | 57 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
| 58 | .period_bytes_min = PERIOD_BYTES_MIN, | 58 | .period_bytes_min = PERIOD_BYTES_MIN, |
| 59 | .period_bytes_max = BUFFER_BYTES_MAX / 2, | 59 | .period_bytes_max = BUFFER_BYTES_MAX, |
| 60 | .periods_min = 2, | 60 | .periods_min = 1, |
| 61 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | 61 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
| 62 | }; | 62 | }; |
| 63 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | 63 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { |
| @@ -82,8 +82,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | |||
| 82 | .channels_max = 8, | 82 | .channels_max = 8, |
| 83 | .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, | 83 | .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, |
| 84 | .period_bytes_min = PERIOD_BYTES_MIN, | 84 | .period_bytes_min = PERIOD_BYTES_MIN, |
| 85 | .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2, | 85 | .period_bytes_max = BUFFER_BYTES_MAX_MULTICH, |
| 86 | .periods_min = 2, | 86 | .periods_min = 1, |
| 87 | .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, | 87 | .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, |
| 88 | }; | 88 | }; |
| 89 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { | 89 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { |
| @@ -100,8 +100,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { | |||
| 100 | .channels_max = 2, | 100 | .channels_max = 2, |
| 101 | .buffer_bytes_max = BUFFER_BYTES_MAX, | 101 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
| 102 | .period_bytes_min = PERIOD_BYTES_MIN, | 102 | .period_bytes_min = PERIOD_BYTES_MIN, |
| 103 | .period_bytes_max = BUFFER_BYTES_MAX / 2, | 103 | .period_bytes_max = BUFFER_BYTES_MAX, |
| 104 | .periods_min = 2, | 104 | .periods_min = 1, |
| 105 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | 105 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h index 72de159d4567..4dcd41b78258 100644 --- a/sound/pci/oxygen/oxygen_regs.h +++ b/sound/pci/oxygen/oxygen_regs.h | |||
| @@ -436,13 +436,15 @@ | |||
| 436 | /* OXYGEN_CHANNEL_* */ | 436 | /* OXYGEN_CHANNEL_* */ |
| 437 | 437 | ||
| 438 | #define OXYGEN_CODEC_VERSION 0xe4 | 438 | #define OXYGEN_CODEC_VERSION 0xe4 |
| 439 | #define OXYGEN_XCID_MASK 0x07 | 439 | #define OXYGEN_CODEC_ID_MASK 0x07 |
| 440 | 440 | ||
| 441 | #define OXYGEN_REVISION 0xe6 | 441 | #define OXYGEN_REVISION 0xe6 |
| 442 | #define OXYGEN_REVISION_XPKGID_MASK 0x0007 | 442 | #define OXYGEN_PACKAGE_ID_MASK 0x0007 |
| 443 | #define OXYGEN_PACKAGE_ID_8786 0x0004 | ||
| 444 | #define OXYGEN_PACKAGE_ID_8787 0x0006 | ||
| 445 | #define OXYGEN_PACKAGE_ID_8788 0x0007 | ||
| 443 | #define OXYGEN_REVISION_MASK 0xfff8 | 446 | #define OXYGEN_REVISION_MASK 0xfff8 |
| 444 | #define OXYGEN_REVISION_2 0x0008 /* bit flag */ | 447 | #define OXYGEN_REVISION_2 0x0008 |
| 445 | #define OXYGEN_REVISION_8787 0x0014 /* 8 bits */ | ||
| 446 | 448 | ||
| 447 | #define OXYGEN_OFFSIN_48K 0xe8 | 449 | #define OXYGEN_OFFSIN_48K 0xe8 |
| 448 | #define OXYGEN_OFFSBASE_48K 0xe9 | 450 | #define OXYGEN_OFFSBASE_48K 0xe9 |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 06c863e86e3d..469010a8b849 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
| @@ -25,9 +25,9 @@ | |||
| 25 | #include "xonar.h" | 25 | #include "xonar.h" |
| 26 | 26 | ||
| 27 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 27 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
| 28 | MODULE_DESCRIPTION("Asus AVx00 driver"); | 28 | MODULE_DESCRIPTION("Asus Virtuoso driver"); |
| 29 | MODULE_LICENSE("GPL v2"); | 29 | MODULE_LICENSE("GPL v2"); |
| 30 | MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); | 30 | MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}"); |
| 31 | 31 | ||
| 32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
| 33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
| @@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { | |||
| 49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, | 49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, |
| 50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, | 50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, |
| 51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, | 51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, |
| 52 | { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, | ||
| 52 | { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, | 53 | { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, |
| 53 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | 54 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, |
| 54 | { } | 55 | { } |
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 7c4986b27f2b..aa27c31049af 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c | |||
| @@ -367,13 +367,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, | |||
| 367 | 367 | ||
| 368 | static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); | 368 | static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); |
| 369 | 369 | ||
| 370 | static int xonar_d1_control_filter(struct snd_kcontrol_new *template) | ||
| 371 | { | ||
| 372 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
| 373 | return 1; /* no CD input */ | ||
| 374 | return 0; | ||
| 375 | } | ||
| 376 | |||
| 377 | static int xonar_d1_mixer_init(struct oxygen *chip) | 370 | static int xonar_d1_mixer_init(struct oxygen *chip) |
| 378 | { | 371 | { |
| 379 | int err; | 372 | int err; |
| @@ -391,7 +384,6 @@ static const struct oxygen_model model_xonar_d1 = { | |||
| 391 | .longname = "Asus Virtuoso 100", | 384 | .longname = "Asus Virtuoso 100", |
| 392 | .chip = "AV200", | 385 | .chip = "AV200", |
| 393 | .init = xonar_d1_init, | 386 | .init = xonar_d1_init, |
| 394 | .control_filter = xonar_d1_control_filter, | ||
| 395 | .mixer_init = xonar_d1_mixer_init, | 387 | .mixer_init = xonar_d1_mixer_init, |
| 396 | .cleanup = xonar_d1_cleanup, | 388 | .cleanup = xonar_d1_cleanup, |
| 397 | .suspend = xonar_d1_suspend, | 389 | .suspend = xonar_d1_suspend, |
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index ba18fb546b4f..d491fd6c0be2 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c | |||
| @@ -132,6 +132,18 @@ | |||
| 132 | * GPIO 5 <- 0 | 132 | * GPIO 5 <- 0 |
| 133 | */ | 133 | */ |
| 134 | 134 | ||
| 135 | /* | ||
| 136 | * Xonar HDAV1.3 Slim | ||
| 137 | * ------------------ | ||
| 138 | * | ||
| 139 | * CMI8788: | ||
| 140 | * | ||
| 141 | * GPIO 1 -> enable output | ||
| 142 | * | ||
| 143 | * TXD -> HDMI controller | ||
| 144 | * RXD <- HDMI controller | ||
| 145 | */ | ||
| 146 | |||
| 135 | #include <linux/pci.h> | 147 | #include <linux/pci.h> |
| 136 | #include <linux/delay.h> | 148 | #include <linux/delay.h> |
| 137 | #include <linux/mutex.h> | 149 | #include <linux/mutex.h> |
| @@ -362,7 +374,6 @@ static void xonar_st_init_common(struct oxygen *chip) | |||
| 362 | { | 374 | { |
| 363 | struct xonar_pcm179x *data = chip->model_data; | 375 | struct xonar_pcm179x *data = chip->model_data; |
| 364 | 376 | ||
| 365 | data->generic.anti_pop_delay = 100; | ||
| 366 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; | 377 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; |
| 367 | data->dacs = chip->model.private_data ? 4 : 1; | 378 | data->dacs = chip->model.private_data ? 4 : 1; |
| 368 | data->hp_gain_offset = 2*-18; | 379 | data->hp_gain_offset = 2*-18; |
| @@ -408,6 +419,7 @@ static void xonar_st_init(struct oxygen *chip) | |||
| 408 | { | 419 | { |
| 409 | struct xonar_pcm179x *data = chip->model_data; | 420 | struct xonar_pcm179x *data = chip->model_data; |
| 410 | 421 | ||
| 422 | data->generic.anti_pop_delay = 100; | ||
| 411 | data->has_cs2000 = 1; | 423 | data->has_cs2000 = 1; |
| 412 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; | 424 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; |
| 413 | 425 | ||
| @@ -428,6 +440,7 @@ static void xonar_stx_init(struct oxygen *chip) | |||
| 428 | struct xonar_pcm179x *data = chip->model_data; | 440 | struct xonar_pcm179x *data = chip->model_data; |
| 429 | 441 | ||
| 430 | xonar_st_init_i2c(chip); | 442 | xonar_st_init_i2c(chip); |
| 443 | data->generic.anti_pop_delay = 800; | ||
| 431 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; | 444 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; |
| 432 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 445 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; |
| 433 | data->generic.ext_power_bit = GPI_EXT_POWER; | 446 | data->generic.ext_power_bit = GPI_EXT_POWER; |
| @@ -915,13 +928,6 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template) | |||
| 915 | return 0; | 928 | return 0; |
| 916 | } | 929 | } |
| 917 | 930 | ||
| 918 | static int xonar_st_control_filter(struct snd_kcontrol_new *template) | ||
| 919 | { | ||
| 920 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
| 921 | return 1; /* no CD input */ | ||
| 922 | return 0; | ||
| 923 | } | ||
| 924 | |||
| 925 | static int add_pcm1796_controls(struct oxygen *chip) | 931 | static int add_pcm1796_controls(struct oxygen *chip) |
| 926 | { | 932 | { |
| 927 | int err; | 933 | int err; |
| @@ -991,7 +997,8 @@ static const struct oxygen_model model_xonar_d2 = { | |||
| 991 | CAPTURE_0_FROM_I2S_2 | | 997 | CAPTURE_0_FROM_I2S_2 | |
| 992 | CAPTURE_1_FROM_SPDIF | | 998 | CAPTURE_1_FROM_SPDIF | |
| 993 | MIDI_OUTPUT | | 999 | MIDI_OUTPUT | |
| 994 | MIDI_INPUT, | 1000 | MIDI_INPUT | |
| 1001 | AC97_CD_INPUT, | ||
| 995 | .dac_channels = 8, | 1002 | .dac_channels = 8, |
| 996 | .dac_volume_min = 255 - 2*60, | 1003 | .dac_volume_min = 255 - 2*60, |
| 997 | .dac_volume_max = 255, | 1004 | .dac_volume_max = 255, |
| @@ -1037,7 +1044,6 @@ static const struct oxygen_model model_xonar_st = { | |||
| 1037 | .longname = "Asus Virtuoso 100", | 1044 | .longname = "Asus Virtuoso 100", |
| 1038 | .chip = "AV200", | 1045 | .chip = "AV200", |
| 1039 | .init = xonar_st_init, | 1046 | .init = xonar_st_init, |
| 1040 | .control_filter = xonar_st_control_filter, | ||
| 1041 | .mixer_init = xonar_st_mixer_init, | 1047 | .mixer_init = xonar_st_mixer_init, |
| 1042 | .cleanup = xonar_st_cleanup, | 1048 | .cleanup = xonar_st_cleanup, |
| 1043 | .suspend = xonar_st_suspend, | 1049 | .suspend = xonar_st_suspend, |
| @@ -1108,6 +1114,9 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, | |||
| 1108 | chip->model.resume = xonar_stx_resume; | 1114 | chip->model.resume = xonar_stx_resume; |
| 1109 | chip->model.set_dac_params = set_pcm1796_params; | 1115 | chip->model.set_dac_params = set_pcm1796_params; |
| 1110 | break; | 1116 | break; |
| 1117 | case 0x835e: | ||
| 1118 | snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n"); | ||
| 1119 | return -ENODEV; | ||
| 1111 | default: | 1120 | default: |
| 1112 | return -EINVAL; | 1121 | return -EINVAL; |
| 1113 | } | 1122 | } |
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index b82c1cfa96f5..200f7601276f 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c | |||
| @@ -25,16 +25,24 @@ | |||
| 25 | * SPI 0 -> WM8766 (surround, center/LFE, back) | 25 | * SPI 0 -> WM8766 (surround, center/LFE, back) |
| 26 | * SPI 1 -> WM8776 (front, input) | 26 | * SPI 1 -> WM8776 (front, input) |
| 27 | * | 27 | * |
| 28 | * GPIO 4 <- headphone detect | 28 | * GPIO 4 <- headphone detect, 0 = plugged |
| 29 | * GPIO 6 -> route input jack to input 1/2 (1/0) | 29 | * GPIO 6 -> route input jack to mic-in (0) or line-in (1) |
| 30 | * GPIO 7 -> enable output to speakers | 30 | * GPIO 7 -> enable output to front L/R speaker channels |
| 31 | * GPIO 8 -> enable output to speakers | 31 | * GPIO 8 -> enable output to other speaker channels and front panel headphone |
| 32 | * | ||
| 33 | * WM8766: | ||
| 34 | * | ||
| 35 | * input 1 <- line | ||
| 36 | * input 2 <- mic | ||
| 37 | * input 3 <- front mic | ||
| 38 | * input 4 <- aux | ||
| 32 | */ | 39 | */ |
| 33 | 40 | ||
| 34 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
| 35 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
| 36 | #include <sound/control.h> | 43 | #include <sound/control.h> |
| 37 | #include <sound/core.h> | 44 | #include <sound/core.h> |
| 45 | #include <sound/jack.h> | ||
| 38 | #include <sound/pcm.h> | 46 | #include <sound/pcm.h> |
| 39 | #include <sound/pcm_params.h> | 47 | #include <sound/pcm_params.h> |
| 40 | #include <sound/tlv.h> | 48 | #include <sound/tlv.h> |
| @@ -44,7 +52,8 @@ | |||
| 44 | 52 | ||
| 45 | #define GPIO_DS_HP_DETECT 0x0010 | 53 | #define GPIO_DS_HP_DETECT 0x0010 |
| 46 | #define GPIO_DS_INPUT_ROUTE 0x0040 | 54 | #define GPIO_DS_INPUT_ROUTE 0x0040 |
| 47 | #define GPIO_DS_OUTPUT_ENABLE 0x0180 | 55 | #define GPIO_DS_OUTPUT_FRONTLR 0x0080 |
| 56 | #define GPIO_DS_OUTPUT_ENABLE 0x0100 | ||
| 48 | 57 | ||
| 49 | #define LC_CONTROL_LIMITER 0x40000000 | 58 | #define LC_CONTROL_LIMITER 0x40000000 |
| 50 | #define LC_CONTROL_ALC 0x20000000 | 59 | #define LC_CONTROL_ALC 0x20000000 |
| @@ -56,6 +65,7 @@ struct xonar_wm87x6 { | |||
| 56 | struct snd_kcontrol *line_adcmux_control; | 65 | struct snd_kcontrol *line_adcmux_control; |
| 57 | struct snd_kcontrol *mic_adcmux_control; | 66 | struct snd_kcontrol *mic_adcmux_control; |
| 58 | struct snd_kcontrol *lc_controls[13]; | 67 | struct snd_kcontrol *lc_controls[13]; |
| 68 | struct snd_jack *hp_jack; | ||
| 59 | }; | 69 | }; |
| 60 | 70 | ||
| 61 | static void wm8776_write(struct oxygen *chip, | 71 | static void wm8776_write(struct oxygen *chip, |
| @@ -97,8 +107,12 @@ static void wm8766_write(struct oxygen *chip, | |||
| 97 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | 107 | (0 << OXYGEN_SPI_CODEC_SHIFT) | |
| 98 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 108 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
| 99 | (reg << 9) | value); | 109 | (reg << 9) | value); |
| 100 | if (reg < ARRAY_SIZE(data->wm8766_regs)) | 110 | if (reg < ARRAY_SIZE(data->wm8766_regs)) { |
| 111 | if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || | ||
| 112 | (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) | ||
| 113 | value &= ~WM8766_UPDATE; | ||
| 101 | data->wm8766_regs[reg] = value; | 114 | data->wm8766_regs[reg] = value; |
| 115 | } | ||
| 102 | } | 116 | } |
| 103 | 117 | ||
| 104 | static void wm8766_write_cached(struct oxygen *chip, | 118 | static void wm8766_write_cached(struct oxygen *chip, |
| @@ -107,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip, | |||
| 107 | struct xonar_wm87x6 *data = chip->model_data; | 121 | struct xonar_wm87x6 *data = chip->model_data; |
| 108 | 122 | ||
| 109 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || | 123 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || |
| 110 | value != data->wm8766_regs[reg]) { | 124 | value != data->wm8766_regs[reg]) |
| 111 | if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || | ||
| 112 | (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) | ||
| 113 | value &= ~WM8766_UPDATE; | ||
| 114 | wm8766_write(chip, reg, value); | 125 | wm8766_write(chip, reg, value); |
| 115 | } | ||
| 116 | } | 126 | } |
| 117 | 127 | ||
| 118 | static void wm8776_registers_init(struct oxygen *chip) | 128 | static void wm8776_registers_init(struct oxygen *chip) |
| @@ -141,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip) | |||
| 141 | 151 | ||
| 142 | static void wm8766_registers_init(struct oxygen *chip) | 152 | static void wm8766_registers_init(struct oxygen *chip) |
| 143 | { | 153 | { |
| 154 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 155 | |||
| 144 | wm8766_write(chip, WM8766_RESET, 0); | 156 | wm8766_write(chip, WM8766_RESET, 0); |
| 157 | wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]); | ||
| 145 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); | 158 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); |
| 146 | wm8766_write(chip, WM8766_DAC_CTRL2, | 159 | wm8766_write(chip, WM8766_DAC_CTRL2, |
| 147 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | 160 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); |
| @@ -170,6 +183,40 @@ static void wm8776_init(struct oxygen *chip) | |||
| 170 | wm8776_registers_init(chip); | 183 | wm8776_registers_init(chip); |
| 171 | } | 184 | } |
| 172 | 185 | ||
| 186 | static void wm8766_init(struct oxygen *chip) | ||
| 187 | { | ||
| 188 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 189 | |||
| 190 | data->wm8766_regs[WM8766_DAC_CTRL] = | ||
| 191 | WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; | ||
| 192 | wm8766_registers_init(chip); | ||
| 193 | } | ||
| 194 | |||
| 195 | static void xonar_ds_handle_hp_jack(struct oxygen *chip) | ||
| 196 | { | ||
| 197 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 198 | bool hp_plugged; | ||
| 199 | unsigned int reg; | ||
| 200 | |||
| 201 | mutex_lock(&chip->mutex); | ||
| 202 | |||
| 203 | hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
| 204 | GPIO_DS_HP_DETECT); | ||
| 205 | |||
| 206 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
| 207 | hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR, | ||
| 208 | GPIO_DS_OUTPUT_FRONTLR); | ||
| 209 | |||
| 210 | reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL; | ||
| 211 | if (hp_plugged) | ||
| 212 | reg |= WM8766_MUTEALL; | ||
| 213 | wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); | ||
| 214 | |||
| 215 | snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0); | ||
| 216 | |||
| 217 | mutex_unlock(&chip->mutex); | ||
| 218 | } | ||
| 219 | |||
| 173 | static void xonar_ds_init(struct oxygen *chip) | 220 | static void xonar_ds_init(struct oxygen *chip) |
| 174 | { | 221 | { |
| 175 | struct xonar_wm87x6 *data = chip->model_data; | 222 | struct xonar_wm87x6 *data = chip->model_data; |
| @@ -178,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip) | |||
| 178 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; | 225 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; |
| 179 | 226 | ||
| 180 | wm8776_init(chip); | 227 | wm8776_init(chip); |
| 181 | wm8766_registers_init(chip); | 228 | wm8766_init(chip); |
| 182 | 229 | ||
| 183 | oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, | 230 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
| 184 | GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); | 231 | GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR); |
| 232 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
| 233 | GPIO_DS_HP_DETECT); | ||
| 185 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); | 234 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); |
| 186 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); | 235 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); |
| 187 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | 236 | chip->interrupt_mask |= OXYGEN_INT_GPIO; |
| 188 | 237 | ||
| 189 | xonar_enable_output(chip); | 238 | xonar_enable_output(chip); |
| 190 | 239 | ||
| 240 | snd_jack_new(chip->card, "Headphone", | ||
| 241 | SND_JACK_HEADPHONE, &data->hp_jack); | ||
| 242 | xonar_ds_handle_hp_jack(chip); | ||
| 243 | |||
| 191 | snd_component_add(chip->card, "WM8776"); | 244 | snd_component_add(chip->card, "WM8776"); |
| 192 | snd_component_add(chip->card, "WM8766"); | 245 | snd_component_add(chip->card, "WM8766"); |
| 193 | } | 246 | } |
| @@ -208,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip) | |||
| 208 | wm8776_registers_init(chip); | 261 | wm8776_registers_init(chip); |
| 209 | wm8766_registers_init(chip); | 262 | wm8766_registers_init(chip); |
| 210 | xonar_enable_output(chip); | 263 | xonar_enable_output(chip); |
| 264 | xonar_ds_handle_hp_jack(chip); | ||
| 211 | } | 265 | } |
| 212 | 266 | ||
| 213 | static void wm8776_adc_hardware_filter(unsigned int channel, | 267 | static void wm8776_adc_hardware_filter(unsigned int channel, |
| @@ -323,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip) | |||
| 323 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | 377 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); |
| 324 | } | 378 | } |
| 325 | 379 | ||
| 326 | static void xonar_ds_gpio_changed(struct oxygen *chip) | 380 | static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed) |
| 327 | { | 381 | { |
| 328 | u16 bits; | 382 | struct xonar_wm87x6 *data = chip->model_data; |
| 383 | unsigned int reg; | ||
| 329 | 384 | ||
| 330 | bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | 385 | /* |
| 331 | snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); | 386 | * The WM8766 can mix left and right channels, but this setting |
| 387 | * applies to all three stereo pairs. | ||
| 388 | */ | ||
| 389 | reg = data->wm8766_regs[WM8766_DAC_CTRL] & | ||
| 390 | ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK); | ||
| 391 | if (mixed) | ||
| 392 | reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX; | ||
| 393 | else | ||
| 394 | reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; | ||
| 395 | wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); | ||
| 396 | } | ||
| 397 | |||
| 398 | static void xonar_ds_gpio_changed(struct oxygen *chip) | ||
| 399 | { | ||
| 400 | xonar_ds_handle_hp_jack(chip); | ||
| 332 | } | 401 | } |
| 333 | 402 | ||
| 334 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, | 403 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, |
| @@ -896,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = { | |||
| 896 | .put = wm8776_input_mux_put, | 965 | .put = wm8776_input_mux_put, |
| 897 | .private_value = 1 << 1, | 966 | .private_value = 1 << 1, |
| 898 | }, | 967 | }, |
| 899 | WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), | 968 | WM8776_BIT_SWITCH("Front Mic Capture Switch", |
| 969 | WM8776_ADCMUX, 1 << 2, 0, 0), | ||
| 970 | WM8776_BIT_SWITCH("Aux Capture Switch", | ||
| 971 | WM8776_ADCMUX, 1 << 3, 0, 0), | ||
| 900 | { | 972 | { |
| 901 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 973 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 902 | .name = "ADC Filter Capture Enum", | 974 | .name = "ADC Filter Capture Enum", |
| @@ -956,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = { | |||
| 956 | LC_CONTROL_ALC, wm8776_ngth_db_scale), | 1028 | LC_CONTROL_ALC, wm8776_ngth_db_scale), |
| 957 | }; | 1029 | }; |
| 958 | 1030 | ||
| 959 | static int xonar_ds_control_filter(struct snd_kcontrol_new *template) | ||
| 960 | { | ||
| 961 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
| 962 | return 1; /* no CD input */ | ||
| 963 | return 0; | ||
| 964 | } | ||
| 965 | |||
| 966 | static int xonar_ds_mixer_init(struct oxygen *chip) | 1031 | static int xonar_ds_mixer_init(struct oxygen *chip) |
| 967 | { | 1032 | { |
| 968 | struct xonar_wm87x6 *data = chip->model_data; | 1033 | struct xonar_wm87x6 *data = chip->model_data; |
| @@ -999,10 +1064,9 @@ static int xonar_ds_mixer_init(struct oxygen *chip) | |||
| 999 | 1064 | ||
| 1000 | static const struct oxygen_model model_xonar_ds = { | 1065 | static const struct oxygen_model model_xonar_ds = { |
| 1001 | .shortname = "Xonar DS", | 1066 | .shortname = "Xonar DS", |
| 1002 | .longname = "Asus Virtuoso 200", | 1067 | .longname = "Asus Virtuoso 66", |
| 1003 | .chip = "AV200", | 1068 | .chip = "AV200", |
| 1004 | .init = xonar_ds_init, | 1069 | .init = xonar_ds_init, |
| 1005 | .control_filter = xonar_ds_control_filter, | ||
| 1006 | .mixer_init = xonar_ds_mixer_init, | 1070 | .mixer_init = xonar_ds_mixer_init, |
| 1007 | .cleanup = xonar_ds_cleanup, | 1071 | .cleanup = xonar_ds_cleanup, |
| 1008 | .suspend = xonar_ds_suspend, | 1072 | .suspend = xonar_ds_suspend, |
| @@ -1013,6 +1077,7 @@ static const struct oxygen_model model_xonar_ds = { | |||
| 1013 | .set_adc_params = set_wm8776_adc_params, | 1077 | .set_adc_params = set_wm8776_adc_params, |
| 1014 | .update_dac_volume = update_wm87x6_volume, | 1078 | .update_dac_volume = update_wm87x6_volume, |
| 1015 | .update_dac_mute = update_wm87x6_mute, | 1079 | .update_dac_mute = update_wm87x6_mute, |
| 1080 | .update_center_lfe_mix = update_wm8766_center_lfe_mix, | ||
| 1016 | .gpio_changed = xonar_ds_gpio_changed, | 1081 | .gpio_changed = xonar_ds_gpio_changed, |
| 1017 | .dac_tlv = wm87x6_dac_db_scale, | 1082 | .dac_tlv = wm87x6_dac_db_scale, |
| 1018 | .model_data_size = sizeof(struct xonar_wm87x6), | 1083 | .model_data_size = sizeof(struct xonar_wm87x6), |
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index d19dc052c391..d5f5b440fc40 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
| @@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data) | |||
| 1527 | static void | 1527 | static void |
| 1528 | snd_rme96_free_spdif_pcm(struct snd_pcm *pcm) | 1528 | snd_rme96_free_spdif_pcm(struct snd_pcm *pcm) |
| 1529 | { | 1529 | { |
| 1530 | struct rme96 *rme96 = (struct rme96 *) pcm->private_data; | 1530 | struct rme96 *rme96 = pcm->private_data; |
| 1531 | rme96->spdif_pcm = NULL; | 1531 | rme96->spdif_pcm = NULL; |
| 1532 | } | 1532 | } |
| 1533 | 1533 | ||
| 1534 | static void | 1534 | static void |
| 1535 | snd_rme96_free_adat_pcm(struct snd_pcm *pcm) | 1535 | snd_rme96_free_adat_pcm(struct snd_pcm *pcm) |
| 1536 | { | 1536 | { |
| 1537 | struct rme96 *rme96 = (struct rme96 *) pcm->private_data; | 1537 | struct rme96 *rme96 = pcm->private_data; |
| 1538 | rme96->adat_pcm = NULL; | 1538 | rme96->adat_pcm = NULL; |
| 1539 | } | 1539 | } |
| 1540 | 1540 | ||
| @@ -1661,7 +1661,7 @@ static void | |||
| 1661 | snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 1661 | snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
| 1662 | { | 1662 | { |
| 1663 | int n; | 1663 | int n; |
| 1664 | struct rme96 *rme96 = (struct rme96 *)entry->private_data; | 1664 | struct rme96 *rme96 = entry->private_data; |
| 1665 | 1665 | ||
| 1666 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | 1666 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); |
| 1667 | 1667 | ||
| @@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci, | |||
| 2348 | if (err < 0) | 2348 | if (err < 0) |
| 2349 | return err; | 2349 | return err; |
| 2350 | card->private_free = snd_rme96_card_free; | 2350 | card->private_free = snd_rme96_card_free; |
| 2351 | rme96 = (struct rme96 *)card->private_data; | 2351 | rme96 = card->private_data; |
| 2352 | rme96->card = card; | 2352 | rme96->card = card; |
| 2353 | rme96->pci = pci; | 2353 | rme96->pci = pci; |
| 2354 | snd_card_set_dev(card, &pci->dev); | 2354 | snd_card_set_dev(card, &pci->dev); |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index d6fa7bfd9aa1..0b720cf7783e 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
| @@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) | |||
| 3284 | static void | 3284 | static void |
| 3285 | snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 3285 | snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
| 3286 | { | 3286 | { |
| 3287 | struct hdsp *hdsp = (struct hdsp *) entry->private_data; | 3287 | struct hdsp *hdsp = entry->private_data; |
| 3288 | unsigned int status; | 3288 | unsigned int status; |
| 3289 | unsigned int status2; | 3289 | unsigned int status2; |
| 3290 | char *pref_sync_ref; | 3290 | char *pref_sync_ref; |
| @@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm | |||
| 4566 | 4566 | ||
| 4567 | static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) | 4567 | static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) |
| 4568 | { | 4568 | { |
| 4569 | struct hdsp *hdsp = (struct hdsp *)hw->private_data; | 4569 | struct hdsp *hdsp = hw->private_data; |
| 4570 | void __user *argp = (void __user *)arg; | 4570 | void __user *argp = (void __user *)arg; |
| 4571 | int err; | 4571 | int err; |
| 4572 | 4572 | ||
| @@ -5156,7 +5156,7 @@ static int snd_hdsp_free(struct hdsp *hdsp) | |||
| 5156 | 5156 | ||
| 5157 | static void snd_hdsp_card_free(struct snd_card *card) | 5157 | static void snd_hdsp_card_free(struct snd_card *card) |
| 5158 | { | 5158 | { |
| 5159 | struct hdsp *hdsp = (struct hdsp *) card->private_data; | 5159 | struct hdsp *hdsp = card->private_data; |
| 5160 | 5160 | ||
| 5161 | if (hdsp) | 5161 | if (hdsp) |
| 5162 | snd_hdsp_free(hdsp); | 5162 | snd_hdsp_free(hdsp); |
| @@ -5182,7 +5182,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci, | |||
| 5182 | if (err < 0) | 5182 | if (err < 0) |
| 5183 | return err; | 5183 | return err; |
| 5184 | 5184 | ||
| 5185 | hdsp = (struct hdsp *) card->private_data; | 5185 | hdsp = card->private_data; |
| 5186 | card->private_free = snd_hdsp_card_free; | 5186 | card->private_free = snd_hdsp_card_free; |
| 5187 | hdsp->dev = dev; | 5187 | hdsp->dev = dev; |
| 5188 | hdsp->pci = pci; | 5188 | hdsp->pci = pci; |
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 20afdf9772ee..961d98297695 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c | |||
| @@ -785,7 +785,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix) | |||
| 785 | if (! mix->i2c.client) | 785 | if (! mix->i2c.client) |
| 786 | return -ENODEV; | 786 | return -ENODEV; |
| 787 | if (mix->capture_source) | 787 | if (mix->capture_source) |
| 788 | mix->acs = mix->acs |= 2; | 788 | mix->acs |= 2; |
| 789 | else | 789 | else |
| 790 | mix->acs &= ~2; | 790 | mix->acs &= ~2; |
| 791 | return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs); | 791 | return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs); |
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 40eccfe9e358..4948a79f86a0 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c | |||
| @@ -150,7 +150,7 @@ static int __init sffsdr_init(void) | |||
| 150 | sffsdr_snd_resources, | 150 | sffsdr_snd_resources, |
| 151 | ARRAY_SIZE(sffsdr_snd_resources)); | 151 | ARRAY_SIZE(sffsdr_snd_resources)); |
| 152 | if (ret) { | 152 | if (ret) { |
| 153 | printk(KERN_ERR "platform device add ressources failed\n"); | 153 | printk(KERN_ERR "platform device add resources failed\n"); |
| 154 | goto error; | 154 | goto error; |
| 155 | } | 155 | } |
| 156 | 156 | ||
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 209c25994c7e..4719558289d4 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c | |||
| @@ -182,7 +182,7 @@ static int neo1973_gta02_voice_hw_params( | |||
| 182 | if (ret < 0) | 182 | if (ret < 0) |
| 183 | return ret; | 183 | return ret; |
| 184 | 184 | ||
| 185 | /* configue and enable PLL for 12.288MHz output */ | 185 | /* configure and enable PLL for 12.288MHz output */ |
| 186 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, | 186 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, |
| 187 | iis_clkrate / 4, 12288000); | 187 | iis_clkrate / 4, 12288000); |
| 188 | if (ret < 0) | 188 | if (ret < 0) |
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 0cb4f86f6d1e..4ac620988e7c 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
| @@ -201,7 +201,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
| 201 | if (ret < 0) | 201 | if (ret < 0) |
| 202 | return ret; | 202 | return ret; |
| 203 | 203 | ||
| 204 | /* configue and enable PLL for 12.288MHz output */ | 204 | /* configure and enable PLL for 12.288MHz output */ |
| 205 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, | 205 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, |
| 206 | iis_clkrate / 4, 12288000); | 206 | iis_clkrate / 4, 12288000); |
| 207 | if (ret < 0) | 207 | if (ret < 0) |
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index ff0b2a8fd25b..5ae1eae9f6db 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c | |||
| @@ -128,6 +128,9 @@ snd_emux_init_hwdep(struct snd_emux *emu) | |||
| 128 | strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); | 128 | strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); |
| 129 | hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; | 129 | hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; |
| 130 | hw->ops.ioctl = snd_emux_hwdep_ioctl; | 130 | hw->ops.ioctl = snd_emux_hwdep_ioctl; |
| 131 | /* The ioctl parameter types are compatible between 32- and | ||
| 132 | * 64-bit architectures, so use the same function. */ | ||
| 133 | hw->ops.ioctl_compat = snd_emux_hwdep_ioctl; | ||
| 131 | hw->exclusive = 1; | 134 | hw->exclusive = 1; |
| 132 | hw->private_data = emu; | 135 | hw->private_data = emu; |
| 133 | if ((err = snd_card_register(emu->card)) < 0) | 136 | if ((err = snd_card_register(emu->card)) < 0) |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 44d6d2ec964f..112984f4080f 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
| @@ -65,6 +65,7 @@ config SND_USB_CAIAQ | |||
| 65 | * Native Instruments Guitar Rig Session I/O | 65 | * Native Instruments Guitar Rig Session I/O |
| 66 | * Native Instruments Guitar Rig mobile | 66 | * Native Instruments Guitar Rig mobile |
| 67 | * Native Instruments Traktor Kontrol X1 | 67 | * Native Instruments Traktor Kontrol X1 |
| 68 | * Native Instruments Traktor Kontrol S4 | ||
| 68 | 69 | ||
| 69 | To compile this driver as a module, choose M here: the module | 70 | To compile this driver as a module, choose M here: the module |
| 70 | will be called snd-usb-caiaq. | 71 | will be called snd-usb-caiaq. |
| @@ -82,6 +83,7 @@ config SND_USB_CAIAQ_INPUT | |||
| 82 | * Native Instruments Kore Controller | 83 | * Native Instruments Kore Controller |
| 83 | * Native Instruments Kore Controller 2 | 84 | * Native Instruments Kore Controller 2 |
| 84 | * Native Instruments Audio Kontrol 1 | 85 | * Native Instruments Audio Kontrol 1 |
| 86 | * Native Instruments Traktor Kontrol S4 | ||
| 85 | 87 | ||
| 86 | config SND_USB_US122L | 88 | config SND_USB_US122L |
| 87 | tristate "Tascam US-122L USB driver" | 89 | tristate "Tascam US-122L USB driver" |
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 4328cad6c3a2..68b97477577b 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c | |||
| @@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev) | |||
| 111 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); | 111 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); |
| 112 | dev->input_panic = 0; | 112 | dev->input_panic = 0; |
| 113 | dev->output_panic = 0; | 113 | dev->output_panic = 0; |
| 114 | dev->first_packet = 1; | 114 | dev->first_packet = 4; |
| 115 | dev->streaming = 1; | 115 | dev->streaming = 1; |
| 116 | dev->warned = 0; | 116 | dev->warned = 0; |
| 117 | 117 | ||
| @@ -169,7 +169,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) | |||
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, | 171 | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, |
| 172 | struct snd_pcm_hw_params *hw_params) | 172 | struct snd_pcm_hw_params *hw_params) |
| 173 | { | 173 | { |
| 174 | debug("%s(%p)\n", __func__, sub); | 174 | debug("%s(%p)\n", __func__, sub); |
| 175 | return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); | 175 | return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); |
| @@ -189,7 +189,7 @@ static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) | |||
| 189 | #endif | 189 | #endif |
| 190 | 190 | ||
| 191 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, | 191 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, |
| 192 | 48000, 64000, 88200, 96000, 176400, 192000 }; | 192 | 48000, 64000, 88200, 96000, 176400, 192000 }; |
| 193 | 193 | ||
| 194 | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | 194 | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) |
| 195 | { | 195 | { |
| @@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 201 | debug("%s(%p)\n", __func__, substream); | 201 | debug("%s(%p)\n", __func__, substream); |
| 202 | 202 | ||
| 203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 204 | dev->period_out_count[index] = BYTES_PER_SAMPLE + 1; | 204 | int out_pos; |
| 205 | dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; | 205 | |
| 206 | switch (dev->spec.data_alignment) { | ||
| 207 | case 0: | ||
| 208 | case 2: | ||
| 209 | out_pos = BYTES_PER_SAMPLE + 1; | ||
| 210 | break; | ||
| 211 | case 3: | ||
| 212 | default: | ||
| 213 | out_pos = 0; | ||
| 214 | break; | ||
| 215 | } | ||
| 216 | |||
| 217 | dev->period_out_count[index] = out_pos; | ||
| 218 | dev->audio_out_buf_pos[index] = out_pos; | ||
| 206 | } else { | 219 | } else { |
| 207 | int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2; | 220 | int in_pos; |
| 208 | dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos; | 221 | |
| 209 | dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos; | 222 | switch (dev->spec.data_alignment) { |
| 223 | case 0: | ||
| 224 | in_pos = BYTES_PER_SAMPLE + 2; | ||
| 225 | break; | ||
| 226 | case 2: | ||
| 227 | in_pos = BYTES_PER_SAMPLE; | ||
| 228 | break; | ||
| 229 | case 3: | ||
| 230 | default: | ||
| 231 | in_pos = 0; | ||
| 232 | break; | ||
| 233 | } | ||
| 234 | |||
| 235 | dev->period_in_count[index] = in_pos; | ||
| 236 | dev->audio_in_buf_pos[index] = in_pos; | ||
| 210 | } | 237 | } |
| 211 | 238 | ||
| 212 | if (dev->streaming) | 239 | if (dev->streaming) |
| @@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 221 | snd_pcm_limit_hw_rates(runtime); | 248 | snd_pcm_limit_hw_rates(runtime); |
| 222 | 249 | ||
| 223 | bytes_per_sample = BYTES_PER_SAMPLE; | 250 | bytes_per_sample = BYTES_PER_SAMPLE; |
| 224 | if (dev->spec.data_alignment == 2) | 251 | if (dev->spec.data_alignment >= 2) |
| 225 | bytes_per_sample++; | 252 | bytes_per_sample++; |
| 226 | 253 | ||
| 227 | bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) | 254 | bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) |
| @@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd) | |||
| 253 | { | 280 | { |
| 254 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | 281 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); |
| 255 | 282 | ||
| 283 | debug("%s(%p) cmd %d\n", __func__, sub, cmd); | ||
| 284 | |||
| 256 | switch (cmd) { | 285 | switch (cmd) { |
| 257 | case SNDRV_PCM_TRIGGER_START: | 286 | case SNDRV_PCM_TRIGGER_START: |
| 258 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 287 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
| @@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, | |||
| 402 | } | 431 | } |
| 403 | } | 432 | } |
| 404 | 433 | ||
| 434 | static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev, | ||
| 435 | const struct urb *urb, | ||
| 436 | const struct usb_iso_packet_descriptor *iso) | ||
| 437 | { | ||
| 438 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | ||
| 439 | int stream, i; | ||
| 440 | |||
| 441 | /* paranoia check */ | ||
| 442 | if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM)) | ||
| 443 | return; | ||
| 444 | |||
| 445 | for (i = 0; i < iso->actual_length;) { | ||
| 446 | for (stream = 0; stream < dev->n_streams; stream++) { | ||
| 447 | struct snd_pcm_substream *sub = dev->sub_capture[stream]; | ||
| 448 | char *audio_buf = NULL; | ||
| 449 | int c, n, sz = 0; | ||
| 450 | |||
| 451 | if (sub && !dev->input_panic) { | ||
| 452 | struct snd_pcm_runtime *rt = sub->runtime; | ||
| 453 | audio_buf = rt->dma_area; | ||
| 454 | sz = frames_to_bytes(rt, rt->buffer_size); | ||
| 455 | } | ||
| 456 | |||
| 457 | for (c = 0; c < CHANNELS_PER_STREAM; c++) { | ||
| 458 | /* 3 audio data bytes, followed by 1 check byte */ | ||
| 459 | if (audio_buf) { | ||
| 460 | for (n = 0; n < BYTES_PER_SAMPLE; n++) { | ||
| 461 | audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n]; | ||
| 462 | |||
| 463 | if (dev->audio_in_buf_pos[stream] == sz) | ||
| 464 | dev->audio_in_buf_pos[stream] = 0; | ||
| 465 | } | ||
| 466 | |||
| 467 | dev->period_in_count[stream] += BYTES_PER_SAMPLE; | ||
| 468 | } | ||
| 469 | |||
| 470 | i += BYTES_PER_SAMPLE; | ||
| 471 | |||
| 472 | if (usb_buf[i] != ((stream << 1) | c) && | ||
| 473 | !dev->first_packet) { | ||
| 474 | if (!dev->input_panic) | ||
| 475 | printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n", | ||
| 476 | ((stream << 1) | c), usb_buf[i], c, stream, i); | ||
| 477 | dev->input_panic = 1; | ||
| 478 | } | ||
| 479 | |||
| 480 | i++; | ||
| 481 | } | ||
| 482 | } | ||
| 483 | } | ||
| 484 | |||
| 485 | if (dev->first_packet > 0) | ||
| 486 | dev->first_packet--; | ||
| 487 | } | ||
| 488 | |||
| 405 | static void read_in_urb(struct snd_usb_caiaqdev *dev, | 489 | static void read_in_urb(struct snd_usb_caiaqdev *dev, |
| 406 | const struct urb *urb, | 490 | const struct urb *urb, |
| 407 | const struct usb_iso_packet_descriptor *iso) | 491 | const struct usb_iso_packet_descriptor *iso) |
| @@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, | |||
| 419 | case 2: | 503 | case 2: |
| 420 | read_in_urb_mode2(dev, urb, iso); | 504 | read_in_urb_mode2(dev, urb, iso); |
| 421 | break; | 505 | break; |
| 506 | case 3: | ||
| 507 | read_in_urb_mode3(dev, urb, iso); | ||
| 508 | break; | ||
| 422 | } | 509 | } |
| 423 | 510 | ||
| 424 | if ((dev->input_panic || dev->output_panic) && !dev->warned) { | 511 | if ((dev->input_panic || dev->output_panic) && !dev->warned) { |
| @@ -429,9 +516,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, | |||
| 429 | } | 516 | } |
| 430 | } | 517 | } |
| 431 | 518 | ||
| 432 | static void fill_out_urb(struct snd_usb_caiaqdev *dev, | 519 | static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev, |
| 433 | struct urb *urb, | 520 | struct urb *urb, |
| 434 | const struct usb_iso_packet_descriptor *iso) | 521 | const struct usb_iso_packet_descriptor *iso) |
| 435 | { | 522 | { |
| 436 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 523 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; |
| 437 | struct snd_pcm_substream *sub; | 524 | struct snd_pcm_substream *sub; |
| @@ -457,9 +544,67 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, | |||
| 457 | /* fill in the check bytes */ | 544 | /* fill in the check bytes */ |
| 458 | if (dev->spec.data_alignment == 2 && | 545 | if (dev->spec.data_alignment == 2 && |
| 459 | i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == | 546 | i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == |
| 460 | (dev->n_streams * CHANNELS_PER_STREAM)) | 547 | (dev->n_streams * CHANNELS_PER_STREAM)) |
| 461 | for (stream = 0; stream < dev->n_streams; stream++, i++) | 548 | for (stream = 0; stream < dev->n_streams; stream++, i++) |
| 462 | usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); | 549 | usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); |
| 550 | } | ||
| 551 | } | ||
| 552 | |||
| 553 | static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev, | ||
| 554 | struct urb *urb, | ||
| 555 | const struct usb_iso_packet_descriptor *iso) | ||
| 556 | { | ||
| 557 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | ||
| 558 | int stream, i; | ||
| 559 | |||
| 560 | for (i = 0; i < iso->length;) { | ||
| 561 | for (stream = 0; stream < dev->n_streams; stream++) { | ||
| 562 | struct snd_pcm_substream *sub = dev->sub_playback[stream]; | ||
| 563 | char *audio_buf = NULL; | ||
| 564 | int c, n, sz = 0; | ||
| 565 | |||
| 566 | if (sub) { | ||
| 567 | struct snd_pcm_runtime *rt = sub->runtime; | ||
| 568 | audio_buf = rt->dma_area; | ||
| 569 | sz = frames_to_bytes(rt, rt->buffer_size); | ||
| 570 | } | ||
| 571 | |||
| 572 | for (c = 0; c < CHANNELS_PER_STREAM; c++) { | ||
| 573 | for (n = 0; n < BYTES_PER_SAMPLE; n++) { | ||
| 574 | if (audio_buf) { | ||
| 575 | usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++]; | ||
| 576 | |||
| 577 | if (dev->audio_out_buf_pos[stream] == sz) | ||
| 578 | dev->audio_out_buf_pos[stream] = 0; | ||
| 579 | } else { | ||
| 580 | usb_buf[i+n] = 0; | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | if (audio_buf) | ||
| 585 | dev->period_out_count[stream] += BYTES_PER_SAMPLE; | ||
| 586 | |||
| 587 | i += BYTES_PER_SAMPLE; | ||
| 588 | |||
| 589 | /* fill in the check byte pattern */ | ||
| 590 | usb_buf[i++] = (stream << 1) | c; | ||
| 591 | } | ||
| 592 | } | ||
| 593 | } | ||
| 594 | } | ||
| 595 | |||
| 596 | static inline void fill_out_urb(struct snd_usb_caiaqdev *dev, | ||
| 597 | struct urb *urb, | ||
| 598 | const struct usb_iso_packet_descriptor *iso) | ||
| 599 | { | ||
| 600 | switch (dev->spec.data_alignment) { | ||
| 601 | case 0: | ||
| 602 | case 2: | ||
| 603 | fill_out_urb_mode_0(dev, urb, iso); | ||
| 604 | break; | ||
| 605 | case 3: | ||
| 606 | fill_out_urb_mode_3(dev, urb, iso); | ||
| 607 | break; | ||
| 463 | } | 608 | } |
| 464 | } | 609 | } |
| 465 | 610 | ||
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index 91c804cd2782..00e5d0a469e1 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c | |||
| @@ -55,6 +55,10 @@ static int control_info(struct snd_kcontrol *kcontrol, | |||
| 55 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 55 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
| 56 | maxval = 127; | 56 | maxval = 127; |
| 57 | break; | 57 | break; |
| 58 | |||
| 59 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
| 60 | maxval = 31; | ||
| 61 | break; | ||
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | if (is_intval) { | 64 | if (is_intval) { |
| @@ -93,6 +97,7 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
| 93 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); | 97 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); |
| 94 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); | 98 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); |
| 95 | int pos = kcontrol->private_value; | 99 | int pos = kcontrol->private_value; |
| 100 | int v = ucontrol->value.integer.value[0]; | ||
| 96 | unsigned char cmd = EP1_CMD_WRITE_IO; | 101 | unsigned char cmd = EP1_CMD_WRITE_IO; |
| 97 | 102 | ||
| 98 | if (dev->chip.usb_id == | 103 | if (dev->chip.usb_id == |
| @@ -100,12 +105,27 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
| 100 | cmd = EP1_CMD_DIMM_LEDS; | 105 | cmd = EP1_CMD_DIMM_LEDS; |
| 101 | 106 | ||
| 102 | if (pos & CNT_INTVAL) { | 107 | if (pos & CNT_INTVAL) { |
| 103 | dev->control_state[pos & ~CNT_INTVAL] | 108 | int i = pos & ~CNT_INTVAL; |
| 104 | = ucontrol->value.integer.value[0]; | 109 | |
| 105 | snd_usb_caiaq_send_command(dev, cmd, | 110 | dev->control_state[i] = v; |
| 106 | dev->control_state, sizeof(dev->control_state)); | 111 | |
| 112 | if (dev->chip.usb_id == | ||
| 113 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) { | ||
| 114 | int actual_len; | ||
| 115 | |||
| 116 | dev->ep8_out_buf[0] = i; | ||
| 117 | dev->ep8_out_buf[1] = v; | ||
| 118 | |||
| 119 | usb_bulk_msg(dev->chip.dev, | ||
| 120 | usb_sndbulkpipe(dev->chip.dev, 8), | ||
| 121 | dev->ep8_out_buf, sizeof(dev->ep8_out_buf), | ||
| 122 | &actual_len, 200); | ||
| 123 | } else { | ||
| 124 | snd_usb_caiaq_send_command(dev, cmd, | ||
| 125 | dev->control_state, sizeof(dev->control_state)); | ||
| 126 | } | ||
| 107 | } else { | 127 | } else { |
| 108 | if (ucontrol->value.integer.value[0]) | 128 | if (v) |
| 109 | dev->control_state[pos / 8] |= 1 << (pos % 8); | 129 | dev->control_state[pos / 8] |= 1 << (pos % 8); |
| 110 | else | 130 | else |
| 111 | dev->control_state[pos / 8] &= ~(1 << (pos % 8)); | 131 | dev->control_state[pos / 8] &= ~(1 << (pos % 8)); |
| @@ -296,6 +316,179 @@ static struct caiaq_controller kontrolx1_controller[] = { | |||
| 296 | { "LED Deck B: SYNC", 8 | CNT_INTVAL }, | 316 | { "LED Deck B: SYNC", 8 | CNT_INTVAL }, |
| 297 | }; | 317 | }; |
| 298 | 318 | ||
| 319 | static struct caiaq_controller kontrols4_controller[] = { | ||
| 320 | { "LED: Master: Quant", 10 | CNT_INTVAL }, | ||
| 321 | { "LED: Master: Headphone", 11 | CNT_INTVAL }, | ||
| 322 | { "LED: Master: Master", 12 | CNT_INTVAL }, | ||
| 323 | { "LED: Master: Snap", 14 | CNT_INTVAL }, | ||
| 324 | { "LED: Master: Warning", 15 | CNT_INTVAL }, | ||
| 325 | { "LED: Master: Master button", 112 | CNT_INTVAL }, | ||
| 326 | { "LED: Master: Snap button", 113 | CNT_INTVAL }, | ||
| 327 | { "LED: Master: Rec", 118 | CNT_INTVAL }, | ||
| 328 | { "LED: Master: Size", 119 | CNT_INTVAL }, | ||
| 329 | { "LED: Master: Quant button", 120 | CNT_INTVAL }, | ||
| 330 | { "LED: Master: Browser button", 121 | CNT_INTVAL }, | ||
| 331 | { "LED: Master: Play button", 126 | CNT_INTVAL }, | ||
| 332 | { "LED: Master: Undo button", 127 | CNT_INTVAL }, | ||
| 333 | |||
| 334 | { "LED: Channel A: >", 4 | CNT_INTVAL }, | ||
| 335 | { "LED: Channel A: <", 5 | CNT_INTVAL }, | ||
| 336 | { "LED: Channel A: Meter 1", 97 | CNT_INTVAL }, | ||
| 337 | { "LED: Channel A: Meter 2", 98 | CNT_INTVAL }, | ||
| 338 | { "LED: Channel A: Meter 3", 99 | CNT_INTVAL }, | ||
| 339 | { "LED: Channel A: Meter 4", 100 | CNT_INTVAL }, | ||
| 340 | { "LED: Channel A: Meter 5", 101 | CNT_INTVAL }, | ||
| 341 | { "LED: Channel A: Meter 6", 102 | CNT_INTVAL }, | ||
| 342 | { "LED: Channel A: Meter clip", 103 | CNT_INTVAL }, | ||
| 343 | { "LED: Channel A: Active", 114 | CNT_INTVAL }, | ||
| 344 | { "LED: Channel A: Cue", 116 | CNT_INTVAL }, | ||
| 345 | { "LED: Channel A: FX1", 149 | CNT_INTVAL }, | ||
| 346 | { "LED: Channel A: FX2", 148 | CNT_INTVAL }, | ||
| 347 | |||
| 348 | { "LED: Channel B: >", 2 | CNT_INTVAL }, | ||
| 349 | { "LED: Channel B: <", 3 | CNT_INTVAL }, | ||
| 350 | { "LED: Channel B: Meter 1", 89 | CNT_INTVAL }, | ||
| 351 | { "LED: Channel B: Meter 2", 90 | CNT_INTVAL }, | ||
| 352 | { "LED: Channel B: Meter 3", 91 | CNT_INTVAL }, | ||
| 353 | { "LED: Channel B: Meter 4", 92 | CNT_INTVAL }, | ||
| 354 | { "LED: Channel B: Meter 5", 93 | CNT_INTVAL }, | ||
| 355 | { "LED: Channel B: Meter 6", 94 | CNT_INTVAL }, | ||
| 356 | { "LED: Channel B: Meter clip", 95 | CNT_INTVAL }, | ||
| 357 | { "LED: Channel B: Active", 122 | CNT_INTVAL }, | ||
| 358 | { "LED: Channel B: Cue", 125 | CNT_INTVAL }, | ||
| 359 | { "LED: Channel B: FX1", 147 | CNT_INTVAL }, | ||
| 360 | { "LED: Channel B: FX2", 146 | CNT_INTVAL }, | ||
| 361 | |||
| 362 | { "LED: Channel C: >", 6 | CNT_INTVAL }, | ||
| 363 | { "LED: Channel C: <", 7 | CNT_INTVAL }, | ||
| 364 | { "LED: Channel C: Meter 1", 105 | CNT_INTVAL }, | ||
| 365 | { "LED: Channel C: Meter 2", 106 | CNT_INTVAL }, | ||
| 366 | { "LED: Channel C: Meter 3", 107 | CNT_INTVAL }, | ||
| 367 | { "LED: Channel C: Meter 4", 108 | CNT_INTVAL }, | ||
| 368 | { "LED: Channel C: Meter 5", 109 | CNT_INTVAL }, | ||
| 369 | { "LED: Channel C: Meter 6", 110 | CNT_INTVAL }, | ||
| 370 | { "LED: Channel C: Meter clip", 111 | CNT_INTVAL }, | ||
| 371 | { "LED: Channel C: Active", 115 | CNT_INTVAL }, | ||
| 372 | { "LED: Channel C: Cue", 117 | CNT_INTVAL }, | ||
| 373 | { "LED: Channel C: FX1", 151 | CNT_INTVAL }, | ||
| 374 | { "LED: Channel C: FX2", 150 | CNT_INTVAL }, | ||
| 375 | |||
| 376 | { "LED: Channel D: >", 0 | CNT_INTVAL }, | ||
| 377 | { "LED: Channel D: <", 1 | CNT_INTVAL }, | ||
| 378 | { "LED: Channel D: Meter 1", 81 | CNT_INTVAL }, | ||
| 379 | { "LED: Channel D: Meter 2", 82 | CNT_INTVAL }, | ||
| 380 | { "LED: Channel D: Meter 3", 83 | CNT_INTVAL }, | ||
| 381 | { "LED: Channel D: Meter 4", 84 | CNT_INTVAL }, | ||
| 382 | { "LED: Channel D: Meter 5", 85 | CNT_INTVAL }, | ||
| 383 | { "LED: Channel D: Meter 6", 86 | CNT_INTVAL }, | ||
| 384 | { "LED: Channel D: Meter clip", 87 | CNT_INTVAL }, | ||
| 385 | { "LED: Channel D: Active", 123 | CNT_INTVAL }, | ||
| 386 | { "LED: Channel D: Cue", 124 | CNT_INTVAL }, | ||
| 387 | { "LED: Channel D: FX1", 145 | CNT_INTVAL }, | ||
| 388 | { "LED: Channel D: FX2", 144 | CNT_INTVAL }, | ||
| 389 | |||
| 390 | { "LED: Deck A: 1 (blue)", 22 | CNT_INTVAL }, | ||
| 391 | { "LED: Deck A: 1 (green)", 23 | CNT_INTVAL }, | ||
| 392 | { "LED: Deck A: 2 (blue)", 20 | CNT_INTVAL }, | ||
| 393 | { "LED: Deck A: 2 (green)", 21 | CNT_INTVAL }, | ||
| 394 | { "LED: Deck A: 3 (blue)", 18 | CNT_INTVAL }, | ||
| 395 | { "LED: Deck A: 3 (green)", 19 | CNT_INTVAL }, | ||
| 396 | { "LED: Deck A: 4 (blue)", 16 | CNT_INTVAL }, | ||
| 397 | { "LED: Deck A: 4 (green)", 17 | CNT_INTVAL }, | ||
| 398 | { "LED: Deck A: Load", 44 | CNT_INTVAL }, | ||
| 399 | { "LED: Deck A: Deck C button", 45 | CNT_INTVAL }, | ||
| 400 | { "LED: Deck A: In", 47 | CNT_INTVAL }, | ||
| 401 | { "LED: Deck A: Out", 46 | CNT_INTVAL }, | ||
| 402 | { "LED: Deck A: Shift", 24 | CNT_INTVAL }, | ||
| 403 | { "LED: Deck A: Sync", 27 | CNT_INTVAL }, | ||
| 404 | { "LED: Deck A: Cue", 26 | CNT_INTVAL }, | ||
| 405 | { "LED: Deck A: Play", 25 | CNT_INTVAL }, | ||
| 406 | { "LED: Deck A: Tempo up", 33 | CNT_INTVAL }, | ||
| 407 | { "LED: Deck A: Tempo down", 32 | CNT_INTVAL }, | ||
| 408 | { "LED: Deck A: Master", 34 | CNT_INTVAL }, | ||
| 409 | { "LED: Deck A: Keylock", 35 | CNT_INTVAL }, | ||
| 410 | { "LED: Deck A: Deck A", 37 | CNT_INTVAL }, | ||
| 411 | { "LED: Deck A: Deck C", 36 | CNT_INTVAL }, | ||
| 412 | { "LED: Deck A: Samples", 38 | CNT_INTVAL }, | ||
| 413 | { "LED: Deck A: On Air", 39 | CNT_INTVAL }, | ||
| 414 | { "LED: Deck A: Sample 1", 31 | CNT_INTVAL }, | ||
| 415 | { "LED: Deck A: Sample 2", 30 | CNT_INTVAL }, | ||
| 416 | { "LED: Deck A: Sample 3", 29 | CNT_INTVAL }, | ||
| 417 | { "LED: Deck A: Sample 4", 28 | CNT_INTVAL }, | ||
| 418 | { "LED: Deck A: Digit 1 - A", 55 | CNT_INTVAL }, | ||
| 419 | { "LED: Deck A: Digit 1 - B", 54 | CNT_INTVAL }, | ||
| 420 | { "LED: Deck A: Digit 1 - C", 53 | CNT_INTVAL }, | ||
| 421 | { "LED: Deck A: Digit 1 - D", 52 | CNT_INTVAL }, | ||
| 422 | { "LED: Deck A: Digit 1 - E", 51 | CNT_INTVAL }, | ||
| 423 | { "LED: Deck A: Digit 1 - F", 50 | CNT_INTVAL }, | ||
| 424 | { "LED: Deck A: Digit 1 - G", 49 | CNT_INTVAL }, | ||
| 425 | { "LED: Deck A: Digit 1 - dot", 48 | CNT_INTVAL }, | ||
| 426 | { "LED: Deck A: Digit 2 - A", 63 | CNT_INTVAL }, | ||
| 427 | { "LED: Deck A: Digit 2 - B", 62 | CNT_INTVAL }, | ||
| 428 | { "LED: Deck A: Digit 2 - C", 61 | CNT_INTVAL }, | ||
| 429 | { "LED: Deck A: Digit 2 - D", 60 | CNT_INTVAL }, | ||
| 430 | { "LED: Deck A: Digit 2 - E", 59 | CNT_INTVAL }, | ||
| 431 | { "LED: Deck A: Digit 2 - F", 58 | CNT_INTVAL }, | ||
| 432 | { "LED: Deck A: Digit 2 - G", 57 | CNT_INTVAL }, | ||
| 433 | { "LED: Deck A: Digit 2 - dot", 56 | CNT_INTVAL }, | ||
| 434 | |||
| 435 | { "LED: Deck B: 1 (blue)", 78 | CNT_INTVAL }, | ||
| 436 | { "LED: Deck B: 1 (green)", 79 | CNT_INTVAL }, | ||
| 437 | { "LED: Deck B: 2 (blue)", 76 | CNT_INTVAL }, | ||
| 438 | { "LED: Deck B: 2 (green)", 77 | CNT_INTVAL }, | ||
| 439 | { "LED: Deck B: 3 (blue)", 74 | CNT_INTVAL }, | ||
| 440 | { "LED: Deck B: 3 (green)", 75 | CNT_INTVAL }, | ||
| 441 | { "LED: Deck B: 4 (blue)", 72 | CNT_INTVAL }, | ||
| 442 | { "LED: Deck B: 4 (green)", 73 | CNT_INTVAL }, | ||
| 443 | { "LED: Deck B: Load", 180 | CNT_INTVAL }, | ||
| 444 | { "LED: Deck B: Deck D button", 181 | CNT_INTVAL }, | ||
| 445 | { "LED: Deck B: In", 183 | CNT_INTVAL }, | ||
| 446 | { "LED: Deck B: Out", 182 | CNT_INTVAL }, | ||
| 447 | { "LED: Deck B: Shift", 64 | CNT_INTVAL }, | ||
| 448 | { "LED: Deck B: Sync", 67 | CNT_INTVAL }, | ||
| 449 | { "LED: Deck B: Cue", 66 | CNT_INTVAL }, | ||
| 450 | { "LED: Deck B: Play", 65 | CNT_INTVAL }, | ||
| 451 | { "LED: Deck B: Tempo up", 185 | CNT_INTVAL }, | ||
| 452 | { "LED: Deck B: Tempo down", 184 | CNT_INTVAL }, | ||
| 453 | { "LED: Deck B: Master", 186 | CNT_INTVAL }, | ||
| 454 | { "LED: Deck B: Keylock", 187 | CNT_INTVAL }, | ||
| 455 | { "LED: Deck B: Deck B", 189 | CNT_INTVAL }, | ||
| 456 | { "LED: Deck B: Deck D", 188 | CNT_INTVAL }, | ||
| 457 | { "LED: Deck B: Samples", 190 | CNT_INTVAL }, | ||
| 458 | { "LED: Deck B: On Air", 191 | CNT_INTVAL }, | ||
| 459 | { "LED: Deck B: Sample 1", 71 | CNT_INTVAL }, | ||
| 460 | { "LED: Deck B: Sample 2", 70 | CNT_INTVAL }, | ||
| 461 | { "LED: Deck B: Sample 3", 69 | CNT_INTVAL }, | ||
| 462 | { "LED: Deck B: Sample 4", 68 | CNT_INTVAL }, | ||
| 463 | { "LED: Deck B: Digit 1 - A", 175 | CNT_INTVAL }, | ||
| 464 | { "LED: Deck B: Digit 1 - B", 174 | CNT_INTVAL }, | ||
| 465 | { "LED: Deck B: Digit 1 - C", 173 | CNT_INTVAL }, | ||
| 466 | { "LED: Deck B: Digit 1 - D", 172 | CNT_INTVAL }, | ||
| 467 | { "LED: Deck B: Digit 1 - E", 171 | CNT_INTVAL }, | ||
| 468 | { "LED: Deck B: Digit 1 - F", 170 | CNT_INTVAL }, | ||
| 469 | { "LED: Deck B: Digit 1 - G", 169 | CNT_INTVAL }, | ||
| 470 | { "LED: Deck B: Digit 1 - dot", 168 | CNT_INTVAL }, | ||
| 471 | { "LED: Deck B: Digit 2 - A", 167 | CNT_INTVAL }, | ||
| 472 | { "LED: Deck B: Digit 2 - B", 166 | CNT_INTVAL }, | ||
| 473 | { "LED: Deck B: Digit 2 - C", 165 | CNT_INTVAL }, | ||
| 474 | { "LED: Deck B: Digit 2 - D", 164 | CNT_INTVAL }, | ||
| 475 | { "LED: Deck B: Digit 2 - E", 163 | CNT_INTVAL }, | ||
| 476 | { "LED: Deck B: Digit 2 - F", 162 | CNT_INTVAL }, | ||
| 477 | { "LED: Deck B: Digit 2 - G", 161 | CNT_INTVAL }, | ||
| 478 | { "LED: Deck B: Digit 2 - dot", 160 | CNT_INTVAL }, | ||
| 479 | |||
| 480 | { "LED: FX1: dry/wet", 153 | CNT_INTVAL }, | ||
| 481 | { "LED: FX1: 1", 154 | CNT_INTVAL }, | ||
| 482 | { "LED: FX1: 2", 155 | CNT_INTVAL }, | ||
| 483 | { "LED: FX1: 3", 156 | CNT_INTVAL }, | ||
| 484 | { "LED: FX1: Mode", 157 | CNT_INTVAL }, | ||
| 485 | { "LED: FX2: dry/wet", 129 | CNT_INTVAL }, | ||
| 486 | { "LED: FX2: 1", 130 | CNT_INTVAL }, | ||
| 487 | { "LED: FX2: 2", 131 | CNT_INTVAL }, | ||
| 488 | { "LED: FX2: 3", 132 | CNT_INTVAL }, | ||
| 489 | { "LED: FX2: Mode", 133 | CNT_INTVAL }, | ||
| 490 | }; | ||
| 491 | |||
| 299 | static int __devinit add_controls(struct caiaq_controller *c, int num, | 492 | static int __devinit add_controls(struct caiaq_controller *c, int num, |
| 300 | struct snd_usb_caiaqdev *dev) | 493 | struct snd_usb_caiaqdev *dev) |
| 301 | { | 494 | { |
| @@ -354,6 +547,11 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) | |||
| 354 | ret = add_controls(kontrolx1_controller, | 547 | ret = add_controls(kontrolx1_controller, |
| 355 | ARRAY_SIZE(kontrolx1_controller), dev); | 548 | ARRAY_SIZE(kontrolx1_controller), dev); |
| 356 | break; | 549 | break; |
| 550 | |||
| 551 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
| 552 | ret = add_controls(kontrols4_controller, | ||
| 553 | ARRAY_SIZE(kontrols4_controller), dev); | ||
| 554 | break; | ||
| 357 | } | 555 | } |
| 358 | 556 | ||
| 359 | return ret; | 557 | return ret; |
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index cdfb856bddd2..6480c3283c05 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c | |||
| @@ -36,7 +36,7 @@ | |||
| 36 | #include "input.h" | 36 | #include "input.h" |
| 37 | 37 | ||
| 38 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | 38 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); |
| 39 | MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21"); | 39 | MODULE_DESCRIPTION("caiaq USB audio"); |
| 40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
| 41 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | 41 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," |
| 42 | "{Native Instruments, RigKontrol3}," | 42 | "{Native Instruments, RigKontrol3}," |
| @@ -48,7 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | |||
| 48 | "{Native Instruments, Audio 8 DJ}," | 48 | "{Native Instruments, Audio 8 DJ}," |
| 49 | "{Native Instruments, Session I/O}," | 49 | "{Native Instruments, Session I/O}," |
| 50 | "{Native Instruments, GuitarRig mobile}" | 50 | "{Native Instruments, GuitarRig mobile}" |
| 51 | "{Native Instruments, Traktor Kontrol X1}"); | 51 | "{Native Instruments, Traktor Kontrol X1}" |
| 52 | "{Native Instruments, Traktor Kontrol S4}"); | ||
| 52 | 53 | ||
| 53 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ | 54 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ |
| 54 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ | 55 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ |
| @@ -134,6 +135,11 @@ static struct usb_device_id snd_usb_id_table[] = { | |||
| 134 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | 135 | .idVendor = USB_VID_NATIVEINSTRUMENTS, |
| 135 | .idProduct = USB_PID_TRAKTORKONTROLX1 | 136 | .idProduct = USB_PID_TRAKTORKONTROLX1 |
| 136 | }, | 137 | }, |
| 138 | { | ||
| 139 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
| 140 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | ||
| 141 | .idProduct = USB_PID_TRAKTORKONTROLS4 | ||
| 142 | }, | ||
| 137 | { /* terminator */ } | 143 | { /* terminator */ } |
| 138 | }; | 144 | }; |
| 139 | 145 | ||
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index f1117ecc84fd..e3d8a3efb35b 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #define USB_PID_SESSIONIO 0x1915 | 16 | #define USB_PID_SESSIONIO 0x1915 |
| 17 | #define USB_PID_GUITARRIGMOBILE 0x0d8d | 17 | #define USB_PID_GUITARRIGMOBILE 0x0d8d |
| 18 | #define USB_PID_TRAKTORKONTROLX1 0x2305 | 18 | #define USB_PID_TRAKTORKONTROLX1 0x2305 |
| 19 | #define USB_PID_TRAKTORKONTROLS4 0xbaff | ||
| 19 | 20 | ||
| 20 | #define EP1_BUFSIZE 64 | 21 | #define EP1_BUFSIZE 64 |
| 21 | #define EP4_BUFSIZE 512 | 22 | #define EP4_BUFSIZE 512 |
| @@ -99,13 +100,14 @@ struct snd_usb_caiaqdev { | |||
| 99 | struct snd_pcm_substream *sub_capture[MAX_STREAMS]; | 100 | struct snd_pcm_substream *sub_capture[MAX_STREAMS]; |
| 100 | 101 | ||
| 101 | /* Controls */ | 102 | /* Controls */ |
| 102 | unsigned char control_state[64]; | 103 | unsigned char control_state[256]; |
| 104 | unsigned char ep8_out_buf[2]; | ||
| 103 | 105 | ||
| 104 | /* Linux input */ | 106 | /* Linux input */ |
| 105 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | 107 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT |
| 106 | struct input_dev *input_dev; | 108 | struct input_dev *input_dev; |
| 107 | char phys[64]; /* physical device path */ | 109 | char phys[64]; /* physical device path */ |
| 108 | unsigned short keycode[64]; | 110 | unsigned short keycode[128]; |
| 109 | struct urb *ep4_in_urb; | 111 | struct urb *ep4_in_urb; |
| 110 | unsigned char ep4_in_buf[EP4_BUFSIZE]; | 112 | unsigned char ep4_in_buf[EP4_BUFSIZE]; |
| 111 | #endif | 113 | #endif |
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index dcb620796d9e..4432ef7a70a9 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c | |||
| @@ -67,7 +67,12 @@ static unsigned short keycode_kore[] = { | |||
| 67 | KEY_BRL_DOT5 | 67 | KEY_BRL_DOT5 |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | #define KONTROLX1_INPUTS 40 | 70 | #define KONTROLX1_INPUTS (40) |
| 71 | #define KONTROLS4_BUTTONS (12 * 8) | ||
| 72 | #define KONTROLS4_AXIS (46) | ||
| 73 | |||
| 74 | #define KONTROLS4_BUTTON(X) ((X) + BTN_MISC) | ||
| 75 | #define KONTROLS4_ABS(X) ((X) + ABS_HAT0X) | ||
| 71 | 76 | ||
| 72 | #define DEG90 (range / 2) | 77 | #define DEG90 (range / 2) |
| 73 | #define DEG180 (range) | 78 | #define DEG180 (range) |
| @@ -139,6 +144,13 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) | |||
| 139 | #undef HIGH_PEAK | 144 | #undef HIGH_PEAK |
| 140 | #undef LOW_PEAK | 145 | #undef LOW_PEAK |
| 141 | 146 | ||
| 147 | static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev, | ||
| 148 | int axis, const unsigned char *buf, | ||
| 149 | int offset) | ||
| 150 | { | ||
| 151 | input_report_abs(dev->input_dev, axis, | ||
| 152 | (buf[offset * 2] << 8) | buf[offset * 2 + 1]); | ||
| 153 | } | ||
| 142 | 154 | ||
| 143 | static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, | 155 | static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, |
| 144 | const unsigned char *buf, | 156 | const unsigned char *buf, |
| @@ -148,36 +160,30 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, | |||
| 148 | 160 | ||
| 149 | switch (dev->chip.usb_id) { | 161 | switch (dev->chip.usb_id) { |
| 150 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): | 162 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): |
| 151 | input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]); | 163 | snd_caiaq_input_report_abs(dev, ABS_X, buf, 2); |
| 152 | input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]); | 164 | snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0); |
| 153 | input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]); | 165 | snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1); |
| 154 | input_sync(input_dev); | ||
| 155 | break; | 166 | break; |
| 156 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | 167 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): |
| 157 | input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); | ||
| 158 | input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); | ||
| 159 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); | ||
| 160 | input_sync(input_dev); | ||
| 161 | break; | ||
| 162 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): | 168 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): |
| 163 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): | 169 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): |
| 164 | input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); | 170 | snd_caiaq_input_report_abs(dev, ABS_X, buf, 0); |
| 165 | input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); | 171 | snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1); |
| 166 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); | 172 | snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2); |
| 167 | input_sync(input_dev); | ||
| 168 | break; | 173 | break; |
| 169 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 174 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
| 170 | input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]); | 175 | snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4); |
| 171 | input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]); | 176 | snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2); |
| 172 | input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]); | 177 | snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6); |
| 173 | input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]); | 178 | snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1); |
| 174 | input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]); | 179 | snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7); |
| 175 | input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]); | 180 | snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0); |
| 176 | input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]); | 181 | snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5); |
| 177 | input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]); | 182 | snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3); |
| 178 | input_sync(input_dev); | ||
| 179 | break; | 183 | break; |
| 180 | } | 184 | } |
| 185 | |||
| 186 | input_sync(input_dev); | ||
| 181 | } | 187 | } |
| 182 | 188 | ||
| 183 | static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, | 189 | static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, |
| @@ -250,6 +256,150 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, | |||
| 250 | input_sync(input_dev); | 256 | input_sync(input_dev); |
| 251 | } | 257 | } |
| 252 | 258 | ||
| 259 | #define TKS4_MSGBLOCK_SIZE 16 | ||
| 260 | |||
| 261 | static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev, | ||
| 262 | const unsigned char *buf, | ||
| 263 | unsigned int len) | ||
| 264 | { | ||
| 265 | while (len) { | ||
| 266 | unsigned int i, block_id = (buf[0] << 8) | buf[1]; | ||
| 267 | |||
| 268 | switch (block_id) { | ||
| 269 | case 0: | ||
| 270 | /* buttons */ | ||
| 271 | for (i = 0; i < KONTROLS4_BUTTONS; i++) | ||
| 272 | input_report_key(dev->input_dev, KONTROLS4_BUTTON(i), | ||
| 273 | (buf[4 + (i / 8)] >> (i % 8)) & 1); | ||
| 274 | break; | ||
| 275 | |||
| 276 | case 1: | ||
| 277 | /* left wheel */ | ||
| 278 | input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8)); | ||
| 279 | /* right wheel */ | ||
| 280 | input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8)); | ||
| 281 | |||
| 282 | /* rotary encoders */ | ||
| 283 | input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf); | ||
| 284 | input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4); | ||
| 285 | input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf); | ||
| 286 | input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4); | ||
| 287 | input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf); | ||
| 288 | input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4); | ||
| 289 | input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf); | ||
| 290 | input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4); | ||
| 291 | input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf); | ||
| 292 | |||
| 293 | break; | ||
| 294 | case 2: | ||
| 295 | /* Volume Fader Channel D */ | ||
| 296 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1); | ||
| 297 | /* Volume Fader Channel B */ | ||
| 298 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2); | ||
| 299 | /* Volume Fader Channel A */ | ||
| 300 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3); | ||
| 301 | /* Volume Fader Channel C */ | ||
| 302 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4); | ||
| 303 | /* Loop Volume */ | ||
| 304 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6); | ||
| 305 | /* Crossfader */ | ||
| 306 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7); | ||
| 307 | |||
| 308 | break; | ||
| 309 | |||
| 310 | case 3: | ||
| 311 | /* Tempo Fader R */ | ||
| 312 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3); | ||
| 313 | /* Tempo Fader L */ | ||
| 314 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4); | ||
| 315 | /* Mic Volume */ | ||
| 316 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6); | ||
| 317 | /* Cue Mix */ | ||
| 318 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7); | ||
| 319 | |||
| 320 | break; | ||
| 321 | |||
| 322 | case 4: | ||
| 323 | /* Wheel distance sensor L */ | ||
| 324 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1); | ||
| 325 | /* Wheel distance sensor R */ | ||
| 326 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2); | ||
| 327 | /* Channel D EQ - Filter */ | ||
| 328 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3); | ||
| 329 | /* Channel D EQ - Low */ | ||
| 330 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4); | ||
| 331 | /* Channel D EQ - Mid */ | ||
| 332 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5); | ||
| 333 | /* Channel D EQ - Hi */ | ||
| 334 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6); | ||
| 335 | /* FX2 - dry/wet */ | ||
| 336 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7); | ||
| 337 | |||
| 338 | break; | ||
| 339 | |||
| 340 | case 5: | ||
| 341 | /* FX2 - 1 */ | ||
| 342 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1); | ||
| 343 | /* FX2 - 2 */ | ||
| 344 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2); | ||
| 345 | /* FX2 - 3 */ | ||
| 346 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3); | ||
| 347 | /* Channel B EQ - Filter */ | ||
| 348 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4); | ||
| 349 | /* Channel B EQ - Low */ | ||
| 350 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5); | ||
| 351 | /* Channel B EQ - Mid */ | ||
| 352 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6); | ||
| 353 | /* Channel B EQ - Hi */ | ||
| 354 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7); | ||
| 355 | |||
| 356 | break; | ||
| 357 | |||
| 358 | case 6: | ||
| 359 | /* Channel A EQ - Filter */ | ||
| 360 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1); | ||
| 361 | /* Channel A EQ - Low */ | ||
| 362 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2); | ||
| 363 | /* Channel A EQ - Mid */ | ||
| 364 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3); | ||
| 365 | /* Channel A EQ - Hi */ | ||
| 366 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4); | ||
| 367 | /* Channel C EQ - Filter */ | ||
| 368 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5); | ||
| 369 | /* Channel C EQ - Low */ | ||
| 370 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6); | ||
| 371 | /* Channel C EQ - Mid */ | ||
| 372 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7); | ||
| 373 | |||
| 374 | break; | ||
| 375 | |||
| 376 | case 7: | ||
| 377 | /* Channel C EQ - Hi */ | ||
| 378 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1); | ||
| 379 | /* FX1 - wet/dry */ | ||
| 380 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2); | ||
| 381 | /* FX1 - 1 */ | ||
| 382 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3); | ||
| 383 | /* FX1 - 2 */ | ||
| 384 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4); | ||
| 385 | /* FX1 - 3 */ | ||
| 386 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5); | ||
| 387 | |||
| 388 | break; | ||
| 389 | |||
| 390 | default: | ||
| 391 | debug("%s(): bogus block (id %d)\n", | ||
| 392 | __func__, block_id); | ||
| 393 | return; | ||
| 394 | } | ||
| 395 | |||
| 396 | len -= TKS4_MSGBLOCK_SIZE; | ||
| 397 | buf += TKS4_MSGBLOCK_SIZE; | ||
| 398 | } | ||
| 399 | |||
| 400 | input_sync(dev->input_dev); | ||
| 401 | } | ||
| 402 | |||
| 253 | static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | 403 | static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) |
| 254 | { | 404 | { |
| 255 | struct snd_usb_caiaqdev *dev = urb->context; | 405 | struct snd_usb_caiaqdev *dev = urb->context; |
| @@ -259,11 +409,11 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | |||
| 259 | if (urb->status || !dev || urb != dev->ep4_in_urb) | 409 | if (urb->status || !dev || urb != dev->ep4_in_urb) |
| 260 | return; | 410 | return; |
| 261 | 411 | ||
| 262 | if (urb->actual_length < 24) | ||
| 263 | goto requeue; | ||
| 264 | |||
| 265 | switch (dev->chip.usb_id) { | 412 | switch (dev->chip.usb_id) { |
| 266 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 413 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
| 414 | if (urb->actual_length < 24) | ||
| 415 | goto requeue; | ||
| 416 | |||
| 267 | if (buf[0] & 0x3) | 417 | if (buf[0] & 0x3) |
| 268 | snd_caiaq_input_read_io(dev, buf + 1, 7); | 418 | snd_caiaq_input_read_io(dev, buf + 1, 7); |
| 269 | 419 | ||
| @@ -271,6 +421,10 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | |||
| 271 | snd_caiaq_input_read_analog(dev, buf + 8, 16); | 421 | snd_caiaq_input_read_analog(dev, buf + 8, 16); |
| 272 | 422 | ||
| 273 | break; | 423 | break; |
| 424 | |||
| 425 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
| 426 | snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length); | ||
| 427 | break; | ||
| 274 | } | 428 | } |
| 275 | 429 | ||
| 276 | requeue: | 430 | requeue: |
| @@ -289,6 +443,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev) | |||
| 289 | 443 | ||
| 290 | switch (dev->chip.usb_id) { | 444 | switch (dev->chip.usb_id) { |
| 291 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 445 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
| 446 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
| 292 | if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) | 447 | if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) |
| 293 | return -EIO; | 448 | return -EIO; |
| 294 | break; | 449 | break; |
| @@ -306,6 +461,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev) | |||
| 306 | 461 | ||
| 307 | switch (dev->chip.usb_id) { | 462 | switch (dev->chip.usb_id) { |
| 308 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 463 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
| 464 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
| 309 | usb_kill_urb(dev->ep4_in_urb); | 465 | usb_kill_urb(dev->ep4_in_urb); |
| 310 | break; | 466 | break; |
| 311 | } | 467 | } |
| @@ -456,6 +612,46 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) | |||
| 456 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); | 612 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); |
| 457 | 613 | ||
| 458 | break; | 614 | break; |
| 615 | |||
| 616 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
| 617 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
| 618 | BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS); | ||
| 619 | for (i = 0; i < KONTROLS4_BUTTONS; i++) | ||
| 620 | dev->keycode[i] = KONTROLS4_BUTTON(i); | ||
| 621 | input->keycodemax = KONTROLS4_BUTTONS; | ||
| 622 | |||
| 623 | for (i = 0; i < KONTROLS4_AXIS; i++) { | ||
| 624 | int axis = KONTROLS4_ABS(i); | ||
| 625 | input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); | ||
| 626 | } | ||
| 627 | |||
| 628 | /* 36 analog potentiometers and faders */ | ||
| 629 | for (i = 0; i < 36; i++) | ||
| 630 | input_set_abs_params(input, KONTROLS4_ABS(i), 0, 0xfff, 0, 10); | ||
| 631 | |||
| 632 | /* 2 encoder wheels */ | ||
| 633 | input_set_abs_params(input, KONTROLS4_ABS(36), 0, 0x3ff, 0, 1); | ||
| 634 | input_set_abs_params(input, KONTROLS4_ABS(37), 0, 0x3ff, 0, 1); | ||
| 635 | |||
| 636 | /* 9 rotary encoders */ | ||
| 637 | for (i = 0; i < 9; i++) | ||
| 638 | input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1); | ||
| 639 | |||
| 640 | dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 641 | if (!dev->ep4_in_urb) { | ||
| 642 | ret = -ENOMEM; | ||
| 643 | goto exit_free_idev; | ||
| 644 | } | ||
| 645 | |||
| 646 | usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, | ||
| 647 | usb_rcvbulkpipe(usb_dev, 0x4), | ||
| 648 | dev->ep4_in_buf, EP4_BUFSIZE, | ||
| 649 | snd_usb_caiaq_ep4_reply_dispatch, dev); | ||
| 650 | |||
| 651 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); | ||
| 652 | |||
| 653 | break; | ||
| 654 | |||
| 459 | default: | 655 | default: |
| 460 | /* no input methods supported on this device */ | 656 | /* no input methods supported on this device */ |
| 461 | goto exit_free_idev; | 657 | goto exit_free_idev; |
diff --git a/sound/usb/card.c b/sound/usb/card.c index 4eabafa5b037..800f7cb4f251 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
| @@ -300,9 +300,13 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
| 300 | 300 | ||
| 301 | *rchip = NULL; | 301 | *rchip = NULL; |
| 302 | 302 | ||
| 303 | if (snd_usb_get_speed(dev) != USB_SPEED_LOW && | 303 | switch (snd_usb_get_speed(dev)) { |
| 304 | snd_usb_get_speed(dev) != USB_SPEED_FULL && | 304 | case USB_SPEED_LOW: |
| 305 | snd_usb_get_speed(dev) != USB_SPEED_HIGH) { | 305 | case USB_SPEED_FULL: |
| 306 | case USB_SPEED_HIGH: | ||
| 307 | case USB_SPEED_SUPER: | ||
| 308 | break; | ||
| 309 | default: | ||
| 306 | snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); | 310 | snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); |
| 307 | return -ENXIO; | 311 | return -ENXIO; |
| 308 | } | 312 | } |
| @@ -378,11 +382,22 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
| 378 | if (len < sizeof(card->longname)) | 382 | if (len < sizeof(card->longname)) |
| 379 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); | 383 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); |
| 380 | 384 | ||
| 381 | strlcat(card->longname, | 385 | switch (snd_usb_get_speed(dev)) { |
| 382 | snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : | 386 | case USB_SPEED_LOW: |
| 383 | snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : | 387 | strlcat(card->longname, ", low speed", sizeof(card->longname)); |
| 384 | ", high speed", | 388 | break; |
| 385 | sizeof(card->longname)); | 389 | case USB_SPEED_FULL: |
| 390 | strlcat(card->longname, ", full speed", sizeof(card->longname)); | ||
| 391 | break; | ||
| 392 | case USB_SPEED_HIGH: | ||
| 393 | strlcat(card->longname, ", high speed", sizeof(card->longname)); | ||
| 394 | break; | ||
| 395 | case USB_SPEED_SUPER: | ||
| 396 | strlcat(card->longname, ", super speed", sizeof(card->longname)); | ||
| 397 | break; | ||
| 398 | default: | ||
| 399 | break; | ||
| 400 | } | ||
| 386 | 401 | ||
| 387 | snd_usb_audio_create_proc(chip); | 402 | snd_usb_audio_create_proc(chip); |
| 388 | 403 | ||
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index ef0a07e34844..b0ef9f501896 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
| @@ -405,8 +405,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 405 | break; | 405 | break; |
| 406 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ | 406 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ |
| 407 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ | 407 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ |
| 408 | case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */ | ||
| 409 | case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ | ||
| 410 | /* doesn't set the sample rate attribute, but supports it */ | 408 | /* doesn't set the sample rate attribute, but supports it */ |
| 411 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; | 409 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; |
| 412 | break; | 410 | break; |
diff --git a/sound/usb/helper.c b/sound/usb/helper.c index d48d6f8f6ac9..f280c1903c25 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c | |||
| @@ -103,11 +103,16 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, | |||
| 103 | unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, | 103 | unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, |
| 104 | struct usb_host_interface *alts) | 104 | struct usb_host_interface *alts) |
| 105 | { | 105 | { |
| 106 | if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH && | 106 | switch (snd_usb_get_speed(chip->dev)) { |
| 107 | get_endpoint(alts, 0)->bInterval >= 1 && | 107 | case USB_SPEED_HIGH: |
| 108 | get_endpoint(alts, 0)->bInterval <= 4) | 108 | case USB_SPEED_SUPER: |
| 109 | return get_endpoint(alts, 0)->bInterval - 1; | 109 | if (get_endpoint(alts, 0)->bInterval >= 1 && |
| 110 | else | 110 | get_endpoint(alts, 0)->bInterval <= 4) |
| 111 | return 0; | 111 | return get_endpoint(alts, 0)->bInterval - 1; |
| 112 | break; | ||
| 113 | default: | ||
| 114 | break; | ||
| 115 | } | ||
| 116 | return 0; | ||
| 112 | } | 117 | } |
| 113 | 118 | ||
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index b9c2bc65f51a..25bce7e5b1af 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c | |||
| @@ -784,7 +784,7 @@ static struct usb_protocol_ops snd_usbmidi_novation_ops = { | |||
| 784 | }; | 784 | }; |
| 785 | 785 | ||
| 786 | /* | 786 | /* |
| 787 | * "raw" protocol: used by the MOTU FastLane. | 787 | * "raw" protocol: just move raw MIDI bytes from/to the endpoint |
| 788 | */ | 788 | */ |
| 789 | 789 | ||
| 790 | static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep, | 790 | static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep, |
| @@ -834,7 +834,14 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, | |||
| 834 | 834 | ||
| 835 | if (!ep->ports[0].active) | 835 | if (!ep->ports[0].active) |
| 836 | return; | 836 | return; |
| 837 | count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; | 837 | switch (snd_usb_get_speed(ep->umidi->dev)) { |
| 838 | case USB_SPEED_HIGH: | ||
| 839 | case USB_SPEED_SUPER: | ||
| 840 | count = 1; | ||
| 841 | break; | ||
| 842 | default: | ||
| 843 | count = 2; | ||
| 844 | } | ||
| 838 | count = snd_rawmidi_transmit(ep->ports[0].substream, | 845 | count = snd_rawmidi_transmit(ep->ports[0].substream, |
| 839 | urb->transfer_buffer, | 846 | urb->transfer_buffer, |
| 840 | count); | 847 | count); |
| @@ -2115,7 +2122,7 @@ int snd_usbmidi_create(struct snd_card *card, | |||
| 2115 | umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; | 2122 | umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; |
| 2116 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); | 2123 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); |
| 2117 | break; | 2124 | break; |
| 2118 | case QUIRK_MIDI_FASTLANE: | 2125 | case QUIRK_MIDI_RAW_BYTES: |
| 2119 | umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; | 2126 | umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; |
| 2120 | /* | 2127 | /* |
| 2121 | * Interface 1 contains isochronous endpoints, but with the same | 2128 | * Interface 1 contains isochronous endpoints, but with the same |
| @@ -2126,7 +2133,8 @@ int snd_usbmidi_create(struct snd_card *card, | |||
| 2126 | * interface 0, so we have to make sure that the USB core looks | 2133 | * interface 0, so we have to make sure that the USB core looks |
| 2127 | * again at interface 0 by calling usb_set_interface() on it. | 2134 | * again at interface 0 by calling usb_set_interface() on it. |
| 2128 | */ | 2135 | */ |
| 2129 | usb_set_interface(umidi->dev, 0, 0); | 2136 | if (umidi->usb_id == USB_ID(0x07fd, 0x0001)) /* MOTU Fastlane */ |
| 2137 | usb_set_interface(umidi->dev, 0, 0); | ||
| 2130 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); | 2138 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); |
| 2131 | break; | 2139 | break; |
| 2132 | case QUIRK_MIDI_EMAGIC: | 2140 | case QUIRK_MIDI_EMAGIC: |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 3ed3901369ce..f2d74d654b3c 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
| @@ -759,8 +759,6 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl) | |||
| 759 | */ | 759 | */ |
| 760 | static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | 760 | static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) |
| 761 | { | 761 | { |
| 762 | struct snd_usb_audio *chip = cval->mixer->chip; | ||
| 763 | |||
| 764 | /* for failsafe */ | 762 | /* for failsafe */ |
| 765 | cval->min = default_min; | 763 | cval->min = default_min; |
| 766 | cval->max = cval->min + 1; | 764 | cval->max = cval->min + 1; |
| @@ -783,7 +781,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
| 783 | if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || | 781 | if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || |
| 784 | get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { | 782 | get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { |
| 785 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", | 783 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", |
| 786 | cval->id, snd_usb_ctrl_intf(chip), cval->control, cval->id); | 784 | cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id); |
| 787 | return -EINVAL; | 785 | return -EINVAL; |
| 788 | } | 786 | } |
| 789 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { | 787 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { |
| @@ -1642,9 +1640,10 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
| 1642 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1640 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
| 1643 | uinfo->count = 1; | 1641 | uinfo->count = 1; |
| 1644 | uinfo->value.enumerated.items = cval->max; | 1642 | uinfo->value.enumerated.items = cval->max; |
| 1645 | if ((int)uinfo->value.enumerated.item >= cval->max) | 1643 | if (uinfo->value.enumerated.item >= cval->max) |
| 1646 | uinfo->value.enumerated.item = cval->max - 1; | 1644 | uinfo->value.enumerated.item = cval->max - 1; |
| 1647 | strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]); | 1645 | strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item], |
| 1646 | sizeof(uinfo->value.enumerated.name)); | ||
| 1648 | return 0; | 1647 | return 0; |
| 1649 | } | 1648 | } |
| 1650 | 1649 | ||
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index e7df1e5e3f2e..7dae05d8783e 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
| @@ -60,6 +60,7 @@ static const struct rc_config { | |||
| 60 | { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ | 60 | { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ |
| 61 | { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ | 61 | { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ |
| 62 | { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ | 62 | { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ |
| 63 | { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi */ | ||
| 63 | { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ | 64 | { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ |
| 64 | }; | 65 | }; |
| 65 | 66 | ||
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 3b5135c93062..f49756c1b837 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
| @@ -466,7 +466,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, | |||
| 466 | return 0; | 466 | return 0; |
| 467 | } | 467 | } |
| 468 | /* check whether the period time is >= the data packet interval */ | 468 | /* check whether the period time is >= the data packet interval */ |
| 469 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { | 469 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { |
| 470 | ptime = 125 * (1 << fp->datainterval); | 470 | ptime = 125 * (1 << fp->datainterval); |
| 471 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { | 471 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { |
| 472 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); | 472 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); |
| @@ -734,7 +734,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
| 734 | } | 734 | } |
| 735 | 735 | ||
| 736 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; | 736 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
| 737 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) | 737 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) |
| 738 | /* full speed devices have fixed data packet interval */ | 738 | /* full speed devices have fixed data packet interval */ |
| 739 | ptmin = 1000; | 739 | ptmin = 1000; |
| 740 | if (ptmin == 1000) | 740 | if (ptmin == 1000) |
diff --git a/sound/usb/proc.c b/sound/usb/proc.c index f5e3f356b95f..3c650ab3c91d 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c | |||
| @@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s | |||
| 107 | } | 107 | } |
| 108 | snd_iprintf(buffer, "\n"); | 108 | snd_iprintf(buffer, "\n"); |
| 109 | } | 109 | } |
| 110 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) | 110 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) |
| 111 | snd_iprintf(buffer, " Data packet interval: %d us\n", | 111 | snd_iprintf(buffer, " Data packet interval: %d us\n", |
| 112 | 125 * (1 << fp->datainterval)); | 112 | 125 * (1 << fp->datainterval)); |
| 113 | // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); | 113 | // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 2e8003f98fca..ad7079d1676c 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
| @@ -240,9 +240,21 @@ YAMAHA_DEVICE(0x104f, NULL), | |||
| 240 | YAMAHA_DEVICE(0x1050, NULL), | 240 | YAMAHA_DEVICE(0x1050, NULL), |
| 241 | YAMAHA_DEVICE(0x1051, NULL), | 241 | YAMAHA_DEVICE(0x1051, NULL), |
| 242 | YAMAHA_DEVICE(0x1052, NULL), | 242 | YAMAHA_DEVICE(0x1052, NULL), |
| 243 | YAMAHA_INTERFACE(0x1053, 0, NULL), | ||
| 244 | YAMAHA_INTERFACE(0x1054, 0, NULL), | ||
| 245 | YAMAHA_DEVICE(0x1055, NULL), | ||
| 246 | YAMAHA_DEVICE(0x1056, NULL), | ||
| 247 | YAMAHA_DEVICE(0x1057, NULL), | ||
| 248 | YAMAHA_DEVICE(0x1058, NULL), | ||
| 249 | YAMAHA_DEVICE(0x1059, NULL), | ||
| 250 | YAMAHA_DEVICE(0x105a, NULL), | ||
| 251 | YAMAHA_DEVICE(0x105b, NULL), | ||
| 252 | YAMAHA_DEVICE(0x105c, NULL), | ||
| 253 | YAMAHA_DEVICE(0x105d, NULL), | ||
| 243 | YAMAHA_DEVICE(0x2000, "DGP-7"), | 254 | YAMAHA_DEVICE(0x2000, "DGP-7"), |
| 244 | YAMAHA_DEVICE(0x2001, "DGP-5"), | 255 | YAMAHA_DEVICE(0x2001, "DGP-5"), |
| 245 | YAMAHA_DEVICE(0x2002, NULL), | 256 | YAMAHA_DEVICE(0x2002, NULL), |
| 257 | YAMAHA_DEVICE(0x2003, NULL), | ||
| 246 | YAMAHA_DEVICE(0x5000, "CS1D"), | 258 | YAMAHA_DEVICE(0x5000, "CS1D"), |
| 247 | YAMAHA_DEVICE(0x5001, "DSP1D"), | 259 | YAMAHA_DEVICE(0x5001, "DSP1D"), |
| 248 | YAMAHA_DEVICE(0x5002, "DME32"), | 260 | YAMAHA_DEVICE(0x5002, "DME32"), |
| @@ -1136,11 +1148,34 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 1136 | } | 1148 | } |
| 1137 | }, | 1149 | }, |
| 1138 | { | 1150 | { |
| 1151 | /* has ID 0x0066 when not in "Advanced Driver" mode */ | ||
| 1152 | USB_DEVICE(0x0582, 0x0064), | ||
| 1153 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
| 1154 | /* .vendor_name = "EDIROL", */ | ||
| 1155 | /* .product_name = "PCR-1", */ | ||
| 1156 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 1157 | .type = QUIRK_COMPOSITE, | ||
| 1158 | .data = (const struct snd_usb_audio_quirk[]) { | ||
| 1159 | { | ||
| 1160 | .ifnum = 1, | ||
| 1161 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
| 1162 | }, | ||
| 1163 | { | ||
| 1164 | .ifnum = 2, | ||
| 1165 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
| 1166 | }, | ||
| 1167 | { | ||
| 1168 | .ifnum = -1 | ||
| 1169 | } | ||
| 1170 | } | ||
| 1171 | } | ||
| 1172 | }, | ||
| 1173 | { | ||
| 1139 | /* has ID 0x0067 when not in "Advanced Driver" mode */ | 1174 | /* has ID 0x0067 when not in "Advanced Driver" mode */ |
| 1140 | USB_DEVICE(0x0582, 0x0065), | 1175 | USB_DEVICE(0x0582, 0x0065), |
| 1141 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 1176 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
| 1142 | .vendor_name = "EDIROL", | 1177 | /* .vendor_name = "EDIROL", */ |
| 1143 | .product_name = "PCR-1", | 1178 | /* .product_name = "PCR-1", */ |
| 1144 | .ifnum = 0, | 1179 | .ifnum = 0, |
| 1145 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 1180 | .type = QUIRK_MIDI_FIXED_ENDPOINT, |
| 1146 | .data = & (const struct snd_usb_midi_endpoint_info) { | 1181 | .data = & (const struct snd_usb_midi_endpoint_info) { |
| @@ -1525,6 +1560,50 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 1525 | } | 1560 | } |
| 1526 | } | 1561 | } |
| 1527 | }, | 1562 | }, |
| 1563 | { | ||
| 1564 | /* has ID 0x0110 when not in Advanced Driver mode */ | ||
| 1565 | USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f), | ||
| 1566 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
| 1567 | /* .vendor_name = "Roland", */ | ||
| 1568 | /* .product_name = "A-PRO", */ | ||
| 1569 | .ifnum = 1, | ||
| 1570 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
| 1571 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
| 1572 | .out_cables = 0x0003, | ||
| 1573 | .in_cables = 0x0007 | ||
| 1574 | } | ||
| 1575 | } | ||
| 1576 | }, | ||
| 1577 | { | ||
| 1578 | USB_DEVICE(0x0582, 0x0113), | ||
| 1579 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
| 1580 | /* .vendor_name = "BOSS", */ | ||
| 1581 | /* .product_name = "ME-25", */ | ||
| 1582 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 1583 | .type = QUIRK_COMPOSITE, | ||
| 1584 | .data = (const struct snd_usb_audio_quirk[]) { | ||
| 1585 | { | ||
| 1586 | .ifnum = 0, | ||
| 1587 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
| 1588 | }, | ||
| 1589 | { | ||
| 1590 | .ifnum = 1, | ||
| 1591 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
| 1592 | }, | ||
| 1593 | { | ||
| 1594 | .ifnum = 2, | ||
| 1595 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
| 1596 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
| 1597 | .out_cables = 0x0001, | ||
| 1598 | .in_cables = 0x0001 | ||
| 1599 | } | ||
| 1600 | }, | ||
| 1601 | { | ||
| 1602 | .ifnum = -1 | ||
| 1603 | } | ||
| 1604 | } | ||
| 1605 | } | ||
| 1606 | }, | ||
| 1528 | 1607 | ||
| 1529 | /* Guillemot devices */ | 1608 | /* Guillemot devices */ |
| 1530 | { | 1609 | { |
| @@ -1830,7 +1909,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 1830 | USB_DEVICE(0x0763, 0x2080), | 1909 | USB_DEVICE(0x0763, 0x2080), |
| 1831 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 1910 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
| 1832 | /* .vendor_name = "M-Audio", */ | 1911 | /* .vendor_name = "M-Audio", */ |
| 1833 | /* .product_name = "Fast Track Ultra 8", */ | 1912 | /* .product_name = "Fast Track Ultra", */ |
| 1834 | .ifnum = QUIRK_ANY_INTERFACE, | 1913 | .ifnum = QUIRK_ANY_INTERFACE, |
| 1835 | .type = QUIRK_COMPOSITE, | 1914 | .type = QUIRK_COMPOSITE, |
| 1836 | .data = & (const struct snd_usb_audio_quirk[]) { | 1915 | .data = & (const struct snd_usb_audio_quirk[]) { |
| @@ -1840,11 +1919,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 1840 | }, | 1919 | }, |
| 1841 | { | 1920 | { |
| 1842 | .ifnum = 1, | 1921 | .ifnum = 1, |
| 1843 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 1922 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
| 1923 | .data = & (const struct audioformat) { | ||
| 1924 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
| 1925 | .channels = 8, | ||
| 1926 | .iface = 1, | ||
| 1927 | .altsetting = 1, | ||
| 1928 | .altset_idx = 1, | ||
| 1929 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
| 1930 | .endpoint = 0x01, | ||
| 1931 | .ep_attr = 0x09, | ||
| 1932 | .rates = SNDRV_PCM_RATE_44100 | | ||
| 1933 | SNDRV_PCM_RATE_48000 | | ||
| 1934 | SNDRV_PCM_RATE_88200 | | ||
| 1935 | SNDRV_PCM_RATE_96000, | ||
| 1936 | .rate_min = 44100, | ||
| 1937 | .rate_max = 96000, | ||
| 1938 | .nr_rates = 4, | ||
| 1939 | .rate_table = (unsigned int[]) { | ||
| 1940 | 44100, 48000, 88200, 96000 | ||
| 1941 | } | ||
| 1942 | } | ||
| 1844 | }, | 1943 | }, |
| 1845 | { | 1944 | { |
| 1846 | .ifnum = 2, | 1945 | .ifnum = 2, |
| 1847 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 1946 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
| 1947 | .data = & (const struct audioformat) { | ||
| 1948 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
| 1949 | .channels = 8, | ||
| 1950 | .iface = 2, | ||
| 1951 | .altsetting = 1, | ||
| 1952 | .altset_idx = 1, | ||
| 1953 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
| 1954 | .endpoint = 0x81, | ||
| 1955 | .ep_attr = 0x05, | ||
| 1956 | .rates = SNDRV_PCM_RATE_44100 | | ||
| 1957 | SNDRV_PCM_RATE_48000 | | ||
| 1958 | SNDRV_PCM_RATE_88200 | | ||
| 1959 | SNDRV_PCM_RATE_96000, | ||
| 1960 | .rate_min = 44100, | ||
| 1961 | .rate_max = 96000, | ||
| 1962 | .nr_rates = 4, | ||
| 1963 | .rate_table = (unsigned int[]) { | ||
| 1964 | 44100, 48000, 88200, 96000 | ||
| 1965 | } | ||
| 1966 | } | ||
| 1848 | }, | 1967 | }, |
| 1849 | /* interface 3 (MIDI) is standard compliant */ | 1968 | /* interface 3 (MIDI) is standard compliant */ |
| 1850 | { | 1969 | { |
| @@ -1867,11 +1986,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 1867 | }, | 1986 | }, |
| 1868 | { | 1987 | { |
| 1869 | .ifnum = 1, | 1988 | .ifnum = 1, |
| 1870 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 1989 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
| 1990 | .data = & (const struct audioformat) { | ||
| 1991 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
| 1992 | .channels = 8, | ||
| 1993 | .iface = 1, | ||
| 1994 | .altsetting = 1, | ||
| 1995 | .altset_idx = 1, | ||
| 1996 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
| 1997 | .endpoint = 0x01, | ||
| 1998 | .ep_attr = 0x09, | ||
| 1999 | .rates = SNDRV_PCM_RATE_44100 | | ||
| 2000 | SNDRV_PCM_RATE_48000 | | ||
| 2001 | SNDRV_PCM_RATE_88200 | | ||
| 2002 | SNDRV_PCM_RATE_96000, | ||
| 2003 | .rate_min = 44100, | ||
| 2004 | .rate_max = 96000, | ||
| 2005 | .nr_rates = 4, | ||
| 2006 | .rate_table = (unsigned int[]) { | ||
| 2007 | 44100, 48000, 88200, 96000 | ||
| 2008 | } | ||
| 2009 | } | ||
| 1871 | }, | 2010 | }, |
| 1872 | { | 2011 | { |
| 1873 | .ifnum = 2, | 2012 | .ifnum = 2, |
| 1874 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 2013 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
| 2014 | .data = & (const struct audioformat) { | ||
| 2015 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
| 2016 | .channels = 8, | ||
| 2017 | .iface = 2, | ||
| 2018 | .altsetting = 1, | ||
| 2019 | .altset_idx = 1, | ||
| 2020 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
| 2021 | .endpoint = 0x81, | ||
| 2022 | .ep_attr = 0x05, | ||
| 2023 | .rates = SNDRV_PCM_RATE_44100 | | ||
| 2024 | SNDRV_PCM_RATE_48000 | | ||
| 2025 | SNDRV_PCM_RATE_88200 | | ||
| 2026 | SNDRV_PCM_RATE_96000, | ||
| 2027 | .rate_min = 44100, | ||
| 2028 | .rate_max = 96000, | ||
| 2029 | .nr_rates = 4, | ||
| 2030 | .rate_table = (unsigned int[]) { | ||
| 2031 | 44100, 48000, 88200, 96000 | ||
| 2032 | } | ||
| 2033 | } | ||
| 1875 | }, | 2034 | }, |
| 1876 | /* interface 3 (MIDI) is standard compliant */ | 2035 | /* interface 3 (MIDI) is standard compliant */ |
| 1877 | { | 2036 | { |
| @@ -1919,7 +2078,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 1919 | .data = & (const struct snd_usb_audio_quirk[]) { | 2078 | .data = & (const struct snd_usb_audio_quirk[]) { |
| 1920 | { | 2079 | { |
| 1921 | .ifnum = 0, | 2080 | .ifnum = 0, |
| 1922 | .type = QUIRK_MIDI_FASTLANE | 2081 | .type = QUIRK_MIDI_RAW_BYTES |
| 1923 | }, | 2082 | }, |
| 1924 | { | 2083 | { |
| 1925 | .ifnum = 1, | 2084 | .ifnum = 1, |
| @@ -2068,6 +2227,15 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 2068 | } | 2227 | } |
| 2069 | }, | 2228 | }, |
| 2070 | { | 2229 | { |
| 2230 | USB_DEVICE(0x1235, 0x000e), | ||
| 2231 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
| 2232 | /* .vendor_name = "Novation", */ | ||
| 2233 | /* .product_name = "Launchpad", */ | ||
| 2234 | .ifnum = 0, | ||
| 2235 | .type = QUIRK_MIDI_RAW_BYTES | ||
| 2236 | } | ||
| 2237 | }, | ||
| 2238 | { | ||
| 2071 | USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661), | 2239 | USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661), |
| 2072 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 2240 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
| 2073 | .vendor_name = "Novation", | 2241 | .vendor_name = "Novation", |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 9a9da09586a5..cf8bf088394b 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
| @@ -287,7 +287,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, | |||
| 287 | [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, | 287 | [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, |
| 288 | [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, | 288 | [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, |
| 289 | [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, | 289 | [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, |
| 290 | [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, | 290 | [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk, |
| 291 | [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, | 291 | [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, |
| 292 | [QUIRK_MIDI_CME] = create_any_midi_quirk, | 292 | [QUIRK_MIDI_CME] = create_any_midi_quirk, |
| 293 | [QUIRK_MIDI_AKAI] = create_any_midi_quirk, | 293 | [QUIRK_MIDI_AKAI] = create_any_midi_quirk, |
diff --git a/sound/usb/urb.c b/sound/usb/urb.c index de607d4411ac..8deeaad10f10 100644 --- a/sound/usb/urb.c +++ b/sound/usb/urb.c | |||
| @@ -244,7 +244,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, | |||
| 244 | else | 244 | else |
| 245 | subs->curpacksize = maxsize; | 245 | subs->curpacksize = maxsize; |
| 246 | 246 | ||
| 247 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) | 247 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) |
| 248 | packs_per_ms = 8 >> subs->datainterval; | 248 | packs_per_ms = 8 >> subs->datainterval; |
| 249 | else | 249 | else |
| 250 | packs_per_ms = 1; | 250 | packs_per_ms = 1; |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 24d3319cc34d..db3eb21627ee 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
| @@ -70,7 +70,7 @@ enum quirk_type { | |||
| 70 | QUIRK_MIDI_YAMAHA, | 70 | QUIRK_MIDI_YAMAHA, |
| 71 | QUIRK_MIDI_MIDIMAN, | 71 | QUIRK_MIDI_MIDIMAN, |
| 72 | QUIRK_MIDI_NOVATION, | 72 | QUIRK_MIDI_NOVATION, |
| 73 | QUIRK_MIDI_FASTLANE, | 73 | QUIRK_MIDI_RAW_BYTES, |
| 74 | QUIRK_MIDI_EMAGIC, | 74 | QUIRK_MIDI_EMAGIC, |
| 75 | QUIRK_MIDI_CME, | 75 | QUIRK_MIDI_CME, |
| 76 | QUIRK_MIDI_AKAI, | 76 | QUIRK_MIDI_AKAI, |
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 2a528e56afd5..287ef73b1237 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c | |||
| @@ -36,9 +36,9 @@ | |||
| 36 | plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the | 36 | plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the |
| 37 | cost of easier triggered i.e. aeolus xruns (128 or 256frames, | 37 | cost of easier triggered i.e. aeolus xruns (128 or 256frames, |
| 38 | 2periods works but is useless cause of crackling). | 38 | 2periods works but is useless cause of crackling). |
| 39 | 39 | ||
| 40 | This is a first "proof of concept" implementation. | 40 | This is a first "proof of concept" implementation. |
| 41 | Later, funcionalities should migrate to more apropriate places: | 41 | Later, functionalities should migrate to more apropriate places: |
| 42 | Userland: | 42 | Userland: |
| 43 | - The jackd could mmap its float-pcm buffers directly from alsa-lib. | 43 | - The jackd could mmap its float-pcm buffers directly from alsa-lib. |
| 44 | - alsa-lib could provide power of 2 period sized shaping combined with int/float | 44 | - alsa-lib could provide power of 2 period sized shaping combined with int/float |
| @@ -54,7 +54,7 @@ | |||
| 54 | #include <linux/gfp.h> | 54 | #include <linux/gfp.h> |
| 55 | #include "usbusx2yaudio.c" | 55 | #include "usbusx2yaudio.c" |
| 56 | 56 | ||
| 57 | #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1) | 57 | #if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1 |
| 58 | 58 | ||
| 59 | #include <sound/hwdep.h> | 59 | #include <sound/hwdep.h> |
| 60 | 60 | ||
