diff options
104 files changed, 6475 insertions, 737 deletions
diff --git a/Documentation/sound/hd-audio/notes.rst b/Documentation/sound/hd-audio/notes.rst index 9eeb9b468706..f59c3cdbfaf4 100644 --- a/Documentation/sound/hd-audio/notes.rst +++ b/Documentation/sound/hd-audio/notes.rst | |||
| @@ -494,6 +494,8 @@ add_hp_mic (bool) | |||
| 494 | hp_mic_detect (bool) | 494 | hp_mic_detect (bool) |
| 495 | enable/disable the hp/mic shared input for a single built-in mic | 495 | enable/disable the hp/mic shared input for a single built-in mic |
| 496 | case; default true | 496 | case; default true |
| 497 | vmaster (bool) | ||
| 498 | enable/disable the virtual Master control; default true | ||
| 497 | mixer_nid (int) | 499 | mixer_nid (int) |
| 498 | specifies the widget NID of the analog-loopback mixer | 500 | specifies the widget NID of the analog-loopback mixer |
| 499 | 501 | ||
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 0013063db7f2..15fc6daf9096 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h | |||
| @@ -106,8 +106,26 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
| 106 | #define AZX_REG_HSW_EM4 0x100c | 106 | #define AZX_REG_HSW_EM4 0x100c |
| 107 | #define AZX_REG_HSW_EM5 0x1010 | 107 | #define AZX_REG_HSW_EM5 0x1010 |
| 108 | 108 | ||
| 109 | /* Skylake/Broxton display HD-A controller Extended Mode registers */ | 109 | /* Skylake/Broxton vendor-specific registers */ |
| 110 | #define AZX_REG_SKL_EM4L 0x1040 | 110 | #define AZX_REG_VS_EM1 0x1000 |
| 111 | #define AZX_REG_VS_INRC 0x1004 | ||
| 112 | #define AZX_REG_VS_OUTRC 0x1008 | ||
| 113 | #define AZX_REG_VS_FIFOTRK 0x100C | ||
| 114 | #define AZX_REG_VS_FIFOTRK2 0x1010 | ||
| 115 | #define AZX_REG_VS_EM2 0x1030 | ||
| 116 | #define AZX_REG_VS_EM3L 0x1038 | ||
| 117 | #define AZX_REG_VS_EM3U 0x103C | ||
| 118 | #define AZX_REG_VS_EM4L 0x1040 | ||
| 119 | #define AZX_REG_VS_EM4U 0x1044 | ||
| 120 | #define AZX_REG_VS_LTRC 0x1048 | ||
| 121 | #define AZX_REG_VS_D0I3C 0x104A | ||
| 122 | #define AZX_REG_VS_PCE 0x104B | ||
| 123 | #define AZX_REG_VS_L2MAGC 0x1050 | ||
| 124 | #define AZX_REG_VS_L2LAHPT 0x1054 | ||
| 125 | #define AZX_REG_VS_SDXDPIB_XBASE 0x1084 | ||
| 126 | #define AZX_REG_VS_SDXDPIB_XINTERVAL 0x20 | ||
| 127 | #define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 | ||
| 128 | #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 | ||
| 111 | 129 | ||
| 112 | /* PCI space */ | 130 | /* PCI space */ |
| 113 | #define AZX_PCIREG_TCSEL 0x44 | 131 | #define AZX_PCIREG_TCSEL 0x44 |
| @@ -243,9 +261,11 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
| 243 | #define AZX_REG_ML_LOUTPAY 0x20 | 261 | #define AZX_REG_ML_LOUTPAY 0x20 |
| 244 | #define AZX_REG_ML_LINPAY 0x30 | 262 | #define AZX_REG_ML_LINPAY 0x30 |
| 245 | 263 | ||
| 246 | #define AZX_MLCTL_SPA (1<<16) | 264 | #define ML_LCTL_SCF_MASK 0xF |
| 247 | #define AZX_MLCTL_CPA 23 | 265 | #define AZX_MLCTL_SPA (0x1 << 16) |
| 248 | 266 | #define AZX_MLCTL_CPA (0x1 << 23) | |
| 267 | #define AZX_MLCTL_SPA_SHIFT 16 | ||
| 268 | #define AZX_MLCTL_CPA_SHIFT 23 | ||
| 249 | 269 | ||
| 250 | /* registers for DMA Resume Capability Structure */ | 270 | /* registers for DMA Resume Capability Structure */ |
| 251 | #define AZX_DRSM_CAP_ID 0x5 | 271 | #define AZX_DRSM_CAP_ID 0x5 |
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 56004ec8d441..96546b30e900 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h | |||
| @@ -368,24 +368,32 @@ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus); | |||
| 368 | /* | 368 | /* |
| 369 | * macros for easy use | 369 | * macros for easy use |
| 370 | */ | 370 | */ |
| 371 | #define _snd_hdac_chip_write(type, chip, reg, value) \ | 371 | #define _snd_hdac_chip_writeb(chip, reg, value) \ |
| 372 | ((chip)->io_ops->reg_write ## type(value, (chip)->remap_addr + (reg))) | 372 | ((chip)->io_ops->reg_writeb(value, (chip)->remap_addr + (reg))) |
| 373 | #define _snd_hdac_chip_read(type, chip, reg) \ | 373 | #define _snd_hdac_chip_readb(chip, reg) \ |
| 374 | ((chip)->io_ops->reg_read ## type((chip)->remap_addr + (reg))) | 374 | ((chip)->io_ops->reg_readb((chip)->remap_addr + (reg))) |
| 375 | #define _snd_hdac_chip_writew(chip, reg, value) \ | ||
| 376 | ((chip)->io_ops->reg_writew(value, (chip)->remap_addr + (reg))) | ||
| 377 | #define _snd_hdac_chip_readw(chip, reg) \ | ||
| 378 | ((chip)->io_ops->reg_readw((chip)->remap_addr + (reg))) | ||
| 379 | #define _snd_hdac_chip_writel(chip, reg, value) \ | ||
| 380 | ((chip)->io_ops->reg_writel(value, (chip)->remap_addr + (reg))) | ||
| 381 | #define _snd_hdac_chip_readl(chip, reg) \ | ||
| 382 | ((chip)->io_ops->reg_readl((chip)->remap_addr + (reg))) | ||
| 375 | 383 | ||
| 376 | /* read/write a register, pass without AZX_REG_ prefix */ | 384 | /* read/write a register, pass without AZX_REG_ prefix */ |
| 377 | #define snd_hdac_chip_writel(chip, reg, value) \ | 385 | #define snd_hdac_chip_writel(chip, reg, value) \ |
| 378 | _snd_hdac_chip_write(l, chip, AZX_REG_ ## reg, value) | 386 | _snd_hdac_chip_writel(chip, AZX_REG_ ## reg, value) |
| 379 | #define snd_hdac_chip_writew(chip, reg, value) \ | 387 | #define snd_hdac_chip_writew(chip, reg, value) \ |
| 380 | _snd_hdac_chip_write(w, chip, AZX_REG_ ## reg, value) | 388 | _snd_hdac_chip_writew(chip, AZX_REG_ ## reg, value) |
| 381 | #define snd_hdac_chip_writeb(chip, reg, value) \ | 389 | #define snd_hdac_chip_writeb(chip, reg, value) \ |
| 382 | _snd_hdac_chip_write(b, chip, AZX_REG_ ## reg, value) | 390 | _snd_hdac_chip_writeb(chip, AZX_REG_ ## reg, value) |
| 383 | #define snd_hdac_chip_readl(chip, reg) \ | 391 | #define snd_hdac_chip_readl(chip, reg) \ |
| 384 | _snd_hdac_chip_read(l, chip, AZX_REG_ ## reg) | 392 | _snd_hdac_chip_readl(chip, AZX_REG_ ## reg) |
| 385 | #define snd_hdac_chip_readw(chip, reg) \ | 393 | #define snd_hdac_chip_readw(chip, reg) \ |
| 386 | _snd_hdac_chip_read(w, chip, AZX_REG_ ## reg) | 394 | _snd_hdac_chip_readw(chip, AZX_REG_ ## reg) |
| 387 | #define snd_hdac_chip_readb(chip, reg) \ | 395 | #define snd_hdac_chip_readb(chip, reg) \ |
| 388 | _snd_hdac_chip_read(b, chip, AZX_REG_ ## reg) | 396 | _snd_hdac_chip_readb(chip, AZX_REG_ ## reg) |
| 389 | 397 | ||
| 390 | /* update a register, pass without AZX_REG_ prefix */ | 398 | /* update a register, pass without AZX_REG_ prefix */ |
| 391 | #define snd_hdac_chip_updatel(chip, reg, mask, val) \ | 399 | #define snd_hdac_chip_updatel(chip, reg, mask, val) \ |
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index be353a78c303..fd41697cb4d3 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h | |||
| @@ -107,9 +107,11 @@ enum { | |||
| 107 | SNDRV_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */ | 107 | SNDRV_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */ |
| 108 | SNDRV_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */ | 108 | SNDRV_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */ |
| 109 | SNDRV_HWDEP_IFACE_LINE6, /* Line6 USB processors */ | 109 | SNDRV_HWDEP_IFACE_LINE6, /* Line6 USB processors */ |
| 110 | SNDRV_HWDEP_IFACE_FW_MOTU, /* MOTU FireWire series */ | ||
| 111 | SNDRV_HWDEP_IFACE_FW_FIREFACE, /* RME Fireface series */ | ||
| 110 | 112 | ||
| 111 | /* Don't forget to change the following: */ | 113 | /* Don't forget to change the following: */ |
| 112 | SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_LINE6 | 114 | SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_FIREFACE |
| 113 | }; | 115 | }; |
| 114 | 116 | ||
| 115 | struct snd_hwdep_info { | 117 | struct snd_hwdep_info { |
diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h index db79a12fcc78..622900488bdc 100644 --- a/include/uapi/sound/firewire.h +++ b/include/uapi/sound/firewire.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #define SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION 0xd1ce004e | 10 | #define SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION 0xd1ce004e |
| 11 | #define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e617475 | 11 | #define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e617475 |
| 12 | #define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c | 12 | #define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c |
| 13 | #define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479 | ||
| 13 | 14 | ||
| 14 | struct snd_firewire_event_common { | 15 | struct snd_firewire_event_common { |
| 15 | unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */ | 16 | unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */ |
| @@ -46,12 +47,18 @@ struct snd_firewire_event_digi00x_message { | |||
| 46 | __u32 message; /* Digi00x-specific message */ | 47 | __u32 message; /* Digi00x-specific message */ |
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 50 | struct snd_firewire_event_motu_notification { | ||
| 51 | unsigned int type; | ||
| 52 | __u32 message; /* MOTU-specific bits. */ | ||
| 53 | }; | ||
| 54 | |||
| 49 | union snd_firewire_event { | 55 | union snd_firewire_event { |
| 50 | struct snd_firewire_event_common common; | 56 | struct snd_firewire_event_common common; |
| 51 | struct snd_firewire_event_lock_status lock_status; | 57 | struct snd_firewire_event_lock_status lock_status; |
| 52 | struct snd_firewire_event_dice_notification dice_notification; | 58 | struct snd_firewire_event_dice_notification dice_notification; |
| 53 | struct snd_firewire_event_efw_response efw_response; | 59 | struct snd_firewire_event_efw_response efw_response; |
| 54 | struct snd_firewire_event_digi00x_message digi00x_message; | 60 | struct snd_firewire_event_digi00x_message digi00x_message; |
| 61 | struct snd_firewire_event_motu_notification motu_notification; | ||
| 55 | }; | 62 | }; |
| 56 | 63 | ||
| 57 | 64 | ||
| @@ -65,7 +72,8 @@ union snd_firewire_event { | |||
| 65 | #define SNDRV_FIREWIRE_TYPE_OXFW 4 | 72 | #define SNDRV_FIREWIRE_TYPE_OXFW 4 |
| 66 | #define SNDRV_FIREWIRE_TYPE_DIGI00X 5 | 73 | #define SNDRV_FIREWIRE_TYPE_DIGI00X 5 |
| 67 | #define SNDRV_FIREWIRE_TYPE_TASCAM 6 | 74 | #define SNDRV_FIREWIRE_TYPE_TASCAM 6 |
| 68 | /* RME, MOTU, ... */ | 75 | #define SNDRV_FIREWIRE_TYPE_MOTU 7 |
| 76 | #define SNDRV_FIREWIRE_TYPE_FIREFACE 8 | ||
| 69 | 77 | ||
| 70 | struct snd_firewire_get_info { | 78 | struct snd_firewire_get_info { |
| 71 | unsigned int type; /* SNDRV_FIREWIRE_TYPE_xxx */ | 79 | unsigned int type; /* SNDRV_FIREWIRE_TYPE_xxx */ |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 6d4fbc439246..2f836ca09860 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
| @@ -1277,6 +1277,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, | |||
| 1277 | struct timespec tstamp; | 1277 | struct timespec tstamp; |
| 1278 | int prev, append = 0; | 1278 | int prev, append = 0; |
| 1279 | 1279 | ||
| 1280 | memset(&r1, 0, sizeof(r1)); | ||
| 1280 | memset(&tstamp, 0, sizeof(tstamp)); | 1281 | memset(&tstamp, 0, sizeof(tstamp)); |
| 1281 | spin_lock(&tu->qlock); | 1282 | spin_lock(&tu->qlock); |
| 1282 | if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) | | 1283 | if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) | |
| @@ -1292,7 +1293,6 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, | |||
| 1292 | } | 1293 | } |
| 1293 | if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && | 1294 | if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && |
| 1294 | tu->last_resolution != resolution) { | 1295 | tu->last_resolution != resolution) { |
| 1295 | memset(&r1, 0, sizeof(r1)); | ||
| 1296 | r1.event = SNDRV_TIMER_EVENT_RESOLUTION; | 1296 | r1.event = SNDRV_TIMER_EVENT_RESOLUTION; |
| 1297 | r1.tstamp = tstamp; | 1297 | r1.tstamp = tstamp; |
| 1298 | r1.val = resolution; | 1298 | r1.val = resolution; |
| @@ -1430,18 +1430,13 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid) | |||
| 1430 | if (id.card < 0) { | 1430 | if (id.card < 0) { |
| 1431 | id.card = 0; | 1431 | id.card = 0; |
| 1432 | } else { | 1432 | } else { |
| 1433 | if (id.card < 0) { | 1433 | if (id.device < 0) { |
| 1434 | id.card = 0; | 1434 | id.device = 0; |
| 1435 | } else { | 1435 | } else { |
| 1436 | if (id.device < 0) { | 1436 | if (id.subdevice < 0) |
| 1437 | id.device = 0; | 1437 | id.subdevice = 0; |
| 1438 | } else { | 1438 | else |
| 1439 | if (id.subdevice < 0) { | 1439 | id.subdevice++; |
| 1440 | id.subdevice = 0; | ||
| 1441 | } else { | ||
| 1442 | id.subdevice++; | ||
| 1443 | } | ||
| 1444 | } | ||
| 1445 | } | 1440 | } |
| 1446 | } | 1441 | } |
| 1447 | list_for_each(p, &snd_timer_list) { | 1442 | list_for_each(p, &snd_timer_list) { |
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index 289f041706cd..f684fffd1397 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c | |||
| @@ -795,10 +795,8 @@ struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw, | |||
| 795 | return NULL; | 795 | return NULL; |
| 796 | 796 | ||
| 797 | chip = kzalloc(sizeof(*chip) + extra_size, GFP_KERNEL); | 797 | chip = kzalloc(sizeof(*chip) + extra_size, GFP_KERNEL); |
| 798 | if (! chip) { | 798 | if (! chip) |
| 799 | snd_printk(KERN_ERR "vx_core: no memory\n"); | ||
| 800 | return NULL; | 799 | return NULL; |
| 801 | } | ||
| 802 | mutex_init(&chip->lock); | 800 | mutex_init(&chip->lock); |
| 803 | chip->irq = -1; | 801 | chip->irq = -1; |
| 804 | chip->hw = hw; | 802 | chip->hw = hw; |
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 9f00696c4e4a..529d9f405fa9 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig | |||
| @@ -140,4 +140,24 @@ config SND_FIREWIRE_TASCAM | |||
| 140 | To compile this driver as a module, choose M here: the module | 140 | To compile this driver as a module, choose M here: the module |
| 141 | will be called snd-firewire-tascam. | 141 | will be called snd-firewire-tascam. |
| 142 | 142 | ||
| 143 | config SND_FIREWIRE_MOTU | ||
| 144 | tristate "Mark of the unicorn FireWire series support" | ||
| 145 | select SND_FIREWIRE_LIB | ||
| 146 | select SND_HWDEP | ||
| 147 | help | ||
| 148 | Say Y here to enable support for FireWire devices which MOTU produced: | ||
| 149 | * 828mk2 | ||
| 150 | * 828mk3 | ||
| 151 | |||
| 152 | To compile this driver as a module, choose M here: the module | ||
| 153 | will be called snd-firewire-motu. | ||
| 154 | |||
| 155 | config SND_FIREFACE | ||
| 156 | tristate "RME Fireface series support" | ||
| 157 | select SND_FIREWIRE_LIB | ||
| 158 | select SND_HWDEP | ||
| 159 | help | ||
| 160 | Say Y here to include support for RME fireface series. | ||
| 161 | * Fireface 400 | ||
| 162 | |||
| 143 | endif # SND_FIREWIRE | 163 | endif # SND_FIREWIRE |
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index 0ee1fb115d88..1b98fa3fa3d4 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile | |||
| @@ -13,3 +13,5 @@ obj-$(CONFIG_SND_FIREWORKS) += fireworks/ | |||
| 13 | obj-$(CONFIG_SND_BEBOB) += bebob/ | 13 | obj-$(CONFIG_SND_BEBOB) += bebob/ |
| 14 | obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/ | 14 | obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/ |
| 15 | obj-$(CONFIG_SND_FIREWIRE_TASCAM) += tascam/ | 15 | obj-$(CONFIG_SND_FIREWIRE_TASCAM) += tascam/ |
| 16 | obj-$(CONFIG_SND_FIREWIRE_MOTU) += motu/ | ||
| 17 | obj-$(CONFIG_SND_FIREFACE) += fireface/ | ||
diff --git a/sound/firewire/amdtp-stream-trace.h b/sound/firewire/amdtp-stream-trace.h index 9c04faf206b2..ea0d486652c8 100644 --- a/sound/firewire/amdtp-stream-trace.h +++ b/sound/firewire/amdtp-stream-trace.h | |||
| @@ -14,8 +14,8 @@ | |||
| 14 | #include <linux/tracepoint.h> | 14 | #include <linux/tracepoint.h> |
| 15 | 15 | ||
| 16 | TRACE_EVENT(in_packet, | 16 | TRACE_EVENT(in_packet, |
| 17 | TP_PROTO(const struct amdtp_stream *s, u32 cycles, u32 cip_header[2], unsigned int payload_quadlets, unsigned int index), | 17 | TP_PROTO(const struct amdtp_stream *s, u32 cycles, u32 cip_header[2], unsigned int payload_length, unsigned int index), |
| 18 | TP_ARGS(s, cycles, cip_header, payload_quadlets, index), | 18 | TP_ARGS(s, cycles, cip_header, payload_length, index), |
| 19 | TP_STRUCT__entry( | 19 | TP_STRUCT__entry( |
| 20 | __field(unsigned int, second) | 20 | __field(unsigned int, second) |
| 21 | __field(unsigned int, cycle) | 21 | __field(unsigned int, cycle) |
| @@ -37,7 +37,7 @@ TRACE_EVENT(in_packet, | |||
| 37 | __entry->dest = fw_parent_device(s->unit)->card->node_id; | 37 | __entry->dest = fw_parent_device(s->unit)->card->node_id; |
| 38 | __entry->cip_header0 = cip_header[0]; | 38 | __entry->cip_header0 = cip_header[0]; |
| 39 | __entry->cip_header1 = cip_header[1]; | 39 | __entry->cip_header1 = cip_header[1]; |
| 40 | __entry->payload_quadlets = payload_quadlets; | 40 | __entry->payload_quadlets = payload_length / 4; |
| 41 | __entry->packet_index = s->packet_index; | 41 | __entry->packet_index = s->packet_index; |
| 42 | __entry->irq = !!in_interrupt(); | 42 | __entry->irq = !!in_interrupt(); |
| 43 | __entry->index = index; | 43 | __entry->index = index; |
| @@ -101,6 +101,94 @@ TRACE_EVENT(out_packet, | |||
| 101 | __entry->index) | 101 | __entry->index) |
| 102 | ); | 102 | ); |
| 103 | 103 | ||
| 104 | TRACE_EVENT(in_packet_without_header, | ||
| 105 | TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_quadlets, unsigned int data_blocks, unsigned int index), | ||
| 106 | TP_ARGS(s, cycles, payload_quadlets, data_blocks, index), | ||
| 107 | TP_STRUCT__entry( | ||
| 108 | __field(unsigned int, second) | ||
| 109 | __field(unsigned int, cycle) | ||
| 110 | __field(int, channel) | ||
| 111 | __field(int, src) | ||
| 112 | __field(int, dest) | ||
| 113 | __field(unsigned int, payload_quadlets) | ||
| 114 | __field(unsigned int, data_blocks) | ||
| 115 | __field(unsigned int, data_block_counter) | ||
| 116 | __field(unsigned int, packet_index) | ||
| 117 | __field(unsigned int, irq) | ||
| 118 | __field(unsigned int, index) | ||
| 119 | ), | ||
| 120 | TP_fast_assign( | ||
| 121 | __entry->second = cycles / CYCLES_PER_SECOND; | ||
| 122 | __entry->cycle = cycles % CYCLES_PER_SECOND; | ||
| 123 | __entry->channel = s->context->channel; | ||
| 124 | __entry->src = fw_parent_device(s->unit)->node_id; | ||
| 125 | __entry->dest = fw_parent_device(s->unit)->card->node_id; | ||
| 126 | __entry->payload_quadlets = payload_quadlets; | ||
| 127 | __entry->data_blocks = data_blocks, | ||
| 128 | __entry->data_block_counter = s->data_block_counter, | ||
| 129 | __entry->packet_index = s->packet_index; | ||
| 130 | __entry->irq = !!in_interrupt(); | ||
| 131 | __entry->index = index; | ||
| 132 | ), | ||
| 133 | TP_printk( | ||
| 134 | "%02u %04u %04x %04x %02d %03u %3u %3u %02u %01u %02u", | ||
| 135 | __entry->second, | ||
| 136 | __entry->cycle, | ||
| 137 | __entry->src, | ||
| 138 | __entry->dest, | ||
| 139 | __entry->channel, | ||
| 140 | __entry->payload_quadlets, | ||
| 141 | __entry->data_blocks, | ||
| 142 | __entry->data_block_counter, | ||
| 143 | __entry->packet_index, | ||
| 144 | __entry->irq, | ||
| 145 | __entry->index) | ||
| 146 | ); | ||
| 147 | |||
| 148 | TRACE_EVENT(out_packet_without_header, | ||
| 149 | TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_length, unsigned int data_blocks, unsigned int index), | ||
| 150 | TP_ARGS(s, cycles, payload_length, data_blocks, index), | ||
| 151 | TP_STRUCT__entry( | ||
| 152 | __field(unsigned int, second) | ||
| 153 | __field(unsigned int, cycle) | ||
| 154 | __field(int, channel) | ||
| 155 | __field(int, src) | ||
| 156 | __field(int, dest) | ||
| 157 | __field(unsigned int, payload_quadlets) | ||
| 158 | __field(unsigned int, data_blocks) | ||
| 159 | __field(unsigned int, data_block_counter) | ||
| 160 | __field(unsigned int, packet_index) | ||
| 161 | __field(unsigned int, irq) | ||
| 162 | __field(unsigned int, index) | ||
| 163 | ), | ||
| 164 | TP_fast_assign( | ||
| 165 | __entry->second = cycles / CYCLES_PER_SECOND; | ||
| 166 | __entry->cycle = cycles % CYCLES_PER_SECOND; | ||
| 167 | __entry->channel = s->context->channel; | ||
| 168 | __entry->src = fw_parent_device(s->unit)->card->node_id; | ||
| 169 | __entry->dest = fw_parent_device(s->unit)->node_id; | ||
| 170 | __entry->payload_quadlets = payload_length / 4; | ||
| 171 | __entry->data_blocks = data_blocks, | ||
| 172 | __entry->data_blocks = s->data_block_counter, | ||
| 173 | __entry->packet_index = s->packet_index; | ||
| 174 | __entry->irq = !!in_interrupt(); | ||
| 175 | __entry->index = index; | ||
| 176 | ), | ||
| 177 | TP_printk( | ||
| 178 | "%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u", | ||
| 179 | __entry->second, | ||
| 180 | __entry->cycle, | ||
| 181 | __entry->src, | ||
| 182 | __entry->dest, | ||
| 183 | __entry->channel, | ||
| 184 | __entry->payload_quadlets, | ||
| 185 | __entry->data_blocks, | ||
| 186 | __entry->data_block_counter, | ||
| 187 | __entry->packet_index, | ||
| 188 | __entry->irq, | ||
| 189 | __entry->index) | ||
| 190 | ); | ||
| 191 | |||
| 104 | #endif | 192 | #endif |
| 105 | 193 | ||
| 106 | #undef TRACE_INCLUDE_PATH | 194 | #undef TRACE_INCLUDE_PATH |
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 00060c4a9deb..9e6f54f8c45d 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | /* isochronous header parameters */ | 28 | /* isochronous header parameters */ |
| 29 | #define ISO_DATA_LENGTH_SHIFT 16 | 29 | #define ISO_DATA_LENGTH_SHIFT 16 |
| 30 | #define TAG_NO_CIP_HEADER 0 | ||
| 30 | #define TAG_CIP 1 | 31 | #define TAG_CIP 1 |
| 31 | 32 | ||
| 32 | /* common isochronous packet header parameters */ | 33 | /* common isochronous packet header parameters */ |
| @@ -37,6 +38,8 @@ | |||
| 37 | #define CIP_SID_MASK 0x3f000000 | 38 | #define CIP_SID_MASK 0x3f000000 |
| 38 | #define CIP_DBS_MASK 0x00ff0000 | 39 | #define CIP_DBS_MASK 0x00ff0000 |
| 39 | #define CIP_DBS_SHIFT 16 | 40 | #define CIP_DBS_SHIFT 16 |
| 41 | #define CIP_SPH_MASK 0x00000400 | ||
| 42 | #define CIP_SPH_SHIFT 10 | ||
| 40 | #define CIP_DBC_MASK 0x000000ff | 43 | #define CIP_DBC_MASK 0x000000ff |
| 41 | #define CIP_FMT_SHIFT 24 | 44 | #define CIP_FMT_SHIFT 24 |
| 42 | #define CIP_FMT_MASK 0x3f000000 | 45 | #define CIP_FMT_MASK 0x3f000000 |
| @@ -232,11 +235,15 @@ EXPORT_SYMBOL(amdtp_stream_set_parameters); | |||
| 232 | unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s) | 235 | unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s) |
| 233 | { | 236 | { |
| 234 | unsigned int multiplier = 1; | 237 | unsigned int multiplier = 1; |
| 238 | unsigned int header_size = 0; | ||
| 235 | 239 | ||
| 236 | if (s->flags & CIP_JUMBO_PAYLOAD) | 240 | if (s->flags & CIP_JUMBO_PAYLOAD) |
| 237 | multiplier = 5; | 241 | multiplier = 5; |
| 242 | if (!(s->flags & CIP_NO_HEADER)) | ||
| 243 | header_size = 8; | ||
| 238 | 244 | ||
| 239 | return 8 + s->syt_interval * s->data_block_quadlets * 4 * multiplier; | 245 | return header_size + |
| 246 | s->syt_interval * s->data_block_quadlets * 4 * multiplier; | ||
| 240 | } | 247 | } |
| 241 | EXPORT_SYMBOL(amdtp_stream_get_max_payload); | 248 | EXPORT_SYMBOL(amdtp_stream_get_max_payload); |
| 242 | 249 | ||
| @@ -378,7 +385,7 @@ static int queue_packet(struct amdtp_stream *s, unsigned int header_length, | |||
| 378 | goto end; | 385 | goto end; |
| 379 | 386 | ||
| 380 | p.interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL); | 387 | p.interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL); |
| 381 | p.tag = TAG_CIP; | 388 | p.tag = s->tag; |
| 382 | p.header_length = header_length; | 389 | p.header_length = header_length; |
| 383 | if (payload_length > 0) | 390 | if (payload_length > 0) |
| 384 | p.payload_length = payload_length; | 391 | p.payload_length = payload_length; |
| @@ -405,17 +412,16 @@ static inline int queue_out_packet(struct amdtp_stream *s, | |||
| 405 | 412 | ||
| 406 | static inline int queue_in_packet(struct amdtp_stream *s) | 413 | static inline int queue_in_packet(struct amdtp_stream *s) |
| 407 | { | 414 | { |
| 408 | return queue_packet(s, IN_PACKET_HEADER_SIZE, | 415 | return queue_packet(s, IN_PACKET_HEADER_SIZE, s->max_payload_length); |
| 409 | amdtp_stream_get_max_payload(s)); | ||
| 410 | } | 416 | } |
| 411 | 417 | ||
| 412 | static int handle_out_packet(struct amdtp_stream *s, unsigned int cycle, | 418 | static int handle_out_packet(struct amdtp_stream *s, |
| 419 | unsigned int payload_length, unsigned int cycle, | ||
| 413 | unsigned int index) | 420 | unsigned int index) |
| 414 | { | 421 | { |
| 415 | __be32 *buffer; | 422 | __be32 *buffer; |
| 416 | unsigned int syt; | 423 | unsigned int syt; |
| 417 | unsigned int data_blocks; | 424 | unsigned int data_blocks; |
| 418 | unsigned int payload_length; | ||
| 419 | unsigned int pcm_frames; | 425 | unsigned int pcm_frames; |
| 420 | struct snd_pcm_substream *pcm; | 426 | struct snd_pcm_substream *pcm; |
| 421 | 427 | ||
| @@ -424,15 +430,22 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int cycle, | |||
| 424 | data_blocks = calculate_data_blocks(s, syt); | 430 | data_blocks = calculate_data_blocks(s, syt); |
| 425 | pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt); | 431 | pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt); |
| 426 | 432 | ||
| 433 | if (s->flags & CIP_DBC_IS_END_EVENT) | ||
| 434 | s->data_block_counter = | ||
| 435 | (s->data_block_counter + data_blocks) & 0xff; | ||
| 436 | |||
| 427 | buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | | 437 | buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | |
| 428 | (s->data_block_quadlets << CIP_DBS_SHIFT) | | 438 | (s->data_block_quadlets << CIP_DBS_SHIFT) | |
| 439 | ((s->sph << CIP_SPH_SHIFT) & CIP_SPH_MASK) | | ||
| 429 | s->data_block_counter); | 440 | s->data_block_counter); |
| 430 | buffer[1] = cpu_to_be32(CIP_EOH | | 441 | buffer[1] = cpu_to_be32(CIP_EOH | |
| 431 | ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) | | 442 | ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) | |
| 432 | ((s->fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) | | 443 | ((s->fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) | |
| 433 | (syt & CIP_SYT_MASK)); | 444 | (syt & CIP_SYT_MASK)); |
| 434 | 445 | ||
| 435 | s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; | 446 | if (!(s->flags & CIP_DBC_IS_END_EVENT)) |
| 447 | s->data_block_counter = | ||
| 448 | (s->data_block_counter + data_blocks) & 0xff; | ||
| 436 | payload_length = 8 + data_blocks * 4 * s->data_block_quadlets; | 449 | payload_length = 8 + data_blocks * 4 * s->data_block_quadlets; |
| 437 | 450 | ||
| 438 | trace_out_packet(s, cycle, buffer, payload_length, index); | 451 | trace_out_packet(s, cycle, buffer, payload_length, index); |
| @@ -448,13 +461,45 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int cycle, | |||
| 448 | return 0; | 461 | return 0; |
| 449 | } | 462 | } |
| 450 | 463 | ||
| 464 | static int handle_out_packet_without_header(struct amdtp_stream *s, | ||
| 465 | unsigned int payload_length, unsigned int cycle, | ||
| 466 | unsigned int index) | ||
| 467 | { | ||
| 468 | __be32 *buffer; | ||
| 469 | unsigned int syt; | ||
| 470 | unsigned int data_blocks; | ||
| 471 | unsigned int pcm_frames; | ||
| 472 | struct snd_pcm_substream *pcm; | ||
| 473 | |||
| 474 | buffer = s->buffer.packets[s->packet_index].buffer; | ||
| 475 | syt = calculate_syt(s, cycle); | ||
| 476 | data_blocks = calculate_data_blocks(s, syt); | ||
| 477 | pcm_frames = s->process_data_blocks(s, buffer, data_blocks, &syt); | ||
| 478 | s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; | ||
| 479 | |||
| 480 | payload_length = data_blocks * 4 * s->data_block_quadlets; | ||
| 481 | |||
| 482 | trace_out_packet_without_header(s, cycle, payload_length, data_blocks, | ||
| 483 | index); | ||
| 484 | |||
| 485 | if (queue_out_packet(s, payload_length) < 0) | ||
| 486 | return -EIO; | ||
| 487 | |||
| 488 | pcm = ACCESS_ONCE(s->pcm); | ||
| 489 | if (pcm && pcm_frames > 0) | ||
| 490 | update_pcm_pointers(s, pcm, pcm_frames); | ||
| 491 | |||
| 492 | /* No need to return the number of handled data blocks. */ | ||
| 493 | return 0; | ||
| 494 | } | ||
| 495 | |||
| 451 | static int handle_in_packet(struct amdtp_stream *s, | 496 | static int handle_in_packet(struct amdtp_stream *s, |
| 452 | unsigned int payload_quadlets, unsigned int cycle, | 497 | unsigned int payload_length, unsigned int cycle, |
| 453 | unsigned int index) | 498 | unsigned int index) |
| 454 | { | 499 | { |
| 455 | __be32 *buffer; | 500 | __be32 *buffer; |
| 456 | u32 cip_header[2]; | 501 | u32 cip_header[2]; |
| 457 | unsigned int fmt, fdf, syt; | 502 | unsigned int sph, fmt, fdf, syt; |
| 458 | unsigned int data_block_quadlets, data_block_counter, dbc_interval; | 503 | unsigned int data_block_quadlets, data_block_counter, dbc_interval; |
| 459 | unsigned int data_blocks; | 504 | unsigned int data_blocks; |
| 460 | struct snd_pcm_substream *pcm; | 505 | struct snd_pcm_substream *pcm; |
| @@ -465,14 +510,15 @@ static int handle_in_packet(struct amdtp_stream *s, | |||
| 465 | cip_header[0] = be32_to_cpu(buffer[0]); | 510 | cip_header[0] = be32_to_cpu(buffer[0]); |
| 466 | cip_header[1] = be32_to_cpu(buffer[1]); | 511 | cip_header[1] = be32_to_cpu(buffer[1]); |
| 467 | 512 | ||
| 468 | trace_in_packet(s, cycle, cip_header, payload_quadlets, index); | 513 | trace_in_packet(s, cycle, cip_header, payload_length, index); |
| 469 | 514 | ||
| 470 | /* | 515 | /* |
| 471 | * This module supports 'Two-quadlet CIP header with SYT field'. | 516 | * This module supports 'Two-quadlet CIP header with SYT field'. |
| 472 | * For convenience, also check FMT field is AM824 or not. | 517 | * For convenience, also check FMT field is AM824 or not. |
| 473 | */ | 518 | */ |
| 474 | if (((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) || | 519 | if ((((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) || |
| 475 | ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH)) { | 520 | ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH)) && |
| 521 | (!(s->flags & CIP_HEADER_WITHOUT_EOH))) { | ||
| 476 | dev_info_ratelimited(&s->unit->device, | 522 | dev_info_ratelimited(&s->unit->device, |
| 477 | "Invalid CIP header for AMDTP: %08X:%08X\n", | 523 | "Invalid CIP header for AMDTP: %08X:%08X\n", |
| 478 | cip_header[0], cip_header[1]); | 524 | cip_header[0], cip_header[1]); |
| @@ -482,8 +528,9 @@ static int handle_in_packet(struct amdtp_stream *s, | |||
| 482 | } | 528 | } |
| 483 | 529 | ||
| 484 | /* Check valid protocol or not. */ | 530 | /* Check valid protocol or not. */ |
| 531 | sph = (cip_header[0] & CIP_SPH_MASK) >> CIP_SPH_SHIFT; | ||
| 485 | fmt = (cip_header[1] & CIP_FMT_MASK) >> CIP_FMT_SHIFT; | 532 | fmt = (cip_header[1] & CIP_FMT_MASK) >> CIP_FMT_SHIFT; |
| 486 | if (fmt != s->fmt) { | 533 | if (sph != s->sph || fmt != s->fmt) { |
| 487 | dev_info_ratelimited(&s->unit->device, | 534 | dev_info_ratelimited(&s->unit->device, |
| 488 | "Detect unexpected protocol: %08x %08x\n", | 535 | "Detect unexpected protocol: %08x %08x\n", |
| 489 | cip_header[0], cip_header[1]); | 536 | cip_header[0], cip_header[1]); |
| @@ -494,7 +541,7 @@ static int handle_in_packet(struct amdtp_stream *s, | |||
| 494 | 541 | ||
| 495 | /* Calculate data blocks */ | 542 | /* Calculate data blocks */ |
| 496 | fdf = (cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SHIFT; | 543 | fdf = (cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SHIFT; |
| 497 | if (payload_quadlets < 3 || | 544 | if (payload_length < 12 || |
| 498 | (fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) { | 545 | (fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) { |
| 499 | data_blocks = 0; | 546 | data_blocks = 0; |
| 500 | } else { | 547 | } else { |
| @@ -510,7 +557,8 @@ static int handle_in_packet(struct amdtp_stream *s, | |||
| 510 | if (s->flags & CIP_WRONG_DBS) | 557 | if (s->flags & CIP_WRONG_DBS) |
| 511 | data_block_quadlets = s->data_block_quadlets; | 558 | data_block_quadlets = s->data_block_quadlets; |
| 512 | 559 | ||
| 513 | data_blocks = (payload_quadlets - 2) / data_block_quadlets; | 560 | data_blocks = (payload_length / 4 - 2) / |
| 561 | data_block_quadlets; | ||
| 514 | } | 562 | } |
| 515 | 563 | ||
| 516 | /* Check data block counter continuity */ | 564 | /* Check data block counter continuity */ |
| @@ -561,6 +609,34 @@ end: | |||
| 561 | return 0; | 609 | return 0; |
| 562 | } | 610 | } |
| 563 | 611 | ||
| 612 | static int handle_in_packet_without_header(struct amdtp_stream *s, | ||
| 613 | unsigned int payload_quadlets, unsigned int cycle, | ||
| 614 | unsigned int index) | ||
| 615 | { | ||
| 616 | __be32 *buffer; | ||
| 617 | unsigned int data_blocks; | ||
| 618 | struct snd_pcm_substream *pcm; | ||
| 619 | unsigned int pcm_frames; | ||
| 620 | |||
| 621 | buffer = s->buffer.packets[s->packet_index].buffer; | ||
| 622 | data_blocks = payload_quadlets / s->data_block_quadlets; | ||
| 623 | |||
| 624 | trace_in_packet_without_header(s, cycle, payload_quadlets, data_blocks, | ||
| 625 | index); | ||
| 626 | |||
| 627 | pcm_frames = s->process_data_blocks(s, buffer, data_blocks, NULL); | ||
| 628 | s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; | ||
| 629 | |||
| 630 | if (queue_in_packet(s) < 0) | ||
| 631 | return -EIO; | ||
| 632 | |||
| 633 | pcm = ACCESS_ONCE(s->pcm); | ||
| 634 | if (pcm && pcm_frames > 0) | ||
| 635 | update_pcm_pointers(s, pcm, pcm_frames); | ||
| 636 | |||
| 637 | return 0; | ||
| 638 | } | ||
| 639 | |||
| 564 | /* | 640 | /* |
| 565 | * In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On | 641 | * In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On |
| 566 | * the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent | 642 | * the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent |
| @@ -604,7 +680,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, | |||
| 604 | 680 | ||
| 605 | for (i = 0; i < packets; ++i) { | 681 | for (i = 0; i < packets; ++i) { |
| 606 | cycle = increment_cycle_count(cycle, 1); | 682 | cycle = increment_cycle_count(cycle, 1); |
| 607 | if (handle_out_packet(s, cycle, i) < 0) { | 683 | if (s->handle_packet(s, 0, cycle, i) < 0) { |
| 608 | s->packet_index = -1; | 684 | s->packet_index = -1; |
| 609 | amdtp_stream_pcm_abort(s); | 685 | amdtp_stream_pcm_abort(s); |
| 610 | return; | 686 | return; |
| @@ -620,7 +696,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, | |||
| 620 | { | 696 | { |
| 621 | struct amdtp_stream *s = private_data; | 697 | struct amdtp_stream *s = private_data; |
| 622 | unsigned int i, packets; | 698 | unsigned int i, packets; |
| 623 | unsigned int payload_quadlets, max_payload_quadlets; | 699 | unsigned int payload_length, max_payload_length; |
| 624 | __be32 *headers = header; | 700 | __be32 *headers = header; |
| 625 | u32 cycle; | 701 | u32 cycle; |
| 626 | 702 | ||
| @@ -636,22 +712,22 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, | |||
| 636 | cycle = decrement_cycle_count(cycle, packets); | 712 | cycle = decrement_cycle_count(cycle, packets); |
| 637 | 713 | ||
| 638 | /* For buffer-over-run prevention. */ | 714 | /* For buffer-over-run prevention. */ |
| 639 | max_payload_quadlets = amdtp_stream_get_max_payload(s) / 4; | 715 | max_payload_length = s->max_payload_length; |
| 640 | 716 | ||
| 641 | for (i = 0; i < packets; i++) { | 717 | for (i = 0; i < packets; i++) { |
| 642 | cycle = increment_cycle_count(cycle, 1); | 718 | cycle = increment_cycle_count(cycle, 1); |
| 643 | 719 | ||
| 644 | /* The number of quadlets in this packet */ | 720 | /* The number of bytes in this packet */ |
| 645 | payload_quadlets = | 721 | payload_length = |
| 646 | (be32_to_cpu(headers[i]) >> ISO_DATA_LENGTH_SHIFT) / 4; | 722 | (be32_to_cpu(headers[i]) >> ISO_DATA_LENGTH_SHIFT); |
| 647 | if (payload_quadlets > max_payload_quadlets) { | 723 | if (payload_length > max_payload_length) { |
| 648 | dev_err(&s->unit->device, | 724 | dev_err(&s->unit->device, |
| 649 | "Detect jumbo payload: %02x %02x\n", | 725 | "Detect jumbo payload: %04x %04x\n", |
| 650 | payload_quadlets, max_payload_quadlets); | 726 | payload_length, max_payload_length); |
| 651 | break; | 727 | break; |
| 652 | } | 728 | } |
| 653 | 729 | ||
| 654 | if (handle_in_packet(s, payload_quadlets, cycle, i) < 0) | 730 | if (s->handle_packet(s, payload_length, cycle, i) < 0) |
| 655 | break; | 731 | break; |
| 656 | } | 732 | } |
| 657 | 733 | ||
| @@ -671,6 +747,10 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, | |||
| 671 | void *header, void *private_data) | 747 | void *header, void *private_data) |
| 672 | { | 748 | { |
| 673 | struct amdtp_stream *s = private_data; | 749 | struct amdtp_stream *s = private_data; |
| 750 | u32 cycle; | ||
| 751 | unsigned int packets; | ||
| 752 | |||
| 753 | s->max_payload_length = amdtp_stream_get_max_payload(s); | ||
| 674 | 754 | ||
| 675 | /* | 755 | /* |
| 676 | * For in-stream, first packet has come. | 756 | * For in-stream, first packet has come. |
| @@ -679,10 +759,27 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, | |||
| 679 | s->callbacked = true; | 759 | s->callbacked = true; |
| 680 | wake_up(&s->callback_wait); | 760 | wake_up(&s->callback_wait); |
| 681 | 761 | ||
| 682 | if (s->direction == AMDTP_IN_STREAM) | 762 | cycle = compute_cycle_count(tstamp); |
| 763 | |||
| 764 | if (s->direction == AMDTP_IN_STREAM) { | ||
| 765 | packets = header_length / IN_PACKET_HEADER_SIZE; | ||
| 766 | cycle = decrement_cycle_count(cycle, packets); | ||
| 683 | context->callback.sc = in_stream_callback; | 767 | context->callback.sc = in_stream_callback; |
| 684 | else | 768 | if (s->flags & CIP_NO_HEADER) |
| 769 | s->handle_packet = handle_in_packet_without_header; | ||
| 770 | else | ||
| 771 | s->handle_packet = handle_in_packet; | ||
| 772 | } else { | ||
| 773 | packets = header_length / 4; | ||
| 774 | cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets); | ||
| 685 | context->callback.sc = out_stream_callback; | 775 | context->callback.sc = out_stream_callback; |
| 776 | if (s->flags & CIP_NO_HEADER) | ||
| 777 | s->handle_packet = handle_out_packet_without_header; | ||
| 778 | else | ||
| 779 | s->handle_packet = handle_out_packet; | ||
| 780 | } | ||
| 781 | |||
| 782 | s->start_cycle = cycle; | ||
| 686 | 783 | ||
| 687 | context->callback.sc(context, tstamp, header_length, header, s); | 784 | context->callback.sc(context, tstamp, header_length, header, s); |
| 688 | } | 785 | } |
| @@ -759,6 +856,11 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) | |||
| 759 | 856 | ||
| 760 | amdtp_stream_update(s); | 857 | amdtp_stream_update(s); |
| 761 | 858 | ||
| 859 | if (s->flags & CIP_NO_HEADER) | ||
| 860 | s->tag = TAG_NO_CIP_HEADER; | ||
| 861 | else | ||
| 862 | s->tag = TAG_CIP; | ||
| 863 | |||
| 762 | s->packet_index = 0; | 864 | s->packet_index = 0; |
| 763 | do { | 865 | do { |
| 764 | if (s->direction == AMDTP_IN_STREAM) | 866 | if (s->direction == AMDTP_IN_STREAM) |
| @@ -771,7 +873,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) | |||
| 771 | 873 | ||
| 772 | /* NOTE: TAG1 matches CIP. This just affects in stream. */ | 874 | /* NOTE: TAG1 matches CIP. This just affects in stream. */ |
| 773 | tag = FW_ISO_CONTEXT_MATCH_TAG1; | 875 | tag = FW_ISO_CONTEXT_MATCH_TAG1; |
| 774 | if (s->flags & CIP_EMPTY_WITH_TAG0) | 876 | if ((s->flags & CIP_EMPTY_WITH_TAG0) || (s->flags & CIP_NO_HEADER)) |
| 775 | tag |= FW_ISO_CONTEXT_MATCH_TAG0; | 877 | tag |= FW_ISO_CONTEXT_MATCH_TAG0; |
| 776 | 878 | ||
| 777 | s->callbacked = false; | 879 | s->callbacked = false; |
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index c1bc7fad056e..7e8831722821 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h | |||
| @@ -18,8 +18,8 @@ | |||
| 18 | * SYT_INTERVAL samples, with these two types alternating so that | 18 | * SYT_INTERVAL samples, with these two types alternating so that |
| 19 | * the overall sample rate comes out right. | 19 | * the overall sample rate comes out right. |
| 20 | * @CIP_EMPTY_WITH_TAG0: Only for in-stream. Empty in-packets have TAG0. | 20 | * @CIP_EMPTY_WITH_TAG0: Only for in-stream. Empty in-packets have TAG0. |
| 21 | * @CIP_DBC_IS_END_EVENT: Only for in-stream. The value of dbc in an in-packet | 21 | * @CIP_DBC_IS_END_EVENT: The value of dbc in an packet corresponds to the end |
| 22 | * corresponds to the end of event in the packet. Out of IEC 61883. | 22 | * of event in the packet. Out of IEC 61883. |
| 23 | * @CIP_WRONG_DBS: Only for in-stream. The value of dbs is wrong in in-packets. | 23 | * @CIP_WRONG_DBS: Only for in-stream. The value of dbs is wrong in in-packets. |
| 24 | * The value of data_block_quadlets is used instead of reported value. | 24 | * The value of data_block_quadlets is used instead of reported value. |
| 25 | * @CIP_SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is | 25 | * @CIP_SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is |
| @@ -29,6 +29,9 @@ | |||
| 29 | * @CIP_JUMBO_PAYLOAD: Only for in-stream. The number of data blocks in an | 29 | * @CIP_JUMBO_PAYLOAD: Only for in-stream. The number of data blocks in an |
| 30 | * packet is larger than IEC 61883-6 defines. Current implementation | 30 | * packet is larger than IEC 61883-6 defines. Current implementation |
| 31 | * allows 5 times as large as IEC 61883-6 defines. | 31 | * allows 5 times as large as IEC 61883-6 defines. |
| 32 | * @CIP_HEADER_WITHOUT_EOH: Only for in-stream. CIP Header doesn't include | ||
| 33 | * valid EOH. | ||
| 34 | * @CIP_NO_HEADERS: a lack of headers in packets | ||
| 32 | */ | 35 | */ |
| 33 | enum cip_flags { | 36 | enum cip_flags { |
| 34 | CIP_NONBLOCKING = 0x00, | 37 | CIP_NONBLOCKING = 0x00, |
| @@ -39,6 +42,8 @@ enum cip_flags { | |||
| 39 | CIP_SKIP_DBC_ZERO_CHECK = 0x10, | 42 | CIP_SKIP_DBC_ZERO_CHECK = 0x10, |
| 40 | CIP_EMPTY_HAS_WRONG_DBC = 0x20, | 43 | CIP_EMPTY_HAS_WRONG_DBC = 0x20, |
| 41 | CIP_JUMBO_PAYLOAD = 0x40, | 44 | CIP_JUMBO_PAYLOAD = 0x40, |
| 45 | CIP_HEADER_WITHOUT_EOH = 0x80, | ||
| 46 | CIP_NO_HEADER = 0x100, | ||
| 42 | }; | 47 | }; |
| 43 | 48 | ||
| 44 | /** | 49 | /** |
| @@ -101,11 +106,17 @@ struct amdtp_stream { | |||
| 101 | struct fw_iso_context *context; | 106 | struct fw_iso_context *context; |
| 102 | struct iso_packets_buffer buffer; | 107 | struct iso_packets_buffer buffer; |
| 103 | int packet_index; | 108 | int packet_index; |
| 109 | int tag; | ||
| 110 | int (*handle_packet)(struct amdtp_stream *s, | ||
| 111 | unsigned int payload_quadlets, unsigned int cycle, | ||
| 112 | unsigned int index); | ||
| 113 | unsigned int max_payload_length; | ||
| 104 | 114 | ||
| 105 | /* For CIP headers. */ | 115 | /* For CIP headers. */ |
| 106 | unsigned int source_node_id_field; | 116 | unsigned int source_node_id_field; |
| 107 | unsigned int data_block_quadlets; | 117 | unsigned int data_block_quadlets; |
| 108 | unsigned int data_block_counter; | 118 | unsigned int data_block_counter; |
| 119 | unsigned int sph; | ||
| 109 | unsigned int fmt; | 120 | unsigned int fmt; |
| 110 | unsigned int fdf; | 121 | unsigned int fdf; |
| 111 | /* quirk: fixed interval of dbc between previos/current packets. */ | 122 | /* quirk: fixed interval of dbc between previos/current packets. */ |
| @@ -130,6 +141,7 @@ struct amdtp_stream { | |||
| 130 | /* To wait for first packet. */ | 141 | /* To wait for first packet. */ |
| 131 | bool callbacked; | 142 | bool callbacked; |
| 132 | wait_queue_head_t callback_wait; | 143 | wait_queue_head_t callback_wait; |
| 144 | u32 start_cycle; | ||
| 133 | 145 | ||
| 134 | /* For backends to process data blocks. */ | 146 | /* For backends to process data blocks. */ |
| 135 | void *protocol; | 147 | void *protocol; |
diff --git a/sound/firewire/bebob/bebob_command.c b/sound/firewire/bebob/bebob_command.c index 9402cc15dbc1..f9b4225dd86f 100644 --- a/sound/firewire/bebob/bebob_command.c +++ b/sound/firewire/bebob/bebob_command.c | |||
| @@ -31,13 +31,15 @@ int avc_audio_set_selector(struct fw_unit *unit, unsigned int subunit_id, | |||
| 31 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, | 31 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, |
| 32 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | 32 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | |
| 33 | BIT(6) | BIT(7) | BIT(8)); | 33 | BIT(6) | BIT(7) | BIT(8)); |
| 34 | if (err > 0 && err < 9) | 34 | if (err < 0) |
| 35 | ; | ||
| 36 | else if (err < 9) | ||
| 35 | err = -EIO; | 37 | err = -EIO; |
| 36 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 38 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 37 | err = -ENOSYS; | 39 | err = -ENOSYS; |
| 38 | else if (buf[0] == 0x0a) /* REJECTED */ | 40 | else if (buf[0] == 0x0a) /* REJECTED */ |
| 39 | err = -EINVAL; | 41 | err = -EINVAL; |
| 40 | else if (err > 0) | 42 | else |
| 41 | err = 0; | 43 | err = 0; |
| 42 | 44 | ||
| 43 | kfree(buf); | 45 | kfree(buf); |
| @@ -67,7 +69,9 @@ int avc_audio_get_selector(struct fw_unit *unit, unsigned int subunit_id, | |||
| 67 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, | 69 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, |
| 68 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | 70 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | |
| 69 | BIT(6) | BIT(8)); | 71 | BIT(6) | BIT(8)); |
| 70 | if (err > 0 && err < 9) | 72 | if (err < 0) |
| 73 | ; | ||
| 74 | else if (err < 9) | ||
| 71 | err = -EIO; | 75 | err = -EIO; |
| 72 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 76 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 73 | err = -ENOSYS; | 77 | err = -ENOSYS; |
| @@ -120,7 +124,9 @@ int avc_bridgeco_get_plug_type(struct fw_unit *unit, | |||
| 120 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, | 124 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, |
| 121 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | 125 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | |
| 122 | BIT(6) | BIT(7) | BIT(9)); | 126 | BIT(6) | BIT(7) | BIT(9)); |
| 123 | if ((err >= 0) && (err < 8)) | 127 | if (err < 0) |
| 128 | ; | ||
| 129 | else if (err < 11) | ||
| 124 | err = -EIO; | 130 | err = -EIO; |
| 125 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 131 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 126 | err = -ENOSYS; | 132 | err = -ENOSYS; |
| @@ -150,7 +156,9 @@ int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, | |||
| 150 | err = fcp_avc_transaction(unit, buf, 12, buf, 256, | 156 | err = fcp_avc_transaction(unit, buf, 12, buf, 256, |
| 151 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | | 157 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | |
| 152 | BIT(5) | BIT(6) | BIT(7) | BIT(9)); | 158 | BIT(5) | BIT(6) | BIT(7) | BIT(9)); |
| 153 | if ((err >= 0) && (err < 8)) | 159 | if (err < 0) |
| 160 | ; | ||
| 161 | else if (err < 11) | ||
| 154 | err = -EIO; | 162 | err = -EIO; |
| 155 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 163 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 156 | err = -ENOSYS; | 164 | err = -ENOSYS; |
| @@ -187,7 +195,9 @@ int avc_bridgeco_get_plug_section_type(struct fw_unit *unit, | |||
| 187 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, | 195 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, |
| 188 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | 196 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | |
| 189 | BIT(6) | BIT(7) | BIT(9) | BIT(10)); | 197 | BIT(6) | BIT(7) | BIT(9) | BIT(10)); |
| 190 | if ((err >= 0) && (err < 8)) | 198 | if (err < 0) |
| 199 | ; | ||
| 200 | else if (err < 12) | ||
| 191 | err = -EIO; | 201 | err = -EIO; |
| 192 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 202 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 193 | err = -ENOSYS; | 203 | err = -ENOSYS; |
| @@ -221,7 +231,9 @@ int avc_bridgeco_get_plug_input(struct fw_unit *unit, | |||
| 221 | err = fcp_avc_transaction(unit, buf, 16, buf, 16, | 231 | err = fcp_avc_transaction(unit, buf, 16, buf, 16, |
| 222 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | 232 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | |
| 223 | BIT(6) | BIT(7)); | 233 | BIT(6) | BIT(7)); |
| 224 | if ((err >= 0) && (err < 8)) | 234 | if (err < 0) |
| 235 | ; | ||
| 236 | else if (err < 16) | ||
| 225 | err = -EIO; | 237 | err = -EIO; |
| 226 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 238 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 227 | err = -ENOSYS; | 239 | err = -ENOSYS; |
| @@ -260,7 +272,9 @@ int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit, | |||
| 260 | err = fcp_avc_transaction(unit, buf, 12, buf, *len, | 272 | err = fcp_avc_transaction(unit, buf, 12, buf, *len, |
| 261 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | 273 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | |
| 262 | BIT(6) | BIT(7) | BIT(10)); | 274 | BIT(6) | BIT(7) | BIT(10)); |
| 263 | if ((err >= 0) && (err < 12)) | 275 | if (err < 0) |
| 276 | ; | ||
| 277 | else if (err < 12) | ||
| 264 | err = -EIO; | 278 | err = -EIO; |
| 265 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 279 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 266 | err = -ENOSYS; | 280 | err = -ENOSYS; |
diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index b3cffd01a19f..a4688545339c 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c | |||
| @@ -28,6 +28,9 @@ | |||
| 28 | */ | 28 | */ |
| 29 | #define MAX_MIDI_RX_BLOCKS 8 | 29 | #define MAX_MIDI_RX_BLOCKS 8 |
| 30 | 30 | ||
| 31 | /* 3 = MAX(DOT_MIDI_IN_PORTS, DOT_MIDI_OUT_PORTS) + 1. */ | ||
| 32 | #define MAX_MIDI_PORTS 3 | ||
| 33 | |||
| 31 | /* | 34 | /* |
| 32 | * The double-oh-three algorithm was discovered by Robin Gareus and Damien | 35 | * The double-oh-three algorithm was discovered by Robin Gareus and Damien |
| 33 | * Zammit in 2012, with reverse-engineering for Digi 003 Rack. | 36 | * Zammit in 2012, with reverse-engineering for Digi 003 Rack. |
| @@ -42,10 +45,8 @@ struct amdtp_dot { | |||
| 42 | unsigned int pcm_channels; | 45 | unsigned int pcm_channels; |
| 43 | struct dot_state state; | 46 | struct dot_state state; |
| 44 | 47 | ||
| 45 | unsigned int midi_ports; | 48 | struct snd_rawmidi_substream *midi[MAX_MIDI_PORTS]; |
| 46 | /* 2 = MAX(DOT_MIDI_IN_PORTS, DOT_MIDI_OUT_PORTS) */ | 49 | int midi_fifo_used[MAX_MIDI_PORTS]; |
| 47 | struct snd_rawmidi_substream *midi[2]; | ||
| 48 | int midi_fifo_used[2]; | ||
| 49 | int midi_fifo_limit; | 50 | int midi_fifo_limit; |
| 50 | 51 | ||
| 51 | void (*transfer_samples)(struct amdtp_stream *s, | 52 | void (*transfer_samples)(struct amdtp_stream *s, |
| @@ -124,8 +125,8 @@ int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate, | |||
| 124 | return -EBUSY; | 125 | return -EBUSY; |
| 125 | 126 | ||
| 126 | /* | 127 | /* |
| 127 | * A first data channel is for MIDI conformant data channel, the rest is | 128 | * A first data channel is for MIDI messages, the rest is Multi Bit |
| 128 | * Multi Bit Linear Audio data channel. | 129 | * Linear Audio data channel. |
| 129 | */ | 130 | */ |
| 130 | err = amdtp_stream_set_parameters(s, rate, pcm_channels + 1); | 131 | err = amdtp_stream_set_parameters(s, rate, pcm_channels + 1); |
| 131 | if (err < 0) | 132 | if (err < 0) |
| @@ -135,11 +136,6 @@ int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate, | |||
| 135 | 136 | ||
| 136 | p->pcm_channels = pcm_channels; | 137 | p->pcm_channels = pcm_channels; |
| 137 | 138 | ||
| 138 | if (s->direction == AMDTP_IN_STREAM) | ||
| 139 | p->midi_ports = DOT_MIDI_IN_PORTS; | ||
| 140 | else | ||
| 141 | p->midi_ports = DOT_MIDI_OUT_PORTS; | ||
| 142 | |||
| 143 | /* | 139 | /* |
| 144 | * We do not know the actual MIDI FIFO size of most devices. Just | 140 | * We do not know the actual MIDI FIFO size of most devices. Just |
| 145 | * assume two bytes, i.e., one byte can be received over the bus while | 141 | * assume two bytes, i.e., one byte can be received over the bus while |
| @@ -281,13 +277,25 @@ static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, | |||
| 281 | b = (u8 *)&buffer[0]; | 277 | b = (u8 *)&buffer[0]; |
| 282 | 278 | ||
| 283 | len = 0; | 279 | len = 0; |
| 284 | if (port < p->midi_ports && | 280 | if (port < MAX_MIDI_PORTS && |
| 285 | midi_ratelimit_per_packet(s, port) && | 281 | midi_ratelimit_per_packet(s, port) && |
| 286 | p->midi[port] != NULL) | 282 | p->midi[port] != NULL) |
| 287 | len = snd_rawmidi_transmit(p->midi[port], b + 1, 2); | 283 | len = snd_rawmidi_transmit(p->midi[port], b + 1, 2); |
| 288 | 284 | ||
| 289 | if (len > 0) { | 285 | if (len > 0) { |
| 290 | b[3] = (0x10 << port) | len; | 286 | /* |
| 287 | * Upper 4 bits of LSB represent port number. | ||
| 288 | * - 0000b: physical MIDI port 1. | ||
| 289 | * - 0010b: physical MIDI port 2. | ||
| 290 | * - 1110b: console MIDI port. | ||
| 291 | */ | ||
| 292 | if (port == 2) | ||
| 293 | b[3] = 0xe0; | ||
| 294 | else if (port == 1) | ||
| 295 | b[3] = 0x20; | ||
| 296 | else | ||
| 297 | b[3] = 0x00; | ||
| 298 | b[3] |= len; | ||
| 291 | midi_use_bytes(s, port, len); | 299 | midi_use_bytes(s, port, len); |
| 292 | } else { | 300 | } else { |
| 293 | b[1] = 0; | 301 | b[1] = 0; |
| @@ -309,11 +317,22 @@ static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, | |||
| 309 | 317 | ||
| 310 | for (f = 0; f < data_blocks; f++) { | 318 | for (f = 0; f < data_blocks; f++) { |
| 311 | b = (u8 *)&buffer[0]; | 319 | b = (u8 *)&buffer[0]; |
| 312 | port = b[3] >> 4; | ||
| 313 | len = b[3] & 0x0f; | ||
| 314 | 320 | ||
| 315 | if (port < p->midi_ports && p->midi[port] && len > 0) | 321 | len = b[3] & 0x0f; |
| 316 | snd_rawmidi_receive(p->midi[port], b + 1, len); | 322 | if (len > 0) { |
| 323 | /* | ||
| 324 | * Upper 4 bits of LSB represent port number. | ||
| 325 | * - 0000b: physical MIDI port 1. Use port 0. | ||
| 326 | * - 1110b: console MIDI port. Use port 2. | ||
| 327 | */ | ||
| 328 | if (b[3] >> 4 > 0) | ||
| 329 | port = 2; | ||
| 330 | else | ||
| 331 | port = 0; | ||
| 332 | |||
| 333 | if (port < MAX_MIDI_PORTS && p->midi[port]) | ||
| 334 | snd_rawmidi_receive(p->midi[port], b + 1, len); | ||
| 335 | } | ||
| 317 | 336 | ||
| 318 | buffer += s->data_block_quadlets; | 337 | buffer += s->data_block_quadlets; |
| 319 | } | 338 | } |
| @@ -364,7 +383,7 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, | |||
| 364 | { | 383 | { |
| 365 | struct amdtp_dot *p = s->protocol; | 384 | struct amdtp_dot *p = s->protocol; |
| 366 | 385 | ||
| 367 | if (port < p->midi_ports) | 386 | if (port < MAX_MIDI_PORTS) |
| 368 | ACCESS_ONCE(p->midi[port]) = midi; | 387 | ACCESS_ONCE(p->midi[port]) = midi; |
| 369 | } | 388 | } |
| 370 | 389 | ||
diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c index 915d2a21223e..7ab3d0810f6b 100644 --- a/sound/firewire/digi00x/digi00x-midi.c +++ b/sound/firewire/digi00x/digi00x-midi.c | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | #include "digi00x.h" | 9 | #include "digi00x.h" |
| 10 | 10 | ||
| 11 | static int midi_phys_open(struct snd_rawmidi_substream *substream) | 11 | static int midi_open(struct snd_rawmidi_substream *substream) |
| 12 | { | 12 | { |
| 13 | struct snd_dg00x *dg00x = substream->rmidi->private_data; | 13 | struct snd_dg00x *dg00x = substream->rmidi->private_data; |
| 14 | int err; | 14 | int err; |
| @@ -27,7 +27,7 @@ static int midi_phys_open(struct snd_rawmidi_substream *substream) | |||
| 27 | return err; | 27 | return err; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | static int midi_phys_close(struct snd_rawmidi_substream *substream) | 30 | static int midi_close(struct snd_rawmidi_substream *substream) |
| 31 | { | 31 | { |
| 32 | struct snd_dg00x *dg00x = substream->rmidi->private_data; | 32 | struct snd_dg00x *dg00x = substream->rmidi->private_data; |
| 33 | 33 | ||
| @@ -40,180 +40,130 @@ static int midi_phys_close(struct snd_rawmidi_substream *substream) | |||
| 40 | return 0; | 40 | return 0; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | static void midi_phys_capture_trigger(struct snd_rawmidi_substream *substream, | 43 | static void midi_capture_trigger(struct snd_rawmidi_substream *substream, |
| 44 | int up) | 44 | int up) |
| 45 | { | 45 | { |
| 46 | struct snd_dg00x *dg00x = substream->rmidi->private_data; | 46 | struct snd_dg00x *dg00x = substream->rmidi->private_data; |
| 47 | unsigned int port; | ||
| 47 | unsigned long flags; | 48 | unsigned long flags; |
| 48 | 49 | ||
| 49 | spin_lock_irqsave(&dg00x->lock, flags); | 50 | if (substream->rmidi->device == 0) |
| 50 | 51 | port = substream->number; | |
| 51 | if (up) | ||
| 52 | amdtp_dot_midi_trigger(&dg00x->tx_stream, substream->number, | ||
| 53 | substream); | ||
| 54 | else | 52 | else |
| 55 | amdtp_dot_midi_trigger(&dg00x->tx_stream, substream->number, | 53 | port = 2; |
| 56 | NULL); | ||
| 57 | |||
| 58 | spin_unlock_irqrestore(&dg00x->lock, flags); | ||
| 59 | } | ||
| 60 | |||
| 61 | static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream, | ||
| 62 | int up) | ||
| 63 | { | ||
| 64 | struct snd_dg00x *dg00x = substream->rmidi->private_data; | ||
| 65 | unsigned long flags; | ||
| 66 | 54 | ||
| 67 | spin_lock_irqsave(&dg00x->lock, flags); | 55 | spin_lock_irqsave(&dg00x->lock, flags); |
| 68 | 56 | ||
| 69 | if (up) | 57 | if (up) |
| 70 | amdtp_dot_midi_trigger(&dg00x->rx_stream, substream->number, | 58 | amdtp_dot_midi_trigger(&dg00x->tx_stream, port, substream); |
| 71 | substream); | ||
| 72 | else | 59 | else |
| 73 | amdtp_dot_midi_trigger(&dg00x->rx_stream, substream->number, | 60 | amdtp_dot_midi_trigger(&dg00x->tx_stream, port, NULL); |
| 74 | NULL); | ||
| 75 | 61 | ||
| 76 | spin_unlock_irqrestore(&dg00x->lock, flags); | 62 | spin_unlock_irqrestore(&dg00x->lock, flags); |
| 77 | } | 63 | } |
| 78 | 64 | ||
| 79 | static int midi_ctl_open(struct snd_rawmidi_substream *substream) | 65 | static void midi_playback_trigger(struct snd_rawmidi_substream *substream, |
| 80 | { | 66 | int up) |
| 81 | /* Do nothing. */ | ||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | static int midi_ctl_capture_close(struct snd_rawmidi_substream *substream) | ||
| 86 | { | ||
| 87 | /* Do nothing. */ | ||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | static int midi_ctl_playback_close(struct snd_rawmidi_substream *substream) | ||
| 92 | { | ||
| 93 | struct snd_dg00x *dg00x = substream->rmidi->private_data; | ||
| 94 | |||
| 95 | snd_fw_async_midi_port_finish(&dg00x->out_control); | ||
| 96 | |||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | static void midi_ctl_capture_trigger(struct snd_rawmidi_substream *substream, | ||
| 101 | int up) | ||
| 102 | { | 67 | { |
| 103 | struct snd_dg00x *dg00x = substream->rmidi->private_data; | 68 | struct snd_dg00x *dg00x = substream->rmidi->private_data; |
| 69 | unsigned int port; | ||
| 104 | unsigned long flags; | 70 | unsigned long flags; |
| 105 | 71 | ||
| 106 | spin_lock_irqsave(&dg00x->lock, flags); | 72 | if (substream->rmidi->device == 0) |
| 107 | 73 | port = substream->number; | |
| 108 | if (up) | ||
| 109 | dg00x->in_control = substream; | ||
| 110 | else | 74 | else |
| 111 | dg00x->in_control = NULL; | 75 | port = 2; |
| 112 | |||
| 113 | spin_unlock_irqrestore(&dg00x->lock, flags); | ||
| 114 | } | ||
| 115 | |||
| 116 | static void midi_ctl_playback_trigger(struct snd_rawmidi_substream *substream, | ||
| 117 | int up) | ||
| 118 | { | ||
| 119 | struct snd_dg00x *dg00x = substream->rmidi->private_data; | ||
| 120 | unsigned long flags; | ||
| 121 | 76 | ||
| 122 | spin_lock_irqsave(&dg00x->lock, flags); | 77 | spin_lock_irqsave(&dg00x->lock, flags); |
| 123 | 78 | ||
| 124 | if (up) | 79 | if (up) |
| 125 | snd_fw_async_midi_port_run(&dg00x->out_control, substream); | 80 | amdtp_dot_midi_trigger(&dg00x->rx_stream, port, substream); |
| 81 | else | ||
| 82 | amdtp_dot_midi_trigger(&dg00x->rx_stream, port, NULL); | ||
| 126 | 83 | ||
| 127 | spin_unlock_irqrestore(&dg00x->lock, flags); | 84 | spin_unlock_irqrestore(&dg00x->lock, flags); |
| 128 | } | 85 | } |
| 129 | 86 | ||
| 130 | static void set_midi_substream_names(struct snd_dg00x *dg00x, | 87 | static void set_substream_names(struct snd_dg00x *dg00x, |
| 131 | struct snd_rawmidi_str *str, | 88 | struct snd_rawmidi *rmidi, bool is_console) |
| 132 | bool is_ctl) | ||
| 133 | { | 89 | { |
| 134 | struct snd_rawmidi_substream *subs; | 90 | struct snd_rawmidi_substream *subs; |
| 135 | 91 | struct snd_rawmidi_str *str; | |
| 136 | list_for_each_entry(subs, &str->substreams, list) { | 92 | int i; |
| 137 | if (!is_ctl) | 93 | |
| 138 | snprintf(subs->name, sizeof(subs->name), | 94 | for (i = 0; i < 2; ++i) { |
| 139 | "%s MIDI %d", | 95 | str = &rmidi->streams[i]; |
| 140 | dg00x->card->shortname, subs->number + 1); | 96 | |
| 141 | else | 97 | list_for_each_entry(subs, &str->substreams, list) { |
| 142 | /* This port is for asynchronous transaction. */ | 98 | if (!is_console) { |
| 143 | snprintf(subs->name, sizeof(subs->name), | 99 | snprintf(subs->name, sizeof(subs->name), |
| 144 | "%s control", | 100 | "%s MIDI %d", |
| 145 | dg00x->card->shortname); | 101 | dg00x->card->shortname, |
| 102 | subs->number + 1); | ||
| 103 | } else { | ||
| 104 | snprintf(subs->name, sizeof(subs->name), | ||
| 105 | "%s control", | ||
| 106 | dg00x->card->shortname); | ||
| 107 | } | ||
| 108 | } | ||
| 146 | } | 109 | } |
| 147 | } | 110 | } |
| 148 | 111 | ||
| 149 | int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x) | 112 | static int add_substream_pair(struct snd_dg00x *dg00x, unsigned int out_ports, |
| 113 | unsigned int in_ports, bool is_console) | ||
| 150 | { | 114 | { |
| 151 | static const struct snd_rawmidi_ops phys_capture_ops = { | 115 | static const struct snd_rawmidi_ops capture_ops = { |
| 152 | .open = midi_phys_open, | 116 | .open = midi_open, |
| 153 | .close = midi_phys_close, | 117 | .close = midi_close, |
| 154 | .trigger = midi_phys_capture_trigger, | 118 | .trigger = midi_capture_trigger, |
| 155 | }; | ||
| 156 | static const struct snd_rawmidi_ops phys_playback_ops = { | ||
| 157 | .open = midi_phys_open, | ||
| 158 | .close = midi_phys_close, | ||
| 159 | .trigger = midi_phys_playback_trigger, | ||
| 160 | }; | 119 | }; |
| 161 | static const struct snd_rawmidi_ops ctl_capture_ops = { | 120 | static const struct snd_rawmidi_ops playback_ops = { |
| 162 | .open = midi_ctl_open, | 121 | .open = midi_open, |
| 163 | .close = midi_ctl_capture_close, | 122 | .close = midi_close, |
| 164 | .trigger = midi_ctl_capture_trigger, | 123 | .trigger = midi_playback_trigger, |
| 165 | }; | 124 | }; |
| 166 | static const struct snd_rawmidi_ops ctl_playback_ops = { | 125 | const char *label; |
| 167 | .open = midi_ctl_open, | 126 | struct snd_rawmidi *rmidi; |
| 168 | .close = midi_ctl_playback_close, | ||
| 169 | .trigger = midi_ctl_playback_trigger, | ||
| 170 | }; | ||
| 171 | struct snd_rawmidi *rmidi[2]; | ||
| 172 | struct snd_rawmidi_str *str; | ||
| 173 | unsigned int i; | ||
| 174 | int err; | 127 | int err; |
| 175 | 128 | ||
| 176 | /* Add physical midi ports. */ | 129 | /* Add physical midi ports. */ |
| 177 | err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 0, | 130 | err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, is_console, |
| 178 | DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS, &rmidi[0]); | 131 | out_ports, in_ports, &rmidi); |
| 179 | if (err < 0) | 132 | if (err < 0) |
| 180 | return err; | 133 | return err; |
| 134 | rmidi->private_data = dg00x; | ||
| 181 | 135 | ||
| 182 | snprintf(rmidi[0]->name, sizeof(rmidi[0]->name), | 136 | if (!is_console) |
| 183 | "%s MIDI", dg00x->card->shortname); | 137 | label = "%s control"; |
| 184 | 138 | else | |
| 185 | snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_INPUT, | 139 | label = "%s MIDI"; |
| 186 | &phys_capture_ops); | 140 | snprintf(rmidi->name, sizeof(rmidi->name), label, |
| 187 | snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_OUTPUT, | 141 | dg00x->card->shortname); |
| 188 | &phys_playback_ops); | ||
| 189 | 142 | ||
| 190 | /* Add a pair of control midi ports. */ | 143 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &playback_ops); |
| 191 | err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 1, | 144 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &capture_ops); |
| 192 | 1, 1, &rmidi[1]); | ||
| 193 | if (err < 0) | ||
| 194 | return err; | ||
| 195 | 145 | ||
| 196 | snprintf(rmidi[1]->name, sizeof(rmidi[1]->name), | 146 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT | |
| 197 | "%s control", dg00x->card->shortname); | 147 | SNDRV_RAWMIDI_INFO_OUTPUT | |
| 148 | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
| 198 | 149 | ||
| 199 | snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_INPUT, | 150 | set_substream_names(dg00x, rmidi, is_console); |
| 200 | &ctl_capture_ops); | ||
| 201 | snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
| 202 | &ctl_playback_ops); | ||
| 203 | 151 | ||
| 204 | for (i = 0; i < ARRAY_SIZE(rmidi); i++) { | 152 | return 0; |
| 205 | rmidi[i]->private_data = dg00x; | 153 | } |
| 206 | 154 | ||
| 207 | rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; | 155 | int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x) |
| 208 | str = &rmidi[i]->streams[SNDRV_RAWMIDI_STREAM_INPUT]; | 156 | { |
| 209 | set_midi_substream_names(dg00x, str, i); | 157 | int err; |
| 210 | 158 | ||
| 211 | rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; | 159 | /* Add physical midi ports. */ |
| 212 | str = &rmidi[i]->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; | 160 | err = add_substream_pair(dg00x, DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS, |
| 213 | set_midi_substream_names(dg00x, str, i); | 161 | false); |
| 162 | if (err < 0) | ||
| 163 | return err; | ||
| 214 | 164 | ||
| 215 | rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; | 165 | if (dg00x->is_console) |
| 216 | } | 166 | err = add_substream_pair(dg00x, 1, 1, true); |
| 217 | 167 | ||
| 218 | return 0; | 168 | return err; |
| 219 | } | 169 | } |
diff --git a/sound/firewire/digi00x/digi00x-transaction.c b/sound/firewire/digi00x/digi00x-transaction.c index 735d35640807..af9bc8504781 100644 --- a/sound/firewire/digi00x/digi00x-transaction.c +++ b/sound/firewire/digi00x/digi00x-transaction.c | |||
| @@ -9,40 +9,6 @@ | |||
| 9 | #include <sound/asound.h> | 9 | #include <sound/asound.h> |
| 10 | #include "digi00x.h" | 10 | #include "digi00x.h" |
| 11 | 11 | ||
| 12 | static int fill_midi_message(struct snd_rawmidi_substream *substream, u8 *buf) | ||
| 13 | { | ||
| 14 | int bytes; | ||
| 15 | |||
| 16 | buf[0] = 0x80; | ||
| 17 | bytes = snd_rawmidi_transmit_peek(substream, buf + 1, 2); | ||
| 18 | if (bytes >= 0) | ||
| 19 | buf[3] = 0xc0 | bytes; | ||
| 20 | |||
| 21 | return bytes; | ||
| 22 | } | ||
| 23 | |||
| 24 | static void handle_midi_control(struct snd_dg00x *dg00x, __be32 *buf, | ||
| 25 | unsigned int length) | ||
| 26 | { | ||
| 27 | struct snd_rawmidi_substream *substream; | ||
| 28 | unsigned int i; | ||
| 29 | unsigned int len; | ||
| 30 | u8 *b; | ||
| 31 | |||
| 32 | substream = ACCESS_ONCE(dg00x->in_control); | ||
| 33 | if (substream == NULL) | ||
| 34 | return; | ||
| 35 | |||
| 36 | length /= 4; | ||
| 37 | |||
| 38 | for (i = 0; i < length; i++) { | ||
| 39 | b = (u8 *)&buf[i]; | ||
| 40 | len = b[3] & 0xf; | ||
| 41 | if (len > 0) | ||
| 42 | snd_rawmidi_receive(dg00x->in_control, b + 1, len); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | static void handle_unknown_message(struct snd_dg00x *dg00x, | 12 | static void handle_unknown_message(struct snd_dg00x *dg00x, |
| 47 | unsigned long long offset, __be32 *buf) | 13 | unsigned long long offset, __be32 *buf) |
| 48 | { | 14 | { |
| @@ -63,39 +29,36 @@ static void handle_message(struct fw_card *card, struct fw_request *request, | |||
| 63 | struct snd_dg00x *dg00x = callback_data; | 29 | struct snd_dg00x *dg00x = callback_data; |
| 64 | __be32 *buf = (__be32 *)data; | 30 | __be32 *buf = (__be32 *)data; |
| 65 | 31 | ||
| 32 | fw_send_response(card, request, RCODE_COMPLETE); | ||
| 33 | |||
| 66 | if (offset == dg00x->async_handler.offset) | 34 | if (offset == dg00x->async_handler.offset) |
| 67 | handle_unknown_message(dg00x, offset, buf); | 35 | handle_unknown_message(dg00x, offset, buf); |
| 68 | else if (offset == dg00x->async_handler.offset + 4) | ||
| 69 | handle_midi_control(dg00x, buf, length); | ||
| 70 | |||
| 71 | fw_send_response(card, request, RCODE_COMPLETE); | ||
| 72 | } | 36 | } |
| 73 | 37 | ||
| 74 | int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x) | 38 | int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x) |
| 75 | { | 39 | { |
| 76 | struct fw_device *device = fw_parent_device(dg00x->unit); | 40 | struct fw_device *device = fw_parent_device(dg00x->unit); |
| 77 | __be32 data[2]; | 41 | __be32 data[2]; |
| 78 | int err; | ||
| 79 | 42 | ||
| 80 | /* Unknown. 4bytes. */ | 43 | /* Unknown. 4bytes. */ |
| 81 | data[0] = cpu_to_be32((device->card->node_id << 16) | | 44 | data[0] = cpu_to_be32((device->card->node_id << 16) | |
| 82 | (dg00x->async_handler.offset >> 32)); | 45 | (dg00x->async_handler.offset >> 32)); |
| 83 | data[1] = cpu_to_be32(dg00x->async_handler.offset); | 46 | data[1] = cpu_to_be32(dg00x->async_handler.offset); |
| 84 | err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST, | ||
| 85 | DG00X_ADDR_BASE + DG00X_OFFSET_MESSAGE_ADDR, | ||
| 86 | &data, sizeof(data), 0); | ||
| 87 | if (err < 0) | ||
| 88 | return err; | ||
| 89 | |||
| 90 | /* Asynchronous transactions for MIDI control message. */ | ||
| 91 | data[0] = cpu_to_be32((device->card->node_id << 16) | | ||
| 92 | (dg00x->async_handler.offset >> 32)); | ||
| 93 | data[1] = cpu_to_be32(dg00x->async_handler.offset + 4); | ||
| 94 | return snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST, | 47 | return snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST, |
| 95 | DG00X_ADDR_BASE + DG00X_OFFSET_MIDI_CTL_ADDR, | 48 | DG00X_ADDR_BASE + DG00X_OFFSET_MESSAGE_ADDR, |
| 96 | &data, sizeof(data), 0); | 49 | &data, sizeof(data), 0); |
| 97 | } | 50 | } |
| 98 | 51 | ||
| 52 | void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x) | ||
| 53 | { | ||
| 54 | if (dg00x->async_handler.callback_data == NULL) | ||
| 55 | return; | ||
| 56 | |||
| 57 | fw_core_remove_address_handler(&dg00x->async_handler); | ||
| 58 | |||
| 59 | dg00x->async_handler.callback_data = NULL; | ||
| 60 | } | ||
| 61 | |||
| 99 | int snd_dg00x_transaction_register(struct snd_dg00x *dg00x) | 62 | int snd_dg00x_transaction_register(struct snd_dg00x *dg00x) |
| 100 | { | 63 | { |
| 101 | static const struct fw_address_region resp_register_region = { | 64 | static const struct fw_address_region resp_register_region = { |
| @@ -104,7 +67,7 @@ int snd_dg00x_transaction_register(struct snd_dg00x *dg00x) | |||
| 104 | }; | 67 | }; |
| 105 | int err; | 68 | int err; |
| 106 | 69 | ||
| 107 | dg00x->async_handler.length = 12; | 70 | dg00x->async_handler.length = 4; |
| 108 | dg00x->async_handler.address_callback = handle_message; | 71 | dg00x->async_handler.address_callback = handle_message; |
| 109 | dg00x->async_handler.callback_data = dg00x; | 72 | dg00x->async_handler.callback_data = dg00x; |
| 110 | 73 | ||
| @@ -115,28 +78,7 @@ int snd_dg00x_transaction_register(struct snd_dg00x *dg00x) | |||
| 115 | 78 | ||
| 116 | err = snd_dg00x_transaction_reregister(dg00x); | 79 | err = snd_dg00x_transaction_reregister(dg00x); |
| 117 | if (err < 0) | 80 | if (err < 0) |
| 118 | goto error; | 81 | snd_dg00x_transaction_unregister(dg00x); |
| 119 | |||
| 120 | err = snd_fw_async_midi_port_init(&dg00x->out_control, dg00x->unit, | ||
| 121 | DG00X_ADDR_BASE + DG00X_OFFSET_MMC, | ||
| 122 | 4, fill_midi_message); | ||
| 123 | if (err < 0) | ||
| 124 | goto error; | ||
| 125 | 82 | ||
| 126 | return err; | 83 | return err; |
| 127 | error: | ||
| 128 | fw_core_remove_address_handler(&dg00x->async_handler); | ||
| 129 | dg00x->async_handler.callback_data = NULL; | ||
| 130 | return err; | ||
| 131 | } | ||
| 132 | |||
| 133 | void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x) | ||
| 134 | { | ||
| 135 | if (dg00x->async_handler.callback_data == NULL) | ||
| 136 | return; | ||
| 137 | |||
| 138 | snd_fw_async_midi_port_destroy(&dg00x->out_control); | ||
| 139 | fw_core_remove_address_handler(&dg00x->async_handler); | ||
| 140 | |||
| 141 | dg00x->async_handler.callback_data = NULL; | ||
| 142 | } | 84 | } |
diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index cc4776c6ded3..1f5e1d23f31a 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c | |||
| @@ -13,7 +13,8 @@ MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>"); | |||
| 13 | MODULE_LICENSE("GPL v2"); | 13 | MODULE_LICENSE("GPL v2"); |
| 14 | 14 | ||
| 15 | #define VENDOR_DIGIDESIGN 0x00a07e | 15 | #define VENDOR_DIGIDESIGN 0x00a07e |
| 16 | #define MODEL_DIGI00X 0x000002 | 16 | #define MODEL_CONSOLE 0x000001 |
| 17 | #define MODEL_RACK 0x000002 | ||
| 17 | 18 | ||
| 18 | static int name_card(struct snd_dg00x *dg00x) | 19 | static int name_card(struct snd_dg00x *dg00x) |
| 19 | { | 20 | { |
| @@ -129,6 +130,8 @@ static int snd_dg00x_probe(struct fw_unit *unit, | |||
| 129 | spin_lock_init(&dg00x->lock); | 130 | spin_lock_init(&dg00x->lock); |
| 130 | init_waitqueue_head(&dg00x->hwdep_wait); | 131 | init_waitqueue_head(&dg00x->hwdep_wait); |
| 131 | 132 | ||
| 133 | dg00x->is_console = entry->model_id == MODEL_CONSOLE; | ||
| 134 | |||
| 132 | /* Allocate and register this sound card later. */ | 135 | /* Allocate and register this sound card later. */ |
| 133 | INIT_DEFERRABLE_WORK(&dg00x->dwork, do_registration); | 136 | INIT_DEFERRABLE_WORK(&dg00x->dwork, do_registration); |
| 134 | snd_fw_schedule_registration(unit, &dg00x->dwork); | 137 | snd_fw_schedule_registration(unit, &dg00x->dwork); |
| @@ -183,7 +186,13 @@ static const struct ieee1394_device_id snd_dg00x_id_table[] = { | |||
| 183 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | 186 | .match_flags = IEEE1394_MATCH_VENDOR_ID | |
| 184 | IEEE1394_MATCH_MODEL_ID, | 187 | IEEE1394_MATCH_MODEL_ID, |
| 185 | .vendor_id = VENDOR_DIGIDESIGN, | 188 | .vendor_id = VENDOR_DIGIDESIGN, |
| 186 | .model_id = MODEL_DIGI00X, | 189 | .model_id = MODEL_CONSOLE, |
| 190 | }, | ||
| 191 | { | ||
| 192 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
| 193 | IEEE1394_MATCH_MODEL_ID, | ||
| 194 | .vendor_id = VENDOR_DIGIDESIGN, | ||
| 195 | .model_id = MODEL_RACK, | ||
| 187 | }, | 196 | }, |
| 188 | {} | 197 | {} |
| 189 | }; | 198 | }; |
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index 9dc761bdacca..1275a50956c0 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h | |||
| @@ -58,16 +58,15 @@ struct snd_dg00x { | |||
| 58 | struct fw_address_handler async_handler; | 58 | struct fw_address_handler async_handler; |
| 59 | u32 msg; | 59 | u32 msg; |
| 60 | 60 | ||
| 61 | /* For asynchronous MIDI controls. */ | 61 | /* Console models have additional MIDI ports for control surface. */ |
| 62 | struct snd_rawmidi_substream *in_control; | 62 | bool is_console; |
| 63 | struct snd_fw_async_midi_port out_control; | ||
| 64 | }; | 63 | }; |
| 65 | 64 | ||
| 66 | #define DG00X_ADDR_BASE 0xffffe0000000ull | 65 | #define DG00X_ADDR_BASE 0xffffe0000000ull |
| 67 | 66 | ||
| 68 | #define DG00X_OFFSET_STREAMING_STATE 0x0000 | 67 | #define DG00X_OFFSET_STREAMING_STATE 0x0000 |
| 69 | #define DG00X_OFFSET_STREAMING_SET 0x0004 | 68 | #define DG00X_OFFSET_STREAMING_SET 0x0004 |
| 70 | #define DG00X_OFFSET_MIDI_CTL_ADDR 0x0008 | 69 | /* unknown but address in host space 0x0008 */ |
| 71 | /* For LSB of the address 0x000c */ | 70 | /* For LSB of the address 0x000c */ |
| 72 | /* unknown 0x0010 */ | 71 | /* unknown 0x0010 */ |
| 73 | #define DG00X_OFFSET_MESSAGE_ADDR 0x0014 | 72 | #define DG00X_OFFSET_MESSAGE_ADDR 0x0014 |
diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c index cce19768f43d..61dda828f767 100644 --- a/sound/firewire/fcp.c +++ b/sound/firewire/fcp.c | |||
| @@ -63,7 +63,9 @@ int avc_general_set_sig_fmt(struct fw_unit *unit, unsigned int rate, | |||
| 63 | /* do transaction and check buf[1-5] are the same against command */ | 63 | /* do transaction and check buf[1-5] are the same against command */ |
| 64 | err = fcp_avc_transaction(unit, buf, 8, buf, 8, | 64 | err = fcp_avc_transaction(unit, buf, 8, buf, 8, |
| 65 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)); | 65 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)); |
| 66 | if (err >= 0 && err < 8) | 66 | if (err < 0) |
| 67 | ; | ||
| 68 | else if (err < 8) | ||
| 67 | err = -EIO; | 69 | err = -EIO; |
| 68 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 70 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 69 | err = -ENOSYS; | 71 | err = -ENOSYS; |
| @@ -106,7 +108,9 @@ int avc_general_get_sig_fmt(struct fw_unit *unit, unsigned int *rate, | |||
| 106 | /* do transaction and check buf[1-4] are the same against command */ | 108 | /* do transaction and check buf[1-4] are the same against command */ |
| 107 | err = fcp_avc_transaction(unit, buf, 8, buf, 8, | 109 | err = fcp_avc_transaction(unit, buf, 8, buf, 8, |
| 108 | BIT(1) | BIT(2) | BIT(3) | BIT(4)); | 110 | BIT(1) | BIT(2) | BIT(3) | BIT(4)); |
| 109 | if (err >= 0 && err < 8) | 111 | if (err < 0) |
| 112 | ; | ||
| 113 | else if (err < 8) | ||
| 110 | err = -EIO; | 114 | err = -EIO; |
| 111 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 115 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 112 | err = -ENOSYS; | 116 | err = -ENOSYS; |
| @@ -154,7 +158,9 @@ int avc_general_get_plug_info(struct fw_unit *unit, unsigned int subunit_type, | |||
| 154 | buf[3] = 0xff & subfunction; | 158 | buf[3] = 0xff & subfunction; |
| 155 | 159 | ||
| 156 | err = fcp_avc_transaction(unit, buf, 8, buf, 8, BIT(1) | BIT(2)); | 160 | err = fcp_avc_transaction(unit, buf, 8, buf, 8, BIT(1) | BIT(2)); |
| 157 | if (err >= 0 && err < 8) | 161 | if (err < 0) |
| 162 | ; | ||
| 163 | else if (err < 8) | ||
| 158 | err = -EIO; | 164 | err = -EIO; |
| 159 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 165 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 160 | err = -ENOSYS; | 166 | err = -ENOSYS; |
diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile new file mode 100644 index 000000000000..8f807284ba54 --- /dev/null +++ b/sound/firewire/fireface/Makefile | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \ | ||
| 2 | ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o | ||
| 3 | obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o | ||
diff --git a/sound/firewire/fireface/amdtp-ff.c b/sound/firewire/fireface/amdtp-ff.c new file mode 100644 index 000000000000..780da9deb2f0 --- /dev/null +++ b/sound/firewire/fireface/amdtp-ff.c | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | /* | ||
| 2 | * amdtp-ff.c - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <sound/pcm.h> | ||
| 10 | #include "ff.h" | ||
| 11 | |||
| 12 | struct amdtp_ff { | ||
| 13 | unsigned int pcm_channels; | ||
| 14 | }; | ||
| 15 | |||
| 16 | int amdtp_ff_set_parameters(struct amdtp_stream *s, unsigned int rate, | ||
| 17 | unsigned int pcm_channels) | ||
| 18 | { | ||
| 19 | struct amdtp_ff *p = s->protocol; | ||
| 20 | unsigned int data_channels; | ||
| 21 | |||
| 22 | if (amdtp_stream_running(s)) | ||
| 23 | return -EBUSY; | ||
| 24 | |||
| 25 | p->pcm_channels = pcm_channels; | ||
| 26 | data_channels = pcm_channels; | ||
| 27 | |||
| 28 | return amdtp_stream_set_parameters(s, rate, data_channels); | ||
| 29 | } | ||
| 30 | |||
| 31 | static void write_pcm_s32(struct amdtp_stream *s, | ||
| 32 | struct snd_pcm_substream *pcm, | ||
| 33 | __le32 *buffer, unsigned int frames) | ||
| 34 | { | ||
| 35 | struct amdtp_ff *p = s->protocol; | ||
| 36 | struct snd_pcm_runtime *runtime = pcm->runtime; | ||
| 37 | unsigned int channels, remaining_frames, i, c; | ||
| 38 | const u32 *src; | ||
| 39 | |||
| 40 | channels = p->pcm_channels; | ||
| 41 | src = (void *)runtime->dma_area + | ||
| 42 | frames_to_bytes(runtime, s->pcm_buffer_pointer); | ||
| 43 | remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; | ||
| 44 | |||
| 45 | for (i = 0; i < frames; ++i) { | ||
| 46 | for (c = 0; c < channels; ++c) { | ||
| 47 | buffer[c] = cpu_to_le32(*src); | ||
| 48 | src++; | ||
| 49 | } | ||
| 50 | buffer += s->data_block_quadlets; | ||
| 51 | if (--remaining_frames == 0) | ||
| 52 | src = (void *)runtime->dma_area; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | static void read_pcm_s32(struct amdtp_stream *s, | ||
| 57 | struct snd_pcm_substream *pcm, | ||
| 58 | __le32 *buffer, unsigned int frames) | ||
| 59 | { | ||
| 60 | struct amdtp_ff *p = s->protocol; | ||
| 61 | struct snd_pcm_runtime *runtime = pcm->runtime; | ||
| 62 | unsigned int channels, remaining_frames, i, c; | ||
| 63 | u32 *dst; | ||
| 64 | |||
| 65 | channels = p->pcm_channels; | ||
| 66 | dst = (void *)runtime->dma_area + | ||
| 67 | frames_to_bytes(runtime, s->pcm_buffer_pointer); | ||
| 68 | remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; | ||
| 69 | |||
| 70 | for (i = 0; i < frames; ++i) { | ||
| 71 | for (c = 0; c < channels; ++c) { | ||
| 72 | *dst = le32_to_cpu(buffer[c]) & 0xffffff00; | ||
| 73 | dst++; | ||
| 74 | } | ||
| 75 | buffer += s->data_block_quadlets; | ||
| 76 | if (--remaining_frames == 0) | ||
| 77 | dst = (void *)runtime->dma_area; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | static void write_pcm_silence(struct amdtp_stream *s, | ||
| 82 | __le32 *buffer, unsigned int frames) | ||
| 83 | { | ||
| 84 | struct amdtp_ff *p = s->protocol; | ||
| 85 | unsigned int i, c, channels = p->pcm_channels; | ||
| 86 | |||
| 87 | for (i = 0; i < frames; ++i) { | ||
| 88 | for (c = 0; c < channels; ++c) | ||
| 89 | buffer[c] = cpu_to_le32(0x00000000); | ||
| 90 | buffer += s->data_block_quadlets; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s, | ||
| 95 | struct snd_pcm_runtime *runtime) | ||
| 96 | { | ||
| 97 | int err; | ||
| 98 | |||
| 99 | err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | ||
| 100 | if (err < 0) | ||
| 101 | return err; | ||
| 102 | |||
| 103 | return amdtp_stream_add_pcm_hw_constraints(s, runtime); | ||
| 104 | } | ||
| 105 | |||
| 106 | static unsigned int process_rx_data_blocks(struct amdtp_stream *s, | ||
| 107 | __be32 *buffer, | ||
| 108 | unsigned int data_blocks, | ||
| 109 | unsigned int *syt) | ||
| 110 | { | ||
| 111 | struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); | ||
| 112 | unsigned int pcm_frames; | ||
| 113 | |||
| 114 | if (pcm) { | ||
| 115 | write_pcm_s32(s, pcm, (__le32 *)buffer, data_blocks); | ||
| 116 | pcm_frames = data_blocks; | ||
| 117 | } else { | ||
| 118 | write_pcm_silence(s, (__le32 *)buffer, data_blocks); | ||
| 119 | pcm_frames = 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | return pcm_frames; | ||
| 123 | } | ||
| 124 | |||
| 125 | static unsigned int process_tx_data_blocks(struct amdtp_stream *s, | ||
| 126 | __be32 *buffer, | ||
| 127 | unsigned int data_blocks, | ||
| 128 | unsigned int *syt) | ||
| 129 | { | ||
| 130 | struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); | ||
| 131 | unsigned int pcm_frames; | ||
| 132 | |||
| 133 | if (pcm) { | ||
| 134 | read_pcm_s32(s, pcm, (__le32 *)buffer, data_blocks); | ||
| 135 | pcm_frames = data_blocks; | ||
| 136 | } else { | ||
| 137 | pcm_frames = 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | return pcm_frames; | ||
| 141 | } | ||
| 142 | |||
| 143 | int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit, | ||
| 144 | enum amdtp_stream_direction dir) | ||
| 145 | { | ||
| 146 | amdtp_stream_process_data_blocks_t process_data_blocks; | ||
| 147 | |||
| 148 | if (dir == AMDTP_IN_STREAM) | ||
| 149 | process_data_blocks = process_tx_data_blocks; | ||
| 150 | else | ||
| 151 | process_data_blocks = process_rx_data_blocks; | ||
| 152 | |||
| 153 | return amdtp_stream_init(s, unit, dir, CIP_NO_HEADER, 0, | ||
| 154 | process_data_blocks, sizeof(struct amdtp_ff)); | ||
| 155 | } | ||
diff --git a/sound/firewire/fireface/ff-hwdep.c b/sound/firewire/fireface/ff-hwdep.c new file mode 100644 index 000000000000..3ee04b054585 --- /dev/null +++ b/sound/firewire/fireface/ff-hwdep.c | |||
| @@ -0,0 +1,191 @@ | |||
| 1 | /* | ||
| 2 | * ff-hwdep.c - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | * This codes give three functionality. | ||
| 11 | * | ||
| 12 | * 1.get firewire node information | ||
| 13 | * 2.get notification about starting/stopping stream | ||
| 14 | * 3.lock/unlock stream | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "ff.h" | ||
| 18 | |||
| 19 | static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, | ||
| 20 | loff_t *offset) | ||
| 21 | { | ||
| 22 | struct snd_ff *ff = hwdep->private_data; | ||
| 23 | DEFINE_WAIT(wait); | ||
| 24 | union snd_firewire_event event; | ||
| 25 | |||
| 26 | spin_lock_irq(&ff->lock); | ||
| 27 | |||
| 28 | while (!ff->dev_lock_changed) { | ||
| 29 | prepare_to_wait(&ff->hwdep_wait, &wait, TASK_INTERRUPTIBLE); | ||
| 30 | spin_unlock_irq(&ff->lock); | ||
| 31 | schedule(); | ||
| 32 | finish_wait(&ff->hwdep_wait, &wait); | ||
| 33 | if (signal_pending(current)) | ||
| 34 | return -ERESTARTSYS; | ||
| 35 | spin_lock_irq(&ff->lock); | ||
| 36 | } | ||
| 37 | |||
| 38 | memset(&event, 0, sizeof(event)); | ||
| 39 | if (ff->dev_lock_changed) { | ||
| 40 | event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; | ||
| 41 | event.lock_status.status = (ff->dev_lock_count > 0); | ||
| 42 | ff->dev_lock_changed = false; | ||
| 43 | |||
| 44 | count = min_t(long, count, sizeof(event.lock_status)); | ||
| 45 | } | ||
| 46 | |||
| 47 | spin_unlock_irq(&ff->lock); | ||
| 48 | |||
| 49 | if (copy_to_user(buf, &event, count)) | ||
| 50 | return -EFAULT; | ||
| 51 | |||
| 52 | return count; | ||
| 53 | } | ||
| 54 | |||
| 55 | static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file, | ||
| 56 | poll_table *wait) | ||
| 57 | { | ||
| 58 | struct snd_ff *ff = hwdep->private_data; | ||
| 59 | unsigned int events; | ||
| 60 | |||
| 61 | poll_wait(file, &ff->hwdep_wait, wait); | ||
| 62 | |||
| 63 | spin_lock_irq(&ff->lock); | ||
| 64 | if (ff->dev_lock_changed) | ||
| 65 | events = POLLIN | POLLRDNORM; | ||
| 66 | else | ||
| 67 | events = 0; | ||
| 68 | spin_unlock_irq(&ff->lock); | ||
| 69 | |||
| 70 | return events; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int hwdep_get_info(struct snd_ff *ff, void __user *arg) | ||
| 74 | { | ||
| 75 | struct fw_device *dev = fw_parent_device(ff->unit); | ||
| 76 | struct snd_firewire_get_info info; | ||
| 77 | |||
| 78 | memset(&info, 0, sizeof(info)); | ||
| 79 | info.type = SNDRV_FIREWIRE_TYPE_FIREFACE; | ||
| 80 | info.card = dev->card->index; | ||
| 81 | *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); | ||
| 82 | *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); | ||
| 83 | strlcpy(info.device_name, dev_name(&dev->device), | ||
| 84 | sizeof(info.device_name)); | ||
| 85 | |||
| 86 | if (copy_to_user(arg, &info, sizeof(info))) | ||
| 87 | return -EFAULT; | ||
| 88 | |||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | static int hwdep_lock(struct snd_ff *ff) | ||
| 93 | { | ||
| 94 | int err; | ||
| 95 | |||
| 96 | spin_lock_irq(&ff->lock); | ||
| 97 | |||
| 98 | if (ff->dev_lock_count == 0) { | ||
| 99 | ff->dev_lock_count = -1; | ||
| 100 | err = 0; | ||
| 101 | } else { | ||
| 102 | err = -EBUSY; | ||
| 103 | } | ||
| 104 | |||
| 105 | spin_unlock_irq(&ff->lock); | ||
| 106 | |||
| 107 | return err; | ||
| 108 | } | ||
| 109 | |||
| 110 | static int hwdep_unlock(struct snd_ff *ff) | ||
| 111 | { | ||
| 112 | int err; | ||
| 113 | |||
| 114 | spin_lock_irq(&ff->lock); | ||
| 115 | |||
| 116 | if (ff->dev_lock_count == -1) { | ||
| 117 | ff->dev_lock_count = 0; | ||
| 118 | err = 0; | ||
| 119 | } else { | ||
| 120 | err = -EBADFD; | ||
| 121 | } | ||
| 122 | |||
| 123 | spin_unlock_irq(&ff->lock); | ||
| 124 | |||
| 125 | return err; | ||
| 126 | } | ||
| 127 | |||
| 128 | static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) | ||
| 129 | { | ||
| 130 | struct snd_ff *ff = hwdep->private_data; | ||
| 131 | |||
| 132 | spin_lock_irq(&ff->lock); | ||
| 133 | if (ff->dev_lock_count == -1) | ||
| 134 | ff->dev_lock_count = 0; | ||
| 135 | spin_unlock_irq(&ff->lock); | ||
| 136 | |||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, | ||
| 141 | unsigned int cmd, unsigned long arg) | ||
| 142 | { | ||
| 143 | struct snd_ff *ff = hwdep->private_data; | ||
| 144 | |||
| 145 | switch (cmd) { | ||
| 146 | case SNDRV_FIREWIRE_IOCTL_GET_INFO: | ||
| 147 | return hwdep_get_info(ff, (void __user *)arg); | ||
| 148 | case SNDRV_FIREWIRE_IOCTL_LOCK: | ||
| 149 | return hwdep_lock(ff); | ||
| 150 | case SNDRV_FIREWIRE_IOCTL_UNLOCK: | ||
| 151 | return hwdep_unlock(ff); | ||
| 152 | default: | ||
| 153 | return -ENOIOCTLCMD; | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | #ifdef CONFIG_COMPAT | ||
| 158 | static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, | ||
| 159 | unsigned int cmd, unsigned long arg) | ||
| 160 | { | ||
| 161 | return hwdep_ioctl(hwdep, file, cmd, | ||
| 162 | (unsigned long)compat_ptr(arg)); | ||
| 163 | } | ||
| 164 | #else | ||
| 165 | #define hwdep_compat_ioctl NULL | ||
| 166 | #endif | ||
| 167 | |||
| 168 | int snd_ff_create_hwdep_devices(struct snd_ff *ff) | ||
| 169 | { | ||
| 170 | static const struct snd_hwdep_ops hwdep_ops = { | ||
| 171 | .read = hwdep_read, | ||
| 172 | .release = hwdep_release, | ||
| 173 | .poll = hwdep_poll, | ||
| 174 | .ioctl = hwdep_ioctl, | ||
| 175 | .ioctl_compat = hwdep_compat_ioctl, | ||
| 176 | }; | ||
| 177 | struct snd_hwdep *hwdep; | ||
| 178 | int err; | ||
| 179 | |||
| 180 | err = snd_hwdep_new(ff->card, ff->card->driver, 0, &hwdep); | ||
| 181 | if (err < 0) | ||
| 182 | return err; | ||
| 183 | |||
| 184 | strcpy(hwdep->name, ff->card->driver); | ||
| 185 | hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREFACE; | ||
| 186 | hwdep->ops = hwdep_ops; | ||
| 187 | hwdep->private_data = ff; | ||
| 188 | hwdep->exclusive = true; | ||
| 189 | |||
| 190 | return 0; | ||
| 191 | } | ||
diff --git a/sound/firewire/fireface/ff-midi.c b/sound/firewire/fireface/ff-midi.c new file mode 100644 index 000000000000..29ee0a7365c3 --- /dev/null +++ b/sound/firewire/fireface/ff-midi.c | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | /* | ||
| 2 | * ff-midi.c - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "ff.h" | ||
| 10 | |||
| 11 | static int midi_capture_open(struct snd_rawmidi_substream *substream) | ||
| 12 | { | ||
| 13 | /* Do nothing. */ | ||
| 14 | return 0; | ||
| 15 | } | ||
| 16 | |||
| 17 | static int midi_playback_open(struct snd_rawmidi_substream *substream) | ||
| 18 | { | ||
| 19 | struct snd_ff *ff = substream->rmidi->private_data; | ||
| 20 | |||
| 21 | /* Initialize internal status. */ | ||
| 22 | ff->running_status[substream->number] = 0; | ||
| 23 | ff->rx_midi_error[substream->number] = false; | ||
| 24 | |||
| 25 | ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = substream; | ||
| 26 | |||
| 27 | return 0; | ||
| 28 | } | ||
| 29 | |||
| 30 | static int midi_capture_close(struct snd_rawmidi_substream *substream) | ||
| 31 | { | ||
| 32 | /* Do nothing. */ | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | static int midi_playback_close(struct snd_rawmidi_substream *substream) | ||
| 37 | { | ||
| 38 | struct snd_ff *ff = substream->rmidi->private_data; | ||
| 39 | |||
| 40 | cancel_work_sync(&ff->rx_midi_work[substream->number]); | ||
| 41 | ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = NULL; | ||
| 42 | |||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | static void midi_capture_trigger(struct snd_rawmidi_substream *substream, | ||
| 47 | int up) | ||
| 48 | { | ||
| 49 | struct snd_ff *ff = substream->rmidi->private_data; | ||
| 50 | unsigned long flags; | ||
| 51 | |||
| 52 | spin_lock_irqsave(&ff->lock, flags); | ||
| 53 | |||
| 54 | if (up) | ||
| 55 | ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) = | ||
| 56 | substream; | ||
| 57 | else | ||
| 58 | ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) = NULL; | ||
| 59 | |||
| 60 | spin_unlock_irqrestore(&ff->lock, flags); | ||
| 61 | } | ||
| 62 | |||
| 63 | static void midi_playback_trigger(struct snd_rawmidi_substream *substream, | ||
| 64 | int up) | ||
| 65 | { | ||
| 66 | struct snd_ff *ff = substream->rmidi->private_data; | ||
| 67 | unsigned long flags; | ||
| 68 | |||
| 69 | spin_lock_irqsave(&ff->lock, flags); | ||
| 70 | |||
| 71 | if (up || !ff->rx_midi_error[substream->number]) | ||
| 72 | schedule_work(&ff->rx_midi_work[substream->number]); | ||
| 73 | |||
| 74 | spin_unlock_irqrestore(&ff->lock, flags); | ||
| 75 | } | ||
| 76 | |||
| 77 | static struct snd_rawmidi_ops midi_capture_ops = { | ||
| 78 | .open = midi_capture_open, | ||
| 79 | .close = midi_capture_close, | ||
| 80 | .trigger = midi_capture_trigger, | ||
| 81 | }; | ||
| 82 | |||
| 83 | static struct snd_rawmidi_ops midi_playback_ops = { | ||
| 84 | .open = midi_playback_open, | ||
| 85 | .close = midi_playback_close, | ||
| 86 | .trigger = midi_playback_trigger, | ||
| 87 | }; | ||
| 88 | |||
| 89 | static void set_midi_substream_names(struct snd_rawmidi_str *stream, | ||
| 90 | const char *const name) | ||
| 91 | { | ||
| 92 | struct snd_rawmidi_substream *substream; | ||
| 93 | |||
| 94 | list_for_each_entry(substream, &stream->substreams, list) { | ||
| 95 | snprintf(substream->name, sizeof(substream->name), | ||
| 96 | "%s MIDI %d", name, substream->number + 1); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | int snd_ff_create_midi_devices(struct snd_ff *ff) | ||
| 101 | { | ||
| 102 | struct snd_rawmidi *rmidi; | ||
| 103 | struct snd_rawmidi_str *stream; | ||
| 104 | int err; | ||
| 105 | |||
| 106 | err = snd_rawmidi_new(ff->card, ff->card->driver, 0, | ||
| 107 | ff->spec->midi_out_ports, ff->spec->midi_in_ports, | ||
| 108 | &rmidi); | ||
| 109 | if (err < 0) | ||
| 110 | return err; | ||
| 111 | |||
| 112 | snprintf(rmidi->name, sizeof(rmidi->name), | ||
| 113 | "%s MIDI", ff->card->shortname); | ||
| 114 | rmidi->private_data = ff; | ||
| 115 | |||
| 116 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; | ||
| 117 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
| 118 | &midi_capture_ops); | ||
| 119 | stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; | ||
| 120 | set_midi_substream_names(stream, ff->card->shortname); | ||
| 121 | |||
| 122 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; | ||
| 123 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
| 124 | &midi_playback_ops); | ||
| 125 | stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; | ||
| 126 | set_midi_substream_names(stream, ff->card->shortname); | ||
| 127 | |||
| 128 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; | ||
| 129 | |||
| 130 | return 0; | ||
| 131 | } | ||
diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c new file mode 100644 index 000000000000..93cee1978e8e --- /dev/null +++ b/sound/firewire/fireface/ff-pcm.c | |||
| @@ -0,0 +1,409 @@ | |||
| 1 | /* | ||
| 2 | * ff-pcm.c - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "ff.h" | ||
| 10 | |||
| 11 | static inline unsigned int get_multiplier_mode_with_index(unsigned int index) | ||
| 12 | { | ||
| 13 | return ((int)index - 1) / 2; | ||
| 14 | } | ||
| 15 | |||
| 16 | static int hw_rule_rate(struct snd_pcm_hw_params *params, | ||
| 17 | struct snd_pcm_hw_rule *rule) | ||
| 18 | { | ||
| 19 | const unsigned int *pcm_channels = rule->private; | ||
| 20 | struct snd_interval *r = | ||
| 21 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
| 22 | const struct snd_interval *c = | ||
| 23 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
| 24 | struct snd_interval t = { | ||
| 25 | .min = UINT_MAX, .max = 0, .integer = 1 | ||
| 26 | }; | ||
| 27 | unsigned int i, mode; | ||
| 28 | |||
| 29 | for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) { | ||
| 30 | mode = get_multiplier_mode_with_index(i); | ||
| 31 | if (!snd_interval_test(c, pcm_channels[mode])) | ||
| 32 | continue; | ||
| 33 | |||
| 34 | t.min = min(t.min, amdtp_rate_table[i]); | ||
| 35 | t.max = max(t.max, amdtp_rate_table[i]); | ||
| 36 | } | ||
| 37 | |||
| 38 | return snd_interval_refine(r, &t); | ||
| 39 | } | ||
| 40 | |||
| 41 | static int hw_rule_channels(struct snd_pcm_hw_params *params, | ||
| 42 | struct snd_pcm_hw_rule *rule) | ||
| 43 | { | ||
| 44 | const unsigned int *pcm_channels = rule->private; | ||
| 45 | struct snd_interval *c = | ||
| 46 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
| 47 | const struct snd_interval *r = | ||
| 48 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); | ||
| 49 | struct snd_interval t = { | ||
| 50 | .min = UINT_MAX, .max = 0, .integer = 1 | ||
| 51 | }; | ||
| 52 | unsigned int i, mode; | ||
| 53 | |||
| 54 | for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) { | ||
| 55 | mode = get_multiplier_mode_with_index(i); | ||
| 56 | if (!snd_interval_test(r, amdtp_rate_table[i])) | ||
| 57 | continue; | ||
| 58 | |||
| 59 | t.min = min(t.min, pcm_channels[mode]); | ||
| 60 | t.max = max(t.max, pcm_channels[mode]); | ||
| 61 | } | ||
| 62 | |||
| 63 | return snd_interval_refine(c, &t); | ||
| 64 | } | ||
| 65 | |||
| 66 | static void limit_channels_and_rates(struct snd_pcm_hardware *hw, | ||
| 67 | const unsigned int *pcm_channels) | ||
| 68 | { | ||
| 69 | unsigned int mode; | ||
| 70 | unsigned int rate, channels; | ||
| 71 | int i; | ||
| 72 | |||
| 73 | hw->channels_min = UINT_MAX; | ||
| 74 | hw->channels_max = 0; | ||
| 75 | hw->rate_min = UINT_MAX; | ||
| 76 | hw->rate_max = 0; | ||
| 77 | |||
| 78 | for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) { | ||
| 79 | mode = get_multiplier_mode_with_index(i); | ||
| 80 | |||
| 81 | channels = pcm_channels[mode]; | ||
| 82 | if (pcm_channels[mode] == 0) | ||
| 83 | continue; | ||
| 84 | hw->channels_min = min(hw->channels_min, channels); | ||
| 85 | hw->channels_max = max(hw->channels_max, channels); | ||
| 86 | |||
| 87 | rate = amdtp_rate_table[i]; | ||
| 88 | hw->rates |= snd_pcm_rate_to_rate_bit(rate); | ||
| 89 | hw->rate_min = min(hw->rate_min, rate); | ||
| 90 | hw->rate_max = max(hw->rate_max, rate); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | static void limit_period_and_buffer(struct snd_pcm_hardware *hw) | ||
| 95 | { | ||
| 96 | hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ | ||
| 97 | hw->periods_max = UINT_MAX; | ||
| 98 | |||
| 99 | hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */ | ||
| 100 | |||
| 101 | /* Just to prevent from allocating much pages. */ | ||
| 102 | hw->period_bytes_max = hw->period_bytes_min * 2048; | ||
| 103 | hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; | ||
| 104 | } | ||
| 105 | |||
| 106 | static int pcm_init_hw_params(struct snd_ff *ff, | ||
| 107 | struct snd_pcm_substream *substream) | ||
| 108 | { | ||
| 109 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 110 | struct amdtp_stream *s; | ||
| 111 | const unsigned int *pcm_channels; | ||
| 112 | int err; | ||
| 113 | |||
| 114 | runtime->hw.info = SNDRV_PCM_INFO_BATCH | | ||
| 115 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
| 116 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 117 | SNDRV_PCM_INFO_JOINT_DUPLEX | | ||
| 118 | SNDRV_PCM_INFO_MMAP | | ||
| 119 | SNDRV_PCM_INFO_MMAP_VALID; | ||
| 120 | |||
| 121 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
| 122 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; | ||
| 123 | s = &ff->tx_stream; | ||
| 124 | pcm_channels = ff->spec->pcm_capture_channels; | ||
| 125 | } else { | ||
| 126 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; | ||
| 127 | s = &ff->rx_stream; | ||
| 128 | pcm_channels = ff->spec->pcm_playback_channels; | ||
| 129 | } | ||
| 130 | |||
| 131 | /* limit rates */ | ||
| 132 | limit_channels_and_rates(&runtime->hw, pcm_channels); | ||
| 133 | limit_period_and_buffer(&runtime->hw); | ||
| 134 | |||
| 135 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
| 136 | hw_rule_channels, (void *)pcm_channels, | ||
| 137 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
| 138 | if (err < 0) | ||
| 139 | return err; | ||
| 140 | |||
| 141 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
| 142 | hw_rule_rate, (void *)pcm_channels, | ||
| 143 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
| 144 | if (err < 0) | ||
| 145 | return err; | ||
| 146 | |||
| 147 | return amdtp_ff_add_pcm_hw_constraints(s, runtime); | ||
| 148 | } | ||
| 149 | |||
| 150 | static int pcm_open(struct snd_pcm_substream *substream) | ||
| 151 | { | ||
| 152 | struct snd_ff *ff = substream->private_data; | ||
| 153 | unsigned int rate; | ||
| 154 | enum snd_ff_clock_src src; | ||
| 155 | int i, err; | ||
| 156 | |||
| 157 | err = snd_ff_stream_lock_try(ff); | ||
| 158 | if (err < 0) | ||
| 159 | return err; | ||
| 160 | |||
| 161 | err = pcm_init_hw_params(ff, substream); | ||
| 162 | if (err < 0) { | ||
| 163 | snd_ff_stream_lock_release(ff); | ||
| 164 | return err; | ||
| 165 | } | ||
| 166 | |||
| 167 | err = ff->spec->protocol->get_clock(ff, &rate, &src); | ||
| 168 | if (err < 0) { | ||
| 169 | snd_ff_stream_lock_release(ff); | ||
| 170 | return err; | ||
| 171 | } | ||
| 172 | |||
| 173 | if (src != SND_FF_CLOCK_SRC_INTERNAL) { | ||
| 174 | for (i = 0; i < CIP_SFC_COUNT; ++i) { | ||
| 175 | if (amdtp_rate_table[i] == rate) | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | /* | ||
| 179 | * The unit is configured at sampling frequency which packet | ||
| 180 | * streaming engine can't support. | ||
| 181 | */ | ||
| 182 | if (i >= CIP_SFC_COUNT) { | ||
| 183 | snd_ff_stream_lock_release(ff); | ||
| 184 | return -EIO; | ||
| 185 | } | ||
| 186 | |||
| 187 | substream->runtime->hw.rate_min = rate; | ||
| 188 | substream->runtime->hw.rate_max = rate; | ||
| 189 | } else { | ||
| 190 | if (amdtp_stream_pcm_running(&ff->rx_stream) || | ||
| 191 | amdtp_stream_pcm_running(&ff->tx_stream)) { | ||
| 192 | rate = amdtp_rate_table[ff->rx_stream.sfc]; | ||
| 193 | substream->runtime->hw.rate_min = rate; | ||
| 194 | substream->runtime->hw.rate_max = rate; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | snd_pcm_set_sync(substream); | ||
| 199 | |||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | |||
| 203 | static int pcm_close(struct snd_pcm_substream *substream) | ||
| 204 | { | ||
| 205 | struct snd_ff *ff = substream->private_data; | ||
| 206 | |||
| 207 | snd_ff_stream_lock_release(ff); | ||
| 208 | |||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | static int pcm_capture_hw_params(struct snd_pcm_substream *substream, | ||
| 213 | struct snd_pcm_hw_params *hw_params) | ||
| 214 | { | ||
| 215 | struct snd_ff *ff = substream->private_data; | ||
| 216 | int err; | ||
| 217 | |||
| 218 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
| 219 | params_buffer_bytes(hw_params)); | ||
| 220 | if (err < 0) | ||
| 221 | return err; | ||
| 222 | |||
| 223 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { | ||
| 224 | mutex_lock(&ff->mutex); | ||
| 225 | ff->substreams_counter++; | ||
| 226 | mutex_unlock(&ff->mutex); | ||
| 227 | } | ||
| 228 | |||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | |||
| 232 | static int pcm_playback_hw_params(struct snd_pcm_substream *substream, | ||
| 233 | struct snd_pcm_hw_params *hw_params) | ||
| 234 | { | ||
| 235 | struct snd_ff *ff = substream->private_data; | ||
| 236 | int err; | ||
| 237 | |||
| 238 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
| 239 | params_buffer_bytes(hw_params)); | ||
| 240 | if (err < 0) | ||
| 241 | return err; | ||
| 242 | |||
| 243 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { | ||
| 244 | mutex_lock(&ff->mutex); | ||
| 245 | ff->substreams_counter++; | ||
| 246 | mutex_unlock(&ff->mutex); | ||
| 247 | } | ||
| 248 | |||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static int pcm_capture_hw_free(struct snd_pcm_substream *substream) | ||
| 253 | { | ||
| 254 | struct snd_ff *ff = substream->private_data; | ||
| 255 | |||
| 256 | mutex_lock(&ff->mutex); | ||
| 257 | |||
| 258 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) | ||
| 259 | ff->substreams_counter--; | ||
| 260 | |||
| 261 | snd_ff_stream_stop_duplex(ff); | ||
| 262 | |||
| 263 | mutex_unlock(&ff->mutex); | ||
| 264 | |||
| 265 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
| 266 | } | ||
| 267 | |||
| 268 | static int pcm_playback_hw_free(struct snd_pcm_substream *substream) | ||
| 269 | { | ||
| 270 | struct snd_ff *ff = substream->private_data; | ||
| 271 | |||
| 272 | mutex_lock(&ff->mutex); | ||
| 273 | |||
| 274 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) | ||
| 275 | ff->substreams_counter--; | ||
| 276 | |||
| 277 | snd_ff_stream_stop_duplex(ff); | ||
| 278 | |||
| 279 | mutex_unlock(&ff->mutex); | ||
| 280 | |||
| 281 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
| 282 | } | ||
| 283 | |||
| 284 | static int pcm_capture_prepare(struct snd_pcm_substream *substream) | ||
| 285 | { | ||
| 286 | struct snd_ff *ff = substream->private_data; | ||
| 287 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 288 | int err; | ||
| 289 | |||
| 290 | mutex_lock(&ff->mutex); | ||
| 291 | |||
| 292 | err = snd_ff_stream_start_duplex(ff, runtime->rate); | ||
| 293 | if (err >= 0) | ||
| 294 | amdtp_stream_pcm_prepare(&ff->tx_stream); | ||
| 295 | |||
| 296 | mutex_unlock(&ff->mutex); | ||
| 297 | |||
| 298 | return err; | ||
| 299 | } | ||
| 300 | |||
| 301 | static int pcm_playback_prepare(struct snd_pcm_substream *substream) | ||
| 302 | { | ||
| 303 | struct snd_ff *ff = substream->private_data; | ||
| 304 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 305 | int err; | ||
| 306 | |||
| 307 | mutex_lock(&ff->mutex); | ||
| 308 | |||
| 309 | err = snd_ff_stream_start_duplex(ff, runtime->rate); | ||
| 310 | if (err >= 0) | ||
| 311 | amdtp_stream_pcm_prepare(&ff->rx_stream); | ||
| 312 | |||
| 313 | mutex_unlock(&ff->mutex); | ||
| 314 | |||
| 315 | return err; | ||
| 316 | } | ||
| 317 | |||
| 318 | static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 319 | { | ||
| 320 | struct snd_ff *ff = substream->private_data; | ||
| 321 | |||
| 322 | switch (cmd) { | ||
| 323 | case SNDRV_PCM_TRIGGER_START: | ||
| 324 | amdtp_stream_pcm_trigger(&ff->tx_stream, substream); | ||
| 325 | break; | ||
| 326 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 327 | amdtp_stream_pcm_trigger(&ff->tx_stream, NULL); | ||
| 328 | break; | ||
| 329 | default: | ||
| 330 | return -EINVAL; | ||
| 331 | } | ||
| 332 | |||
| 333 | return 0; | ||
| 334 | } | ||
| 335 | |||
| 336 | static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 337 | { | ||
| 338 | struct snd_ff *ff = substream->private_data; | ||
| 339 | |||
| 340 | switch (cmd) { | ||
| 341 | case SNDRV_PCM_TRIGGER_START: | ||
| 342 | amdtp_stream_pcm_trigger(&ff->rx_stream, substream); | ||
| 343 | break; | ||
| 344 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 345 | amdtp_stream_pcm_trigger(&ff->rx_stream, NULL); | ||
| 346 | break; | ||
| 347 | default: | ||
| 348 | return -EINVAL; | ||
| 349 | } | ||
| 350 | |||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) | ||
| 355 | { | ||
| 356 | struct snd_ff *ff = sbstrm->private_data; | ||
| 357 | |||
| 358 | return amdtp_stream_pcm_pointer(&ff->tx_stream); | ||
| 359 | } | ||
| 360 | |||
| 361 | static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) | ||
| 362 | { | ||
| 363 | struct snd_ff *ff = sbstrm->private_data; | ||
| 364 | |||
| 365 | return amdtp_stream_pcm_pointer(&ff->rx_stream); | ||
| 366 | } | ||
| 367 | |||
| 368 | static struct snd_pcm_ops pcm_capture_ops = { | ||
| 369 | .open = pcm_open, | ||
| 370 | .close = pcm_close, | ||
| 371 | .ioctl = snd_pcm_lib_ioctl, | ||
| 372 | .hw_params = pcm_capture_hw_params, | ||
| 373 | .hw_free = pcm_capture_hw_free, | ||
| 374 | .prepare = pcm_capture_prepare, | ||
| 375 | .trigger = pcm_capture_trigger, | ||
| 376 | .pointer = pcm_capture_pointer, | ||
| 377 | .page = snd_pcm_lib_get_vmalloc_page, | ||
| 378 | }; | ||
| 379 | |||
| 380 | static struct snd_pcm_ops pcm_playback_ops = { | ||
| 381 | .open = pcm_open, | ||
| 382 | .close = pcm_close, | ||
| 383 | .ioctl = snd_pcm_lib_ioctl, | ||
| 384 | .hw_params = pcm_playback_hw_params, | ||
| 385 | .hw_free = pcm_playback_hw_free, | ||
| 386 | .prepare = pcm_playback_prepare, | ||
| 387 | .trigger = pcm_playback_trigger, | ||
| 388 | .pointer = pcm_playback_pointer, | ||
| 389 | .page = snd_pcm_lib_get_vmalloc_page, | ||
| 390 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 391 | }; | ||
| 392 | |||
| 393 | int snd_ff_create_pcm_devices(struct snd_ff *ff) | ||
| 394 | { | ||
| 395 | struct snd_pcm *pcm; | ||
| 396 | int err; | ||
| 397 | |||
| 398 | err = snd_pcm_new(ff->card, ff->card->driver, 0, 1, 1, &pcm); | ||
| 399 | if (err < 0) | ||
| 400 | return err; | ||
| 401 | |||
| 402 | pcm->private_data = ff; | ||
| 403 | snprintf(pcm->name, sizeof(pcm->name), | ||
| 404 | "%s PCM", ff->card->shortname); | ||
| 405 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); | ||
| 406 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); | ||
| 407 | |||
| 408 | return 0; | ||
| 409 | } | ||
diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c new file mode 100644 index 000000000000..69441d121f71 --- /dev/null +++ b/sound/firewire/fireface/ff-proc.c | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | /* | ||
| 2 | * ff-proc.c - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "./ff.h" | ||
| 10 | |||
| 11 | static void proc_dump_clock_config(struct snd_info_entry *entry, | ||
| 12 | struct snd_info_buffer *buffer) | ||
| 13 | { | ||
| 14 | struct snd_ff *ff = entry->private_data; | ||
| 15 | |||
| 16 | ff->spec->protocol->dump_clock_config(ff, buffer); | ||
| 17 | } | ||
| 18 | |||
| 19 | static void proc_dump_sync_status(struct snd_info_entry *entry, | ||
| 20 | struct snd_info_buffer *buffer) | ||
| 21 | { | ||
| 22 | struct snd_ff *ff = entry->private_data; | ||
| 23 | |||
| 24 | ff->spec->protocol->dump_sync_status(ff, buffer); | ||
| 25 | } | ||
| 26 | |||
| 27 | static void add_node(struct snd_ff *ff, struct snd_info_entry *root, | ||
| 28 | const char *name, | ||
| 29 | void (*op)(struct snd_info_entry *e, | ||
| 30 | struct snd_info_buffer *b)) | ||
| 31 | { | ||
| 32 | struct snd_info_entry *entry; | ||
| 33 | |||
| 34 | entry = snd_info_create_card_entry(ff->card, name, root); | ||
| 35 | if (entry == NULL) | ||
| 36 | return; | ||
| 37 | |||
| 38 | snd_info_set_text_ops(entry, ff, op); | ||
| 39 | if (snd_info_register(entry) < 0) | ||
| 40 | snd_info_free_entry(entry); | ||
| 41 | } | ||
| 42 | |||
| 43 | void snd_ff_proc_init(struct snd_ff *ff) | ||
| 44 | { | ||
| 45 | struct snd_info_entry *root; | ||
| 46 | |||
| 47 | /* | ||
| 48 | * All nodes are automatically removed at snd_card_disconnect(), | ||
| 49 | * by following to link list. | ||
| 50 | */ | ||
| 51 | root = snd_info_create_card_entry(ff->card, "firewire", | ||
| 52 | ff->card->proc_root); | ||
| 53 | if (root == NULL) | ||
| 54 | return; | ||
| 55 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
| 56 | if (snd_info_register(root) < 0) { | ||
| 57 | snd_info_free_entry(root); | ||
| 58 | return; | ||
| 59 | } | ||
| 60 | |||
| 61 | add_node(ff, root, "clock-config", proc_dump_clock_config); | ||
| 62 | add_node(ff, root, "sync-status", proc_dump_sync_status); | ||
| 63 | } | ||
diff --git a/sound/firewire/fireface/ff-protocol-ff400.c b/sound/firewire/fireface/ff-protocol-ff400.c new file mode 100644 index 000000000000..fcec6de80eeb --- /dev/null +++ b/sound/firewire/fireface/ff-protocol-ff400.c | |||
| @@ -0,0 +1,371 @@ | |||
| 1 | /* | ||
| 2 | * ff-protocol-ff400.c - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/delay.h> | ||
| 10 | #include "ff.h" | ||
| 11 | |||
| 12 | #define FF400_STF 0x000080100500ull | ||
| 13 | #define FF400_RX_PACKET_FORMAT 0x000080100504ull | ||
| 14 | #define FF400_ISOC_COMM_START 0x000080100508ull | ||
| 15 | #define FF400_TX_PACKET_FORMAT 0x00008010050cull | ||
| 16 | #define FF400_ISOC_COMM_STOP 0x000080100510ull | ||
| 17 | #define FF400_SYNC_STATUS 0x0000801c0000ull | ||
| 18 | #define FF400_FETCH_PCM_FRAMES 0x0000801c0000ull /* For block request. */ | ||
| 19 | #define FF400_CLOCK_CONFIG 0x0000801c0004ull | ||
| 20 | |||
| 21 | #define FF400_MIDI_HIGH_ADDR 0x0000801003f4ull | ||
| 22 | #define FF400_MIDI_RX_PORT_0 0x000080180000ull | ||
| 23 | #define FF400_MIDI_RX_PORT_1 0x000080190000ull | ||
| 24 | |||
| 25 | static int ff400_get_clock(struct snd_ff *ff, unsigned int *rate, | ||
| 26 | enum snd_ff_clock_src *src) | ||
| 27 | { | ||
| 28 | __le32 reg; | ||
| 29 | u32 data; | ||
| 30 | int err; | ||
| 31 | |||
| 32 | err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, | ||
| 33 | FF400_SYNC_STATUS, ®, sizeof(reg), 0); | ||
| 34 | if (err < 0) | ||
| 35 | return err; | ||
| 36 | data = le32_to_cpu(reg); | ||
| 37 | |||
| 38 | /* Calculate sampling rate. */ | ||
| 39 | switch ((data >> 1) & 0x03) { | ||
| 40 | case 0x01: | ||
| 41 | *rate = 32000; | ||
| 42 | break; | ||
| 43 | case 0x00: | ||
| 44 | *rate = 44100; | ||
| 45 | break; | ||
| 46 | case 0x03: | ||
| 47 | *rate = 48000; | ||
| 48 | break; | ||
| 49 | case 0x02: | ||
| 50 | default: | ||
| 51 | return -EIO; | ||
| 52 | } | ||
| 53 | |||
| 54 | if (data & 0x08) | ||
| 55 | *rate *= 2; | ||
| 56 | else if (data & 0x10) | ||
| 57 | *rate *= 4; | ||
| 58 | |||
| 59 | /* Calculate source of clock. */ | ||
| 60 | if (data & 0x01) { | ||
| 61 | *src = SND_FF_CLOCK_SRC_INTERNAL; | ||
| 62 | } else { | ||
| 63 | /* TODO: 0x00, 0x01, 0x02, 0x06, 0x07? */ | ||
| 64 | switch ((data >> 10) & 0x07) { | ||
| 65 | case 0x03: | ||
| 66 | *src = SND_FF_CLOCK_SRC_SPDIF; | ||
| 67 | break; | ||
| 68 | case 0x04: | ||
| 69 | *src = SND_FF_CLOCK_SRC_WORD; | ||
| 70 | break; | ||
| 71 | case 0x05: | ||
| 72 | *src = SND_FF_CLOCK_SRC_LTC; | ||
| 73 | break; | ||
| 74 | case 0x00: | ||
| 75 | default: | ||
| 76 | *src = SND_FF_CLOCK_SRC_ADAT; | ||
| 77 | break; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | static int ff400_begin_session(struct snd_ff *ff, unsigned int rate) | ||
| 85 | { | ||
| 86 | __le32 reg; | ||
| 87 | int i, err; | ||
| 88 | |||
| 89 | /* Check whether the given value is supported or not. */ | ||
| 90 | for (i = 0; i < CIP_SFC_COUNT; i++) { | ||
| 91 | if (amdtp_rate_table[i] == rate) | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | if (i == CIP_SFC_COUNT) | ||
| 95 | return -EINVAL; | ||
| 96 | |||
| 97 | /* Set the number of data blocks transferred in a second. */ | ||
| 98 | reg = cpu_to_le32(rate); | ||
| 99 | err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
| 100 | FF400_STF, ®, sizeof(reg), 0); | ||
| 101 | if (err < 0) | ||
| 102 | return err; | ||
| 103 | |||
| 104 | msleep(100); | ||
| 105 | |||
| 106 | /* | ||
| 107 | * Set isochronous channel and the number of quadlets of received | ||
| 108 | * packets. | ||
| 109 | */ | ||
| 110 | reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) | | ||
| 111 | ff->rx_resources.channel); | ||
| 112 | err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
| 113 | FF400_RX_PACKET_FORMAT, ®, sizeof(reg), 0); | ||
| 114 | if (err < 0) | ||
| 115 | return err; | ||
| 116 | |||
| 117 | /* | ||
| 118 | * Set isochronous channel and the number of quadlets of transmitted | ||
| 119 | * packet. | ||
| 120 | */ | ||
| 121 | /* TODO: investigate the purpose of this 0x80. */ | ||
| 122 | reg = cpu_to_le32((0x80 << 24) | | ||
| 123 | (ff->tx_resources.channel << 5) | | ||
| 124 | (ff->tx_stream.data_block_quadlets)); | ||
| 125 | err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
| 126 | FF400_TX_PACKET_FORMAT, ®, sizeof(reg), 0); | ||
| 127 | if (err < 0) | ||
| 128 | return err; | ||
| 129 | |||
| 130 | /* Allow to transmit packets. */ | ||
| 131 | reg = cpu_to_le32(0x00000001); | ||
| 132 | return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
| 133 | FF400_ISOC_COMM_START, ®, sizeof(reg), 0); | ||
| 134 | } | ||
| 135 | |||
| 136 | static void ff400_finish_session(struct snd_ff *ff) | ||
| 137 | { | ||
| 138 | __le32 reg; | ||
| 139 | |||
| 140 | reg = cpu_to_le32(0x80000000); | ||
| 141 | snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
| 142 | FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0); | ||
| 143 | } | ||
| 144 | |||
| 145 | static int ff400_switch_fetching_mode(struct snd_ff *ff, bool enable) | ||
| 146 | { | ||
| 147 | __le32 *reg; | ||
| 148 | int i; | ||
| 149 | |||
| 150 | reg = kzalloc(sizeof(__le32) * 18, GFP_KERNEL); | ||
| 151 | if (reg == NULL) | ||
| 152 | return -ENOMEM; | ||
| 153 | |||
| 154 | if (enable) { | ||
| 155 | /* | ||
| 156 | * Each quadlet is corresponding to data channels in a data | ||
| 157 | * blocks in reverse order. Precisely, quadlets for available | ||
| 158 | * data channels should be enabled. Here, I take second best | ||
| 159 | * to fetch PCM frames from all of data channels regardless of | ||
| 160 | * stf. | ||
| 161 | */ | ||
| 162 | for (i = 0; i < 18; ++i) | ||
| 163 | reg[i] = cpu_to_le32(0x00000001); | ||
| 164 | } | ||
| 165 | |||
| 166 | return snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST, | ||
| 167 | FF400_FETCH_PCM_FRAMES, reg, | ||
| 168 | sizeof(__le32) * 18, 0); | ||
| 169 | } | ||
| 170 | |||
| 171 | static void ff400_dump_sync_status(struct snd_ff *ff, | ||
| 172 | struct snd_info_buffer *buffer) | ||
| 173 | { | ||
| 174 | __le32 reg; | ||
| 175 | u32 data; | ||
| 176 | int err; | ||
| 177 | |||
| 178 | err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, | ||
| 179 | FF400_SYNC_STATUS, ®, sizeof(reg), 0); | ||
| 180 | if (err < 0) | ||
| 181 | return; | ||
| 182 | |||
| 183 | data = le32_to_cpu(reg); | ||
| 184 | |||
| 185 | snd_iprintf(buffer, "External source detection:\n"); | ||
| 186 | |||
| 187 | snd_iprintf(buffer, "Word Clock:"); | ||
| 188 | if ((data >> 24) & 0x20) { | ||
| 189 | if ((data >> 24) & 0x40) | ||
| 190 | snd_iprintf(buffer, "sync\n"); | ||
| 191 | else | ||
| 192 | snd_iprintf(buffer, "lock\n"); | ||
| 193 | } else { | ||
| 194 | snd_iprintf(buffer, "none\n"); | ||
| 195 | } | ||
| 196 | |||
| 197 | snd_iprintf(buffer, "S/PDIF:"); | ||
| 198 | if ((data >> 16) & 0x10) { | ||
| 199 | if ((data >> 16) & 0x04) | ||
| 200 | snd_iprintf(buffer, "sync\n"); | ||
| 201 | else | ||
| 202 | snd_iprintf(buffer, "lock\n"); | ||
| 203 | } else { | ||
| 204 | snd_iprintf(buffer, "none\n"); | ||
| 205 | } | ||
| 206 | |||
| 207 | snd_iprintf(buffer, "ADAT:"); | ||
| 208 | if ((data >> 8) & 0x04) { | ||
| 209 | if ((data >> 8) & 0x10) | ||
| 210 | snd_iprintf(buffer, "sync\n"); | ||
| 211 | else | ||
| 212 | snd_iprintf(buffer, "lock\n"); | ||
| 213 | } else { | ||
| 214 | snd_iprintf(buffer, "none\n"); | ||
| 215 | } | ||
| 216 | |||
| 217 | snd_iprintf(buffer, "\nUsed external source:\n"); | ||
| 218 | |||
| 219 | if (((data >> 22) & 0x07) == 0x07) { | ||
| 220 | snd_iprintf(buffer, "None\n"); | ||
| 221 | } else { | ||
| 222 | switch ((data >> 22) & 0x07) { | ||
| 223 | case 0x00: | ||
| 224 | snd_iprintf(buffer, "ADAT:"); | ||
| 225 | break; | ||
| 226 | case 0x03: | ||
| 227 | snd_iprintf(buffer, "S/PDIF:"); | ||
| 228 | break; | ||
| 229 | case 0x04: | ||
| 230 | snd_iprintf(buffer, "Word:"); | ||
| 231 | break; | ||
| 232 | case 0x07: | ||
| 233 | snd_iprintf(buffer, "Nothing:"); | ||
| 234 | break; | ||
| 235 | case 0x01: | ||
| 236 | case 0x02: | ||
| 237 | case 0x05: | ||
| 238 | case 0x06: | ||
| 239 | default: | ||
| 240 | snd_iprintf(buffer, "unknown:"); | ||
| 241 | break; | ||
| 242 | } | ||
| 243 | |||
| 244 | if ((data >> 25) & 0x07) { | ||
| 245 | switch ((data >> 25) & 0x07) { | ||
| 246 | case 0x01: | ||
| 247 | snd_iprintf(buffer, "32000\n"); | ||
| 248 | break; | ||
| 249 | case 0x02: | ||
| 250 | snd_iprintf(buffer, "44100\n"); | ||
| 251 | break; | ||
| 252 | case 0x03: | ||
| 253 | snd_iprintf(buffer, "48000\n"); | ||
| 254 | break; | ||
| 255 | case 0x04: | ||
| 256 | snd_iprintf(buffer, "64000\n"); | ||
| 257 | break; | ||
| 258 | case 0x05: | ||
| 259 | snd_iprintf(buffer, "88200\n"); | ||
| 260 | break; | ||
| 261 | case 0x06: | ||
| 262 | snd_iprintf(buffer, "96000\n"); | ||
| 263 | break; | ||
| 264 | case 0x07: | ||
| 265 | snd_iprintf(buffer, "128000\n"); | ||
| 266 | break; | ||
| 267 | case 0x08: | ||
| 268 | snd_iprintf(buffer, "176400\n"); | ||
| 269 | break; | ||
| 270 | case 0x09: | ||
| 271 | snd_iprintf(buffer, "192000\n"); | ||
| 272 | break; | ||
| 273 | case 0x00: | ||
| 274 | snd_iprintf(buffer, "unknown\n"); | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | snd_iprintf(buffer, "Multiplied:"); | ||
| 281 | snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); | ||
| 282 | } | ||
| 283 | |||
| 284 | static void ff400_dump_clock_config(struct snd_ff *ff, | ||
| 285 | struct snd_info_buffer *buffer) | ||
| 286 | { | ||
| 287 | __le32 reg; | ||
| 288 | u32 data; | ||
| 289 | unsigned int rate; | ||
| 290 | const char *src; | ||
| 291 | int err; | ||
| 292 | |||
| 293 | err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, | ||
| 294 | FF400_CLOCK_CONFIG, ®, sizeof(reg), 0); | ||
| 295 | if (err < 0) | ||
| 296 | return; | ||
| 297 | |||
| 298 | data = le32_to_cpu(reg); | ||
| 299 | |||
| 300 | snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n", | ||
| 301 | (data & 0x20) ? "Professional" : "Consumer", | ||
| 302 | (data & 0x40) ? "on" : "off"); | ||
| 303 | |||
| 304 | snd_iprintf(buffer, "Optical output interface format: %s\n", | ||
| 305 | ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT"); | ||
| 306 | |||
| 307 | snd_iprintf(buffer, "Word output single speed: %s\n", | ||
| 308 | ((data >> 8) & 0x20) ? "on" : "off"); | ||
| 309 | |||
| 310 | snd_iprintf(buffer, "S/PDIF input interface: %s\n", | ||
| 311 | ((data >> 8) & 0x02) ? "Optical" : "Coaxial"); | ||
| 312 | |||
| 313 | switch ((data >> 1) & 0x03) { | ||
| 314 | case 0x01: | ||
| 315 | rate = 32000; | ||
| 316 | break; | ||
| 317 | case 0x00: | ||
| 318 | rate = 44100; | ||
| 319 | break; | ||
| 320 | case 0x03: | ||
| 321 | rate = 48000; | ||
| 322 | break; | ||
| 323 | case 0x02: | ||
| 324 | default: | ||
| 325 | return; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (data & 0x08) | ||
| 329 | rate *= 2; | ||
| 330 | else if (data & 0x10) | ||
| 331 | rate *= 4; | ||
| 332 | |||
| 333 | snd_iprintf(buffer, "Sampling rate: %d\n", rate); | ||
| 334 | |||
| 335 | if (data & 0x01) { | ||
| 336 | src = "Internal"; | ||
| 337 | } else { | ||
| 338 | switch ((data >> 10) & 0x07) { | ||
| 339 | case 0x00: | ||
| 340 | src = "ADAT"; | ||
| 341 | break; | ||
| 342 | case 0x03: | ||
| 343 | src = "S/PDIF"; | ||
| 344 | break; | ||
| 345 | case 0x04: | ||
| 346 | src = "Word"; | ||
| 347 | break; | ||
| 348 | case 0x05: | ||
| 349 | src = "LTC"; | ||
| 350 | break; | ||
| 351 | default: | ||
| 352 | return; | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | snd_iprintf(buffer, "Sync to clock source: %s\n", src); | ||
| 357 | } | ||
| 358 | |||
| 359 | struct snd_ff_protocol snd_ff_protocol_ff400 = { | ||
| 360 | .get_clock = ff400_get_clock, | ||
| 361 | .begin_session = ff400_begin_session, | ||
| 362 | .finish_session = ff400_finish_session, | ||
| 363 | .switch_fetching_mode = ff400_switch_fetching_mode, | ||
| 364 | |||
| 365 | .dump_sync_status = ff400_dump_sync_status, | ||
| 366 | .dump_clock_config = ff400_dump_clock_config, | ||
| 367 | |||
| 368 | .midi_high_addr_reg = FF400_MIDI_HIGH_ADDR, | ||
| 369 | .midi_rx_port_0_reg = FF400_MIDI_RX_PORT_0, | ||
| 370 | .midi_rx_port_1_reg = FF400_MIDI_RX_PORT_1, | ||
| 371 | }; | ||
diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c new file mode 100644 index 000000000000..78880922120e --- /dev/null +++ b/sound/firewire/fireface/ff-stream.c | |||
| @@ -0,0 +1,282 @@ | |||
| 1 | /* | ||
| 2 | * ff-stream.c - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "ff.h" | ||
| 10 | |||
| 11 | #define CALLBACK_TIMEOUT_MS 200 | ||
| 12 | |||
| 13 | static int get_rate_mode(unsigned int rate, unsigned int *mode) | ||
| 14 | { | ||
| 15 | int i; | ||
| 16 | |||
| 17 | for (i = 0; i < CIP_SFC_COUNT; i++) { | ||
| 18 | if (amdtp_rate_table[i] == rate) | ||
| 19 | break; | ||
| 20 | } | ||
| 21 | |||
| 22 | if (i == CIP_SFC_COUNT) | ||
| 23 | return -EINVAL; | ||
| 24 | |||
| 25 | *mode = ((int)i - 1) / 2; | ||
| 26 | |||
| 27 | return 0; | ||
| 28 | } | ||
| 29 | |||
| 30 | /* | ||
| 31 | * Fireface 400 manages isochronous channel number in 3 bit field. Therefore, | ||
| 32 | * we can allocate between 0 and 7 channel. | ||
| 33 | */ | ||
| 34 | static int keep_resources(struct snd_ff *ff, unsigned int rate) | ||
| 35 | { | ||
| 36 | int mode; | ||
| 37 | int err; | ||
| 38 | |||
| 39 | err = get_rate_mode(rate, &mode); | ||
| 40 | if (err < 0) | ||
| 41 | return err; | ||
| 42 | |||
| 43 | /* Keep resources for in-stream. */ | ||
| 44 | err = amdtp_ff_set_parameters(&ff->tx_stream, rate, | ||
| 45 | ff->spec->pcm_capture_channels[mode]); | ||
| 46 | if (err < 0) | ||
| 47 | return err; | ||
| 48 | ff->tx_resources.channels_mask = 0x00000000000000ffuLL; | ||
| 49 | err = fw_iso_resources_allocate(&ff->tx_resources, | ||
| 50 | amdtp_stream_get_max_payload(&ff->tx_stream), | ||
| 51 | fw_parent_device(ff->unit)->max_speed); | ||
| 52 | if (err < 0) | ||
| 53 | return err; | ||
| 54 | |||
| 55 | /* Keep resources for out-stream. */ | ||
| 56 | err = amdtp_ff_set_parameters(&ff->rx_stream, rate, | ||
| 57 | ff->spec->pcm_playback_channels[mode]); | ||
| 58 | if (err < 0) | ||
| 59 | return err; | ||
| 60 | ff->rx_resources.channels_mask = 0x00000000000000ffuLL; | ||
| 61 | err = fw_iso_resources_allocate(&ff->rx_resources, | ||
| 62 | amdtp_stream_get_max_payload(&ff->rx_stream), | ||
| 63 | fw_parent_device(ff->unit)->max_speed); | ||
| 64 | if (err < 0) | ||
| 65 | fw_iso_resources_free(&ff->tx_resources); | ||
| 66 | |||
| 67 | return err; | ||
| 68 | } | ||
| 69 | |||
| 70 | static void release_resources(struct snd_ff *ff) | ||
| 71 | { | ||
| 72 | fw_iso_resources_free(&ff->tx_resources); | ||
| 73 | fw_iso_resources_free(&ff->rx_resources); | ||
| 74 | } | ||
| 75 | |||
| 76 | static inline void finish_session(struct snd_ff *ff) | ||
| 77 | { | ||
| 78 | ff->spec->protocol->finish_session(ff); | ||
| 79 | ff->spec->protocol->switch_fetching_mode(ff, false); | ||
| 80 | } | ||
| 81 | |||
| 82 | static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) | ||
| 83 | { | ||
| 84 | int err; | ||
| 85 | struct fw_iso_resources *resources; | ||
| 86 | struct amdtp_stream *stream; | ||
| 87 | |||
| 88 | if (dir == AMDTP_IN_STREAM) { | ||
| 89 | resources = &ff->tx_resources; | ||
| 90 | stream = &ff->tx_stream; | ||
| 91 | } else { | ||
| 92 | resources = &ff->rx_resources; | ||
| 93 | stream = &ff->rx_stream; | ||
| 94 | } | ||
| 95 | |||
| 96 | err = fw_iso_resources_init(resources, ff->unit); | ||
| 97 | if (err < 0) | ||
| 98 | return err; | ||
| 99 | |||
| 100 | err = amdtp_ff_init(stream, ff->unit, dir); | ||
| 101 | if (err < 0) | ||
| 102 | fw_iso_resources_destroy(resources); | ||
| 103 | |||
| 104 | return err; | ||
| 105 | } | ||
| 106 | |||
| 107 | static void destroy_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) | ||
| 108 | { | ||
| 109 | if (dir == AMDTP_IN_STREAM) { | ||
| 110 | amdtp_stream_destroy(&ff->tx_stream); | ||
| 111 | fw_iso_resources_destroy(&ff->tx_resources); | ||
| 112 | } else { | ||
| 113 | amdtp_stream_destroy(&ff->rx_stream); | ||
| 114 | fw_iso_resources_destroy(&ff->rx_resources); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | int snd_ff_stream_init_duplex(struct snd_ff *ff) | ||
| 119 | { | ||
| 120 | int err; | ||
| 121 | |||
| 122 | err = init_stream(ff, AMDTP_OUT_STREAM); | ||
| 123 | if (err < 0) | ||
| 124 | goto end; | ||
| 125 | |||
| 126 | err = init_stream(ff, AMDTP_IN_STREAM); | ||
| 127 | if (err < 0) | ||
| 128 | destroy_stream(ff, AMDTP_OUT_STREAM); | ||
| 129 | end: | ||
| 130 | return err; | ||
| 131 | } | ||
| 132 | |||
| 133 | /* | ||
| 134 | * This function should be called before starting streams or after stopping | ||
| 135 | * streams. | ||
| 136 | */ | ||
| 137 | void snd_ff_stream_destroy_duplex(struct snd_ff *ff) | ||
| 138 | { | ||
| 139 | destroy_stream(ff, AMDTP_IN_STREAM); | ||
| 140 | destroy_stream(ff, AMDTP_OUT_STREAM); | ||
| 141 | } | ||
| 142 | |||
| 143 | int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) | ||
| 144 | { | ||
| 145 | unsigned int curr_rate; | ||
| 146 | enum snd_ff_clock_src src; | ||
| 147 | int err; | ||
| 148 | |||
| 149 | if (ff->substreams_counter == 0) | ||
| 150 | return 0; | ||
| 151 | |||
| 152 | err = ff->spec->protocol->get_clock(ff, &curr_rate, &src); | ||
| 153 | if (err < 0) | ||
| 154 | return err; | ||
| 155 | if (curr_rate != rate || | ||
| 156 | amdtp_streaming_error(&ff->tx_stream) || | ||
| 157 | amdtp_streaming_error(&ff->rx_stream)) { | ||
| 158 | finish_session(ff); | ||
| 159 | |||
| 160 | amdtp_stream_stop(&ff->tx_stream); | ||
| 161 | amdtp_stream_stop(&ff->rx_stream); | ||
| 162 | |||
| 163 | release_resources(ff); | ||
| 164 | } | ||
| 165 | |||
| 166 | /* | ||
| 167 | * Regardless of current source of clock signal, drivers transfer some | ||
| 168 | * packets. Then, the device transfers packets. | ||
| 169 | */ | ||
| 170 | if (!amdtp_stream_running(&ff->rx_stream)) { | ||
| 171 | err = keep_resources(ff, rate); | ||
| 172 | if (err < 0) | ||
| 173 | goto error; | ||
| 174 | |||
| 175 | err = ff->spec->protocol->begin_session(ff, rate); | ||
| 176 | if (err < 0) | ||
| 177 | goto error; | ||
| 178 | |||
| 179 | err = amdtp_stream_start(&ff->rx_stream, | ||
| 180 | ff->rx_resources.channel, | ||
| 181 | fw_parent_device(ff->unit)->max_speed); | ||
| 182 | if (err < 0) | ||
| 183 | goto error; | ||
| 184 | |||
| 185 | if (!amdtp_stream_wait_callback(&ff->rx_stream, | ||
| 186 | CALLBACK_TIMEOUT_MS)) { | ||
| 187 | err = -ETIMEDOUT; | ||
| 188 | goto error; | ||
| 189 | } | ||
| 190 | |||
| 191 | err = ff->spec->protocol->switch_fetching_mode(ff, true); | ||
| 192 | if (err < 0) | ||
| 193 | goto error; | ||
| 194 | } | ||
| 195 | |||
| 196 | if (!amdtp_stream_running(&ff->tx_stream)) { | ||
| 197 | err = amdtp_stream_start(&ff->tx_stream, | ||
| 198 | ff->tx_resources.channel, | ||
| 199 | fw_parent_device(ff->unit)->max_speed); | ||
| 200 | if (err < 0) | ||
| 201 | goto error; | ||
| 202 | |||
| 203 | if (!amdtp_stream_wait_callback(&ff->tx_stream, | ||
| 204 | CALLBACK_TIMEOUT_MS)) { | ||
| 205 | err = -ETIMEDOUT; | ||
| 206 | goto error; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | error: | ||
| 212 | amdtp_stream_stop(&ff->tx_stream); | ||
| 213 | amdtp_stream_stop(&ff->rx_stream); | ||
| 214 | |||
| 215 | finish_session(ff); | ||
| 216 | release_resources(ff); | ||
| 217 | |||
| 218 | return err; | ||
| 219 | } | ||
| 220 | |||
| 221 | void snd_ff_stream_stop_duplex(struct snd_ff *ff) | ||
| 222 | { | ||
| 223 | if (ff->substreams_counter > 0) | ||
| 224 | return; | ||
| 225 | |||
| 226 | amdtp_stream_stop(&ff->tx_stream); | ||
| 227 | amdtp_stream_stop(&ff->rx_stream); | ||
| 228 | finish_session(ff); | ||
| 229 | release_resources(ff); | ||
| 230 | } | ||
| 231 | |||
| 232 | void snd_ff_stream_update_duplex(struct snd_ff *ff) | ||
| 233 | { | ||
| 234 | /* The device discontinue to transfer packets. */ | ||
| 235 | amdtp_stream_pcm_abort(&ff->tx_stream); | ||
| 236 | amdtp_stream_stop(&ff->tx_stream); | ||
| 237 | |||
| 238 | amdtp_stream_pcm_abort(&ff->rx_stream); | ||
| 239 | amdtp_stream_stop(&ff->rx_stream); | ||
| 240 | |||
| 241 | fw_iso_resources_update(&ff->tx_resources); | ||
| 242 | fw_iso_resources_update(&ff->rx_resources); | ||
| 243 | } | ||
| 244 | |||
| 245 | void snd_ff_stream_lock_changed(struct snd_ff *ff) | ||
| 246 | { | ||
| 247 | ff->dev_lock_changed = true; | ||
| 248 | wake_up(&ff->hwdep_wait); | ||
| 249 | } | ||
| 250 | |||
| 251 | int snd_ff_stream_lock_try(struct snd_ff *ff) | ||
| 252 | { | ||
| 253 | int err; | ||
| 254 | |||
| 255 | spin_lock_irq(&ff->lock); | ||
| 256 | |||
| 257 | /* user land lock this */ | ||
| 258 | if (ff->dev_lock_count < 0) { | ||
| 259 | err = -EBUSY; | ||
| 260 | goto end; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* this is the first time */ | ||
| 264 | if (ff->dev_lock_count++ == 0) | ||
| 265 | snd_ff_stream_lock_changed(ff); | ||
| 266 | err = 0; | ||
| 267 | end: | ||
| 268 | spin_unlock_irq(&ff->lock); | ||
| 269 | return err; | ||
| 270 | } | ||
| 271 | |||
| 272 | void snd_ff_stream_lock_release(struct snd_ff *ff) | ||
| 273 | { | ||
| 274 | spin_lock_irq(&ff->lock); | ||
| 275 | |||
| 276 | if (WARN_ON(ff->dev_lock_count <= 0)) | ||
| 277 | goto end; | ||
| 278 | if (--ff->dev_lock_count == 0) | ||
| 279 | snd_ff_stream_lock_changed(ff); | ||
| 280 | end: | ||
| 281 | spin_unlock_irq(&ff->lock); | ||
| 282 | } | ||
diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c new file mode 100644 index 000000000000..dd6c8e839647 --- /dev/null +++ b/sound/firewire/fireface/ff-transaction.c | |||
| @@ -0,0 +1,295 @@ | |||
| 1 | /* | ||
| 2 | * ff-transaction.c - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "ff.h" | ||
| 10 | |||
| 11 | static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port, | ||
| 12 | int rcode) | ||
| 13 | { | ||
| 14 | struct snd_rawmidi_substream *substream = | ||
| 15 | ACCESS_ONCE(ff->rx_midi_substreams[port]); | ||
| 16 | |||
| 17 | if (rcode_is_permanent_error(rcode)) { | ||
| 18 | ff->rx_midi_error[port] = true; | ||
| 19 | return; | ||
| 20 | } | ||
| 21 | |||
| 22 | if (rcode != RCODE_COMPLETE) { | ||
| 23 | /* Transfer the message again, immediately. */ | ||
| 24 | ff->next_ktime[port] = 0; | ||
| 25 | schedule_work(&ff->rx_midi_work[port]); | ||
| 26 | return; | ||
| 27 | } | ||
| 28 | |||
| 29 | snd_rawmidi_transmit_ack(substream, ff->rx_bytes[port]); | ||
| 30 | ff->rx_bytes[port] = 0; | ||
| 31 | |||
| 32 | if (!snd_rawmidi_transmit_empty(substream)) | ||
| 33 | schedule_work(&ff->rx_midi_work[port]); | ||
| 34 | } | ||
| 35 | |||
| 36 | static void finish_transmit_midi0_msg(struct fw_card *card, int rcode, | ||
| 37 | void *data, size_t length, | ||
| 38 | void *callback_data) | ||
| 39 | { | ||
| 40 | struct snd_ff *ff = | ||
| 41 | container_of(callback_data, struct snd_ff, transactions[0]); | ||
| 42 | finish_transmit_midi_msg(ff, 0, rcode); | ||
| 43 | } | ||
| 44 | |||
| 45 | static void finish_transmit_midi1_msg(struct fw_card *card, int rcode, | ||
| 46 | void *data, size_t length, | ||
| 47 | void *callback_data) | ||
| 48 | { | ||
| 49 | struct snd_ff *ff = | ||
| 50 | container_of(callback_data, struct snd_ff, transactions[1]); | ||
| 51 | finish_transmit_midi_msg(ff, 1, rcode); | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline void fill_midi_buf(struct snd_ff *ff, unsigned int port, | ||
| 55 | unsigned int index, u8 byte) | ||
| 56 | { | ||
| 57 | ff->msg_buf[port][index] = cpu_to_le32(byte); | ||
| 58 | } | ||
| 59 | |||
| 60 | static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) | ||
| 61 | { | ||
| 62 | struct snd_rawmidi_substream *substream = | ||
| 63 | ACCESS_ONCE(ff->rx_midi_substreams[port]); | ||
| 64 | u8 *buf = (u8 *)ff->msg_buf[port]; | ||
| 65 | int i, len; | ||
| 66 | |||
| 67 | struct fw_device *fw_dev = fw_parent_device(ff->unit); | ||
| 68 | unsigned long long addr; | ||
| 69 | int generation; | ||
| 70 | fw_transaction_callback_t callback; | ||
| 71 | |||
| 72 | if (substream == NULL || snd_rawmidi_transmit_empty(substream)) | ||
| 73 | return; | ||
| 74 | |||
| 75 | if (ff->rx_bytes[port] > 0 || ff->rx_midi_error[port]) | ||
| 76 | return; | ||
| 77 | |||
| 78 | /* Do it in next chance. */ | ||
| 79 | if (ktime_after(ff->next_ktime[port], ktime_get())) { | ||
| 80 | schedule_work(&ff->rx_midi_work[port]); | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | |||
| 84 | len = snd_rawmidi_transmit_peek(substream, buf, | ||
| 85 | SND_FF_MAXIMIM_MIDI_QUADS); | ||
| 86 | if (len <= 0) | ||
| 87 | return; | ||
| 88 | |||
| 89 | for (i = len - 1; i >= 0; i--) | ||
| 90 | fill_midi_buf(ff, port, i, buf[i]); | ||
| 91 | |||
| 92 | if (port == 0) { | ||
| 93 | addr = ff->spec->protocol->midi_rx_port_0_reg; | ||
| 94 | callback = finish_transmit_midi0_msg; | ||
| 95 | } else { | ||
| 96 | addr = ff->spec->protocol->midi_rx_port_1_reg; | ||
| 97 | callback = finish_transmit_midi1_msg; | ||
| 98 | } | ||
| 99 | |||
| 100 | /* Set interval to next transaction. */ | ||
| 101 | ff->next_ktime[port] = ktime_add_ns(ktime_get(), | ||
| 102 | len * 8 * NSEC_PER_SEC / 31250); | ||
| 103 | ff->rx_bytes[port] = len; | ||
| 104 | |||
| 105 | /* | ||
| 106 | * In Linux FireWire core, when generation is updated with memory | ||
| 107 | * barrier, node id has already been updated. In this module, After | ||
| 108 | * this smp_rmb(), load/store instructions to memory are completed. | ||
| 109 | * Thus, both of generation and node id are available with recent | ||
| 110 | * values. This is a light-serialization solution to handle bus reset | ||
| 111 | * events on IEEE 1394 bus. | ||
| 112 | */ | ||
| 113 | generation = fw_dev->generation; | ||
| 114 | smp_rmb(); | ||
| 115 | fw_send_request(fw_dev->card, &ff->transactions[port], | ||
| 116 | TCODE_WRITE_BLOCK_REQUEST, | ||
| 117 | fw_dev->node_id, generation, fw_dev->max_speed, | ||
| 118 | addr, &ff->msg_buf[port], len * 4, | ||
| 119 | callback, &ff->transactions[port]); | ||
| 120 | } | ||
| 121 | |||
| 122 | static void transmit_midi0_msg(struct work_struct *work) | ||
| 123 | { | ||
| 124 | struct snd_ff *ff = container_of(work, struct snd_ff, rx_midi_work[0]); | ||
| 125 | |||
| 126 | transmit_midi_msg(ff, 0); | ||
| 127 | } | ||
| 128 | |||
| 129 | static void transmit_midi1_msg(struct work_struct *work) | ||
| 130 | { | ||
| 131 | struct snd_ff *ff = container_of(work, struct snd_ff, rx_midi_work[1]); | ||
| 132 | |||
| 133 | transmit_midi_msg(ff, 1); | ||
| 134 | } | ||
| 135 | |||
| 136 | static void handle_midi_msg(struct fw_card *card, struct fw_request *request, | ||
| 137 | int tcode, int destination, int source, | ||
| 138 | int generation, unsigned long long offset, | ||
| 139 | void *data, size_t length, void *callback_data) | ||
| 140 | { | ||
| 141 | struct snd_ff *ff = callback_data; | ||
| 142 | __le32 *buf = data; | ||
| 143 | u32 quad; | ||
| 144 | u8 byte; | ||
| 145 | unsigned int index; | ||
| 146 | struct snd_rawmidi_substream *substream; | ||
| 147 | int i; | ||
| 148 | |||
| 149 | fw_send_response(card, request, RCODE_COMPLETE); | ||
| 150 | |||
| 151 | for (i = 0; i < length / 4; i++) { | ||
| 152 | quad = le32_to_cpu(buf[i]); | ||
| 153 | |||
| 154 | /* Message in first port. */ | ||
| 155 | /* | ||
| 156 | * This value may represent the index of this unit when the same | ||
| 157 | * units are on the same IEEE 1394 bus. This driver doesn't use | ||
| 158 | * it. | ||
| 159 | */ | ||
| 160 | index = (quad >> 8) & 0xff; | ||
| 161 | if (index > 0) { | ||
| 162 | substream = ACCESS_ONCE(ff->tx_midi_substreams[0]); | ||
| 163 | if (substream != NULL) { | ||
| 164 | byte = quad & 0xff; | ||
| 165 | snd_rawmidi_receive(substream, &byte, 1); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | /* Message in second port. */ | ||
| 170 | index = (quad >> 24) & 0xff; | ||
| 171 | if (index > 0) { | ||
| 172 | substream = ACCESS_ONCE(ff->tx_midi_substreams[1]); | ||
| 173 | if (substream != NULL) { | ||
| 174 | byte = (quad >> 16) & 0xff; | ||
| 175 | snd_rawmidi_receive(substream, &byte, 1); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | static int allocate_own_address(struct snd_ff *ff, int i) | ||
| 182 | { | ||
| 183 | struct fw_address_region midi_msg_region; | ||
| 184 | int err; | ||
| 185 | |||
| 186 | ff->async_handler.length = SND_FF_MAXIMIM_MIDI_QUADS * 4; | ||
| 187 | ff->async_handler.address_callback = handle_midi_msg; | ||
| 188 | ff->async_handler.callback_data = ff; | ||
| 189 | |||
| 190 | midi_msg_region.start = 0x000100000000ull * i; | ||
| 191 | midi_msg_region.end = midi_msg_region.start + ff->async_handler.length; | ||
| 192 | |||
| 193 | err = fw_core_add_address_handler(&ff->async_handler, &midi_msg_region); | ||
| 194 | if (err >= 0) { | ||
| 195 | /* Controllers are allowed to register this region. */ | ||
| 196 | if (ff->async_handler.offset & 0x0000ffffffff) { | ||
| 197 | fw_core_remove_address_handler(&ff->async_handler); | ||
| 198 | err = -EAGAIN; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | return err; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* | ||
| 206 | * The configuration to start asynchronous transactions for MIDI messages is in | ||
| 207 | * 0x'0000'8010'051c. This register includes the other options, thus this driver | ||
| 208 | * doesn't touch it and leaves the decision to userspace. The userspace MUST add | ||
| 209 | * 0x04000000 to write transactions to the register to receive any MIDI | ||
| 210 | * messages. | ||
| 211 | * | ||
| 212 | * Here, I just describe MIDI-related offsets of the register, in little-endian | ||
| 213 | * order. | ||
| 214 | * | ||
| 215 | * Controllers are allowed to register higher 4 bytes of address to receive | ||
| 216 | * the transactions. The register is 0x'0000'8010'03f4. On the other hand, the | ||
| 217 | * controllers are not allowed to register lower 4 bytes of the address. They | ||
| 218 | * are forced to select from 4 options by writing corresponding bits to | ||
| 219 | * 0x'0000'8010'051c. | ||
| 220 | * | ||
| 221 | * The 3rd-6th bits in MSB of this register are used to indicate lower 4 bytes | ||
| 222 | * of address to which the device transferrs the transactions. | ||
| 223 | * - 6th: 0x'....'....'0000'0180 | ||
| 224 | * - 5th: 0x'....'....'0000'0100 | ||
| 225 | * - 4th: 0x'....'....'0000'0080 | ||
| 226 | * - 3rd: 0x'....'....'0000'0000 | ||
| 227 | * | ||
| 228 | * This driver configure 0x'....'....'0000'0000 for units to receive MIDI | ||
| 229 | * messages. 3rd bit of the register should be configured, however this driver | ||
| 230 | * deligates this task to user space applications due to a restriction that | ||
| 231 | * this register is write-only and the other bits have own effects. | ||
| 232 | * | ||
| 233 | * The 1st and 2nd bits in LSB of this register are used to cancel transferring | ||
| 234 | * asynchronous transactions. These two bits have the same effect. | ||
| 235 | * - 1st/2nd: cancel transferring | ||
| 236 | */ | ||
| 237 | int snd_ff_transaction_reregister(struct snd_ff *ff) | ||
| 238 | { | ||
| 239 | struct fw_card *fw_card = fw_parent_device(ff->unit)->card; | ||
| 240 | u32 addr; | ||
| 241 | __le32 reg; | ||
| 242 | |||
| 243 | /* | ||
| 244 | * Controllers are allowed to register its node ID and upper 2 byte of | ||
| 245 | * local address to listen asynchronous transactions. | ||
| 246 | */ | ||
| 247 | addr = (fw_card->node_id << 16) | (ff->async_handler.offset >> 32); | ||
| 248 | reg = cpu_to_le32(addr); | ||
| 249 | return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
| 250 | ff->spec->protocol->midi_high_addr_reg, | ||
| 251 | ®, sizeof(reg), 0); | ||
| 252 | } | ||
| 253 | |||
| 254 | int snd_ff_transaction_register(struct snd_ff *ff) | ||
| 255 | { | ||
| 256 | int i, err; | ||
| 257 | |||
| 258 | /* | ||
| 259 | * Allocate in Memory Space of IEC 13213, but lower 4 byte in LSB should | ||
| 260 | * be zero due to device specification. | ||
| 261 | */ | ||
| 262 | for (i = 0; i < 0xffff; i++) { | ||
| 263 | err = allocate_own_address(ff, i); | ||
| 264 | if (err != -EBUSY && err != -EAGAIN) | ||
| 265 | break; | ||
| 266 | } | ||
| 267 | if (err < 0) | ||
| 268 | return err; | ||
| 269 | |||
| 270 | err = snd_ff_transaction_reregister(ff); | ||
| 271 | if (err < 0) | ||
| 272 | return err; | ||
| 273 | |||
| 274 | INIT_WORK(&ff->rx_midi_work[0], transmit_midi0_msg); | ||
| 275 | INIT_WORK(&ff->rx_midi_work[1], transmit_midi1_msg); | ||
| 276 | |||
| 277 | return 0; | ||
| 278 | } | ||
| 279 | |||
| 280 | void snd_ff_transaction_unregister(struct snd_ff *ff) | ||
| 281 | { | ||
| 282 | __le32 reg; | ||
| 283 | |||
| 284 | if (ff->async_handler.callback_data == NULL) | ||
| 285 | return; | ||
| 286 | ff->async_handler.callback_data = NULL; | ||
| 287 | |||
| 288 | /* Release higher 4 bytes of address. */ | ||
| 289 | reg = cpu_to_le32(0x00000000); | ||
| 290 | snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
| 291 | ff->spec->protocol->midi_high_addr_reg, | ||
| 292 | ®, sizeof(reg), 0); | ||
| 293 | |||
| 294 | fw_core_remove_address_handler(&ff->async_handler); | ||
| 295 | } | ||
diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c new file mode 100644 index 000000000000..eee7c8eac7a6 --- /dev/null +++ b/sound/firewire/fireface/ff.c | |||
| @@ -0,0 +1,209 @@ | |||
| 1 | /* | ||
| 2 | * ff.c - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "ff.h" | ||
| 10 | |||
| 11 | #define OUI_RME 0x000a35 | ||
| 12 | |||
| 13 | MODULE_DESCRIPTION("RME Fireface series Driver"); | ||
| 14 | MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>"); | ||
| 15 | MODULE_LICENSE("GPL v2"); | ||
| 16 | |||
| 17 | static void name_card(struct snd_ff *ff) | ||
| 18 | { | ||
| 19 | struct fw_device *fw_dev = fw_parent_device(ff->unit); | ||
| 20 | |||
| 21 | strcpy(ff->card->driver, "Fireface"); | ||
| 22 | strcpy(ff->card->shortname, ff->spec->name); | ||
| 23 | strcpy(ff->card->mixername, ff->spec->name); | ||
| 24 | snprintf(ff->card->longname, sizeof(ff->card->longname), | ||
| 25 | "RME %s, GUID %08x%08x at %s, S%d", ff->spec->name, | ||
| 26 | fw_dev->config_rom[3], fw_dev->config_rom[4], | ||
| 27 | dev_name(&ff->unit->device), 100 << fw_dev->max_speed); | ||
| 28 | } | ||
| 29 | |||
| 30 | static void ff_free(struct snd_ff *ff) | ||
| 31 | { | ||
| 32 | snd_ff_stream_destroy_duplex(ff); | ||
| 33 | snd_ff_transaction_unregister(ff); | ||
| 34 | |||
| 35 | fw_unit_put(ff->unit); | ||
| 36 | |||
| 37 | mutex_destroy(&ff->mutex); | ||
| 38 | kfree(ff); | ||
| 39 | } | ||
| 40 | |||
| 41 | static void ff_card_free(struct snd_card *card) | ||
| 42 | { | ||
| 43 | ff_free(card->private_data); | ||
| 44 | } | ||
| 45 | |||
| 46 | static void do_registration(struct work_struct *work) | ||
| 47 | { | ||
| 48 | struct snd_ff *ff = container_of(work, struct snd_ff, dwork.work); | ||
| 49 | int err; | ||
| 50 | |||
| 51 | if (ff->registered) | ||
| 52 | return; | ||
| 53 | |||
| 54 | err = snd_card_new(&ff->unit->device, -1, NULL, THIS_MODULE, 0, | ||
| 55 | &ff->card); | ||
| 56 | if (err < 0) | ||
| 57 | return; | ||
| 58 | |||
| 59 | err = snd_ff_transaction_register(ff); | ||
| 60 | if (err < 0) | ||
| 61 | goto error; | ||
| 62 | |||
| 63 | name_card(ff); | ||
| 64 | |||
| 65 | err = snd_ff_stream_init_duplex(ff); | ||
| 66 | if (err < 0) | ||
| 67 | goto error; | ||
| 68 | |||
| 69 | snd_ff_proc_init(ff); | ||
| 70 | |||
| 71 | err = snd_ff_create_midi_devices(ff); | ||
| 72 | if (err < 0) | ||
| 73 | goto error; | ||
| 74 | |||
| 75 | err = snd_ff_create_pcm_devices(ff); | ||
| 76 | if (err < 0) | ||
| 77 | goto error; | ||
| 78 | |||
| 79 | err = snd_ff_create_hwdep_devices(ff); | ||
| 80 | if (err < 0) | ||
| 81 | goto error; | ||
| 82 | |||
| 83 | err = snd_card_register(ff->card); | ||
| 84 | if (err < 0) | ||
| 85 | goto error; | ||
| 86 | |||
| 87 | ff->card->private_free = ff_card_free; | ||
| 88 | ff->card->private_data = ff; | ||
| 89 | ff->registered = true; | ||
| 90 | |||
| 91 | return; | ||
| 92 | error: | ||
| 93 | snd_ff_transaction_unregister(ff); | ||
| 94 | snd_ff_stream_destroy_duplex(ff); | ||
| 95 | snd_card_free(ff->card); | ||
| 96 | dev_info(&ff->unit->device, | ||
| 97 | "Sound card registration failed: %d\n", err); | ||
| 98 | } | ||
| 99 | |||
| 100 | static int snd_ff_probe(struct fw_unit *unit, | ||
| 101 | const struct ieee1394_device_id *entry) | ||
| 102 | { | ||
| 103 | struct snd_ff *ff; | ||
| 104 | |||
| 105 | ff = kzalloc(sizeof(struct snd_ff), GFP_KERNEL); | ||
| 106 | if (ff == NULL) | ||
| 107 | return -ENOMEM; | ||
| 108 | |||
| 109 | /* initialize myself */ | ||
| 110 | ff->unit = fw_unit_get(unit); | ||
| 111 | dev_set_drvdata(&unit->device, ff); | ||
| 112 | |||
| 113 | mutex_init(&ff->mutex); | ||
| 114 | spin_lock_init(&ff->lock); | ||
| 115 | init_waitqueue_head(&ff->hwdep_wait); | ||
| 116 | |||
| 117 | ff->spec = (const struct snd_ff_spec *)entry->driver_data; | ||
| 118 | |||
| 119 | /* Register this sound card later. */ | ||
| 120 | INIT_DEFERRABLE_WORK(&ff->dwork, do_registration); | ||
| 121 | snd_fw_schedule_registration(unit, &ff->dwork); | ||
| 122 | |||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | static void snd_ff_update(struct fw_unit *unit) | ||
| 127 | { | ||
| 128 | struct snd_ff *ff = dev_get_drvdata(&unit->device); | ||
| 129 | |||
| 130 | /* Postpone a workqueue for deferred registration. */ | ||
| 131 | if (!ff->registered) | ||
| 132 | snd_fw_schedule_registration(unit, &ff->dwork); | ||
| 133 | |||
| 134 | snd_ff_transaction_reregister(ff); | ||
| 135 | |||
| 136 | if (ff->registered) | ||
| 137 | snd_ff_stream_update_duplex(ff); | ||
| 138 | } | ||
| 139 | |||
| 140 | static void snd_ff_remove(struct fw_unit *unit) | ||
| 141 | { | ||
| 142 | struct snd_ff *ff = dev_get_drvdata(&unit->device); | ||
| 143 | |||
| 144 | /* | ||
| 145 | * Confirm to stop the work for registration before the sound card is | ||
| 146 | * going to be released. The work is not scheduled again because bus | ||
| 147 | * reset handler is not called anymore. | ||
| 148 | */ | ||
| 149 | cancel_work_sync(&ff->dwork.work); | ||
| 150 | |||
| 151 | if (ff->registered) { | ||
| 152 | /* No need to wait for releasing card object in this context. */ | ||
| 153 | snd_card_free_when_closed(ff->card); | ||
| 154 | } else { | ||
| 155 | /* Don't forget this case. */ | ||
| 156 | ff_free(ff); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | static struct snd_ff_spec spec_ff400 = { | ||
| 161 | .name = "Fireface400", | ||
| 162 | .pcm_capture_channels = {18, 14, 10}, | ||
| 163 | .pcm_playback_channels = {18, 14, 10}, | ||
| 164 | .midi_in_ports = 2, | ||
| 165 | .midi_out_ports = 2, | ||
| 166 | .protocol = &snd_ff_protocol_ff400, | ||
| 167 | }; | ||
| 168 | |||
| 169 | static const struct ieee1394_device_id snd_ff_id_table[] = { | ||
| 170 | /* Fireface 400 */ | ||
| 171 | { | ||
| 172 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
| 173 | IEEE1394_MATCH_SPECIFIER_ID | | ||
| 174 | IEEE1394_MATCH_VERSION | | ||
| 175 | IEEE1394_MATCH_MODEL_ID, | ||
| 176 | .vendor_id = OUI_RME, | ||
| 177 | .specifier_id = 0x000a35, | ||
| 178 | .version = 0x000002, | ||
| 179 | .model_id = 0x101800, | ||
| 180 | .driver_data = (kernel_ulong_t)&spec_ff400, | ||
| 181 | }, | ||
| 182 | {} | ||
| 183 | }; | ||
| 184 | MODULE_DEVICE_TABLE(ieee1394, snd_ff_id_table); | ||
| 185 | |||
| 186 | static struct fw_driver ff_driver = { | ||
| 187 | .driver = { | ||
| 188 | .owner = THIS_MODULE, | ||
| 189 | .name = "snd-fireface", | ||
| 190 | .bus = &fw_bus_type, | ||
| 191 | }, | ||
| 192 | .probe = snd_ff_probe, | ||
| 193 | .update = snd_ff_update, | ||
| 194 | .remove = snd_ff_remove, | ||
| 195 | .id_table = snd_ff_id_table, | ||
| 196 | }; | ||
| 197 | |||
| 198 | static int __init snd_ff_init(void) | ||
| 199 | { | ||
| 200 | return driver_register(&ff_driver.driver); | ||
| 201 | } | ||
| 202 | |||
| 203 | static void __exit snd_ff_exit(void) | ||
| 204 | { | ||
| 205 | driver_unregister(&ff_driver.driver); | ||
| 206 | } | ||
| 207 | |||
| 208 | module_init(snd_ff_init); | ||
| 209 | module_exit(snd_ff_exit); | ||
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h new file mode 100644 index 000000000000..3cb812a50030 --- /dev/null +++ b/sound/firewire/fireface/ff.h | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | /* | ||
| 2 | * ff.h - a part of driver for RME Fireface series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef SOUND_FIREFACE_H_INCLUDED | ||
| 10 | #define SOUND_FIREFACE_H_INCLUDED | ||
| 11 | |||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/firewire.h> | ||
| 14 | #include <linux/firewire-constants.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/mod_devicetable.h> | ||
| 17 | #include <linux/mutex.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/compat.h> | ||
| 20 | #include <linux/sched/signal.h> | ||
| 21 | |||
| 22 | #include <sound/core.h> | ||
| 23 | #include <sound/info.h> | ||
| 24 | #include <sound/rawmidi.h> | ||
| 25 | #include <sound/pcm.h> | ||
| 26 | #include <sound/pcm_params.h> | ||
| 27 | #include <sound/hwdep.h> | ||
| 28 | #include <sound/firewire.h> | ||
| 29 | |||
| 30 | #include "../lib.h" | ||
| 31 | #include "../amdtp-stream.h" | ||
| 32 | #include "../iso-resources.h" | ||
| 33 | |||
| 34 | #define SND_FF_STREAM_MODES 3 | ||
| 35 | |||
| 36 | #define SND_FF_MAXIMIM_MIDI_QUADS 9 | ||
| 37 | #define SND_FF_IN_MIDI_PORTS 2 | ||
| 38 | #define SND_FF_OUT_MIDI_PORTS 2 | ||
| 39 | |||
| 40 | struct snd_ff_protocol; | ||
| 41 | struct snd_ff_spec { | ||
| 42 | const char *const name; | ||
| 43 | |||
| 44 | const unsigned int pcm_capture_channels[SND_FF_STREAM_MODES]; | ||
| 45 | const unsigned int pcm_playback_channels[SND_FF_STREAM_MODES]; | ||
| 46 | |||
| 47 | unsigned int midi_in_ports; | ||
| 48 | unsigned int midi_out_ports; | ||
| 49 | |||
| 50 | struct snd_ff_protocol *protocol; | ||
| 51 | }; | ||
| 52 | |||
| 53 | struct snd_ff { | ||
| 54 | struct snd_card *card; | ||
| 55 | struct fw_unit *unit; | ||
| 56 | struct mutex mutex; | ||
| 57 | spinlock_t lock; | ||
| 58 | |||
| 59 | bool registered; | ||
| 60 | struct delayed_work dwork; | ||
| 61 | |||
| 62 | const struct snd_ff_spec *spec; | ||
| 63 | |||
| 64 | /* To handle MIDI tx. */ | ||
| 65 | struct snd_rawmidi_substream *tx_midi_substreams[SND_FF_IN_MIDI_PORTS]; | ||
| 66 | struct fw_address_handler async_handler; | ||
| 67 | |||
| 68 | /* TO handle MIDI rx. */ | ||
| 69 | struct snd_rawmidi_substream *rx_midi_substreams[SND_FF_OUT_MIDI_PORTS]; | ||
| 70 | u8 running_status[SND_FF_OUT_MIDI_PORTS]; | ||
| 71 | __le32 msg_buf[SND_FF_OUT_MIDI_PORTS][SND_FF_MAXIMIM_MIDI_QUADS]; | ||
| 72 | struct work_struct rx_midi_work[SND_FF_OUT_MIDI_PORTS]; | ||
| 73 | struct fw_transaction transactions[SND_FF_OUT_MIDI_PORTS]; | ||
| 74 | ktime_t next_ktime[SND_FF_OUT_MIDI_PORTS]; | ||
| 75 | bool rx_midi_error[SND_FF_OUT_MIDI_PORTS]; | ||
| 76 | unsigned int rx_bytes[SND_FF_OUT_MIDI_PORTS]; | ||
| 77 | |||
| 78 | unsigned int substreams_counter; | ||
| 79 | struct amdtp_stream tx_stream; | ||
| 80 | struct amdtp_stream rx_stream; | ||
| 81 | struct fw_iso_resources tx_resources; | ||
| 82 | struct fw_iso_resources rx_resources; | ||
| 83 | |||
| 84 | int dev_lock_count; | ||
| 85 | bool dev_lock_changed; | ||
| 86 | wait_queue_head_t hwdep_wait; | ||
| 87 | }; | ||
| 88 | |||
| 89 | enum snd_ff_clock_src { | ||
| 90 | SND_FF_CLOCK_SRC_INTERNAL, | ||
| 91 | SND_FF_CLOCK_SRC_SPDIF, | ||
| 92 | SND_FF_CLOCK_SRC_ADAT, | ||
| 93 | SND_FF_CLOCK_SRC_WORD, | ||
| 94 | SND_FF_CLOCK_SRC_LTC, | ||
| 95 | /* TODO: perhaps ADAT2 and TCO exists. */ | ||
| 96 | }; | ||
| 97 | |||
| 98 | struct snd_ff_protocol { | ||
| 99 | int (*get_clock)(struct snd_ff *ff, unsigned int *rate, | ||
| 100 | enum snd_ff_clock_src *src); | ||
| 101 | int (*begin_session)(struct snd_ff *ff, unsigned int rate); | ||
| 102 | void (*finish_session)(struct snd_ff *ff); | ||
| 103 | int (*switch_fetching_mode)(struct snd_ff *ff, bool enable); | ||
| 104 | |||
| 105 | void (*dump_sync_status)(struct snd_ff *ff, | ||
| 106 | struct snd_info_buffer *buffer); | ||
| 107 | void (*dump_clock_config)(struct snd_ff *ff, | ||
| 108 | struct snd_info_buffer *buffer); | ||
| 109 | |||
| 110 | u64 midi_high_addr_reg; | ||
| 111 | u64 midi_rx_port_0_reg; | ||
| 112 | u64 midi_rx_port_1_reg; | ||
| 113 | }; | ||
| 114 | |||
| 115 | extern struct snd_ff_protocol snd_ff_protocol_ff400; | ||
| 116 | |||
| 117 | int snd_ff_transaction_register(struct snd_ff *ff); | ||
| 118 | int snd_ff_transaction_reregister(struct snd_ff *ff); | ||
| 119 | void snd_ff_transaction_unregister(struct snd_ff *ff); | ||
| 120 | |||
| 121 | int amdtp_ff_set_parameters(struct amdtp_stream *s, unsigned int rate, | ||
| 122 | unsigned int pcm_channels); | ||
| 123 | int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s, | ||
| 124 | struct snd_pcm_runtime *runtime); | ||
| 125 | int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit, | ||
| 126 | enum amdtp_stream_direction dir); | ||
| 127 | |||
| 128 | int snd_ff_stream_init_duplex(struct snd_ff *ff); | ||
| 129 | void snd_ff_stream_destroy_duplex(struct snd_ff *ff); | ||
| 130 | int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate); | ||
| 131 | void snd_ff_stream_stop_duplex(struct snd_ff *ff); | ||
| 132 | void snd_ff_stream_update_duplex(struct snd_ff *ff); | ||
| 133 | |||
| 134 | void snd_ff_stream_lock_changed(struct snd_ff *ff); | ||
| 135 | int snd_ff_stream_lock_try(struct snd_ff *ff); | ||
| 136 | void snd_ff_stream_lock_release(struct snd_ff *ff); | ||
| 137 | |||
| 138 | void snd_ff_proc_init(struct snd_ff *ff); | ||
| 139 | |||
| 140 | int snd_ff_create_midi_devices(struct snd_ff *ff); | ||
| 141 | |||
| 142 | int snd_ff_create_pcm_devices(struct snd_ff *ff); | ||
| 143 | |||
| 144 | int snd_ff_create_hwdep_devices(struct snd_ff *ff); | ||
| 145 | |||
| 146 | #endif | ||
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c index 7683238283b6..39dfa74906ef 100644 --- a/sound/firewire/lib.c +++ b/sound/firewire/lib.c | |||
| @@ -99,147 +99,6 @@ void snd_fw_schedule_registration(struct fw_unit *unit, | |||
| 99 | } | 99 | } |
| 100 | EXPORT_SYMBOL(snd_fw_schedule_registration); | 100 | EXPORT_SYMBOL(snd_fw_schedule_registration); |
| 101 | 101 | ||
| 102 | static void async_midi_port_callback(struct fw_card *card, int rcode, | ||
| 103 | void *data, size_t length, | ||
| 104 | void *callback_data) | ||
| 105 | { | ||
| 106 | struct snd_fw_async_midi_port *port = callback_data; | ||
| 107 | struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream); | ||
| 108 | |||
| 109 | /* This port is closed. */ | ||
| 110 | if (substream == NULL) | ||
| 111 | return; | ||
| 112 | |||
| 113 | if (rcode == RCODE_COMPLETE) | ||
| 114 | snd_rawmidi_transmit_ack(substream, port->consume_bytes); | ||
| 115 | else if (!rcode_is_permanent_error(rcode)) | ||
| 116 | /* To start next transaction immediately for recovery. */ | ||
| 117 | port->next_ktime = 0; | ||
| 118 | else | ||
| 119 | /* Don't continue processing. */ | ||
| 120 | port->error = true; | ||
| 121 | |||
| 122 | port->idling = true; | ||
| 123 | |||
| 124 | if (!snd_rawmidi_transmit_empty(substream)) | ||
| 125 | schedule_work(&port->work); | ||
| 126 | } | ||
| 127 | |||
| 128 | static void midi_port_work(struct work_struct *work) | ||
| 129 | { | ||
| 130 | struct snd_fw_async_midi_port *port = | ||
| 131 | container_of(work, struct snd_fw_async_midi_port, work); | ||
| 132 | struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream); | ||
| 133 | int generation; | ||
| 134 | int type; | ||
| 135 | |||
| 136 | /* Under transacting or error state. */ | ||
| 137 | if (!port->idling || port->error) | ||
| 138 | return; | ||
| 139 | |||
| 140 | /* Nothing to do. */ | ||
| 141 | if (substream == NULL || snd_rawmidi_transmit_empty(substream)) | ||
| 142 | return; | ||
| 143 | |||
| 144 | /* Do it in next chance. */ | ||
| 145 | if (ktime_after(port->next_ktime, ktime_get())) { | ||
| 146 | schedule_work(&port->work); | ||
| 147 | return; | ||
| 148 | } | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Fill the buffer. The callee must use snd_rawmidi_transmit_peek(). | ||
| 152 | * Later, snd_rawmidi_transmit_ack() is called. | ||
| 153 | */ | ||
| 154 | memset(port->buf, 0, port->len); | ||
| 155 | port->consume_bytes = port->fill(substream, port->buf); | ||
| 156 | if (port->consume_bytes <= 0) { | ||
| 157 | /* Do it in next chance, immediately. */ | ||
| 158 | if (port->consume_bytes == 0) { | ||
| 159 | port->next_ktime = 0; | ||
| 160 | schedule_work(&port->work); | ||
| 161 | } else { | ||
| 162 | /* Fatal error. */ | ||
| 163 | port->error = true; | ||
| 164 | } | ||
| 165 | return; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* Calculate type of transaction. */ | ||
| 169 | if (port->len == 4) | ||
| 170 | type = TCODE_WRITE_QUADLET_REQUEST; | ||
| 171 | else | ||
| 172 | type = TCODE_WRITE_BLOCK_REQUEST; | ||
| 173 | |||
| 174 | /* Set interval to next transaction. */ | ||
| 175 | port->next_ktime = ktime_add_ns(ktime_get(), | ||
| 176 | port->consume_bytes * 8 * NSEC_PER_SEC / 31250); | ||
| 177 | |||
| 178 | /* Start this transaction. */ | ||
| 179 | port->idling = false; | ||
| 180 | |||
| 181 | /* | ||
| 182 | * In Linux FireWire core, when generation is updated with memory | ||
| 183 | * barrier, node id has already been updated. In this module, After | ||
| 184 | * this smp_rmb(), load/store instructions to memory are completed. | ||
| 185 | * Thus, both of generation and node id are available with recent | ||
| 186 | * values. This is a light-serialization solution to handle bus reset | ||
| 187 | * events on IEEE 1394 bus. | ||
| 188 | */ | ||
| 189 | generation = port->parent->generation; | ||
| 190 | smp_rmb(); | ||
| 191 | |||
| 192 | fw_send_request(port->parent->card, &port->transaction, type, | ||
| 193 | port->parent->node_id, generation, | ||
| 194 | port->parent->max_speed, port->addr, | ||
| 195 | port->buf, port->len, async_midi_port_callback, | ||
| 196 | port); | ||
| 197 | } | ||
| 198 | |||
| 199 | /** | ||
| 200 | * snd_fw_async_midi_port_init - initialize asynchronous MIDI port structure | ||
| 201 | * @port: the asynchronous MIDI port to initialize | ||
| 202 | * @unit: the target of the asynchronous transaction | ||
| 203 | * @addr: the address to which transactions are transferred | ||
| 204 | * @len: the length of transaction | ||
| 205 | * @fill: the callback function to fill given buffer, and returns the | ||
| 206 | * number of consumed bytes for MIDI message. | ||
| 207 | * | ||
| 208 | */ | ||
| 209 | int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port, | ||
| 210 | struct fw_unit *unit, u64 addr, unsigned int len, | ||
| 211 | snd_fw_async_midi_port_fill fill) | ||
| 212 | { | ||
| 213 | port->len = DIV_ROUND_UP(len, 4) * 4; | ||
| 214 | port->buf = kzalloc(port->len, GFP_KERNEL); | ||
| 215 | if (port->buf == NULL) | ||
| 216 | return -ENOMEM; | ||
| 217 | |||
| 218 | port->parent = fw_parent_device(unit); | ||
| 219 | port->addr = addr; | ||
| 220 | port->fill = fill; | ||
| 221 | port->idling = true; | ||
| 222 | port->next_ktime = 0; | ||
| 223 | port->error = false; | ||
| 224 | |||
| 225 | INIT_WORK(&port->work, midi_port_work); | ||
| 226 | |||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | EXPORT_SYMBOL(snd_fw_async_midi_port_init); | ||
| 230 | |||
| 231 | /** | ||
| 232 | * snd_fw_async_midi_port_destroy - free asynchronous MIDI port structure | ||
| 233 | * @port: the asynchronous MIDI port structure | ||
| 234 | */ | ||
| 235 | void snd_fw_async_midi_port_destroy(struct snd_fw_async_midi_port *port) | ||
| 236 | { | ||
| 237 | snd_fw_async_midi_port_finish(port); | ||
| 238 | cancel_work_sync(&port->work); | ||
| 239 | kfree(port->buf); | ||
| 240 | } | ||
| 241 | EXPORT_SYMBOL(snd_fw_async_midi_port_destroy); | ||
| 242 | |||
| 243 | MODULE_DESCRIPTION("FireWire audio helper functions"); | 102 | MODULE_DESCRIPTION("FireWire audio helper functions"); |
| 244 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 103 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
| 245 | MODULE_LICENSE("GPL v2"); | 104 | MODULE_LICENSE("GPL v2"); |
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h index c3768cd494a5..eef70922ed89 100644 --- a/sound/firewire/lib.h +++ b/sound/firewire/lib.h | |||
| @@ -25,58 +25,4 @@ static inline bool rcode_is_permanent_error(int rcode) | |||
| 25 | void snd_fw_schedule_registration(struct fw_unit *unit, | 25 | void snd_fw_schedule_registration(struct fw_unit *unit, |
| 26 | struct delayed_work *dwork); | 26 | struct delayed_work *dwork); |
| 27 | 27 | ||
| 28 | struct snd_fw_async_midi_port; | ||
| 29 | typedef int (*snd_fw_async_midi_port_fill)( | ||
| 30 | struct snd_rawmidi_substream *substream, | ||
| 31 | u8 *buf); | ||
| 32 | |||
| 33 | struct snd_fw_async_midi_port { | ||
| 34 | struct fw_device *parent; | ||
| 35 | struct work_struct work; | ||
| 36 | bool idling; | ||
| 37 | ktime_t next_ktime; | ||
| 38 | bool error; | ||
| 39 | |||
| 40 | u64 addr; | ||
| 41 | struct fw_transaction transaction; | ||
| 42 | |||
| 43 | u8 *buf; | ||
| 44 | unsigned int len; | ||
| 45 | |||
| 46 | struct snd_rawmidi_substream *substream; | ||
| 47 | snd_fw_async_midi_port_fill fill; | ||
| 48 | int consume_bytes; | ||
| 49 | }; | ||
| 50 | |||
| 51 | int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port, | ||
| 52 | struct fw_unit *unit, u64 addr, unsigned int len, | ||
| 53 | snd_fw_async_midi_port_fill fill); | ||
| 54 | void snd_fw_async_midi_port_destroy(struct snd_fw_async_midi_port *port); | ||
| 55 | |||
| 56 | /** | ||
| 57 | * snd_fw_async_midi_port_run - run transactions for the async MIDI port | ||
| 58 | * @port: the asynchronous MIDI port | ||
| 59 | * @substream: the MIDI substream | ||
| 60 | */ | ||
| 61 | static inline void | ||
| 62 | snd_fw_async_midi_port_run(struct snd_fw_async_midi_port *port, | ||
| 63 | struct snd_rawmidi_substream *substream) | ||
| 64 | { | ||
| 65 | if (!port->error) { | ||
| 66 | port->substream = substream; | ||
| 67 | schedule_work(&port->work); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | /** | ||
| 72 | * snd_fw_async_midi_port_finish - finish the asynchronous MIDI port | ||
| 73 | * @port: the asynchronous MIDI port | ||
| 74 | */ | ||
| 75 | static inline void | ||
| 76 | snd_fw_async_midi_port_finish(struct snd_fw_async_midi_port *port) | ||
| 77 | { | ||
| 78 | port->substream = NULL; | ||
| 79 | port->error = false; | ||
| 80 | } | ||
| 81 | |||
| 82 | #endif | 28 | #endif |
diff --git a/sound/firewire/motu/Makefile b/sound/firewire/motu/Makefile new file mode 100644 index 000000000000..728f586e754b --- /dev/null +++ b/sound/firewire/motu/Makefile | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | CFLAGS_amdtp-motu.o := -I$(src) | ||
| 2 | |||
| 3 | snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \ | ||
| 4 | motu-proc.o motu-pcm.o motu-midi.o motu-hwdep.o \ | ||
| 5 | motu-protocol-v2.o motu-protocol-v3.o | ||
| 6 | obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o | ||
diff --git a/sound/firewire/motu/amdtp-motu-trace.h b/sound/firewire/motu/amdtp-motu-trace.h new file mode 100644 index 000000000000..cd0cbfa9f96f --- /dev/null +++ b/sound/firewire/motu/amdtp-motu-trace.h | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | /* | ||
| 2 | * amdtp-motu-trace.h - tracepoint definitions to dump a part of packet data | ||
| 3 | * | ||
| 4 | * Copyright (c) 2017 Takashi Sakamoto | ||
| 5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #undef TRACE_SYSTEM | ||
| 9 | #define TRACE_SYSTEM snd_firewire_motu | ||
| 10 | |||
| 11 | #if !defined(_SND_FIREWIRE_MOTU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 12 | #define _SND_FIREWIRE_MOTU_TRACE_H | ||
| 13 | |||
| 14 | #include <linux/tracepoint.h> | ||
| 15 | |||
| 16 | static void copy_sph(u32 *frame, __be32 *buffer, unsigned int data_blocks, | ||
| 17 | unsigned int data_block_quadlets); | ||
| 18 | static void copy_message(u64 *frames, __be32 *buffer, unsigned int data_blocks, | ||
| 19 | unsigned int data_block_quadlets); | ||
| 20 | |||
| 21 | TRACE_EVENT(in_data_block_sph, | ||
| 22 | TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer), | ||
| 23 | TP_ARGS(s, data_blocks, buffer), | ||
| 24 | TP_STRUCT__entry( | ||
| 25 | __field(int, src) | ||
| 26 | __field(int, dst) | ||
| 27 | __field(unsigned int, data_blocks) | ||
| 28 | __dynamic_array(u32, tstamps, data_blocks) | ||
| 29 | ), | ||
| 30 | TP_fast_assign( | ||
| 31 | __entry->src = fw_parent_device(s->unit)->node_id; | ||
| 32 | __entry->dst = fw_parent_device(s->unit)->card->node_id; | ||
| 33 | __entry->data_blocks = data_blocks; | ||
| 34 | copy_sph(__get_dynamic_array(tstamps), buffer, data_blocks, s->data_block_quadlets); | ||
| 35 | ), | ||
| 36 | TP_printk( | ||
| 37 | "%04x %04x %u %s", | ||
| 38 | __entry->src, | ||
| 39 | __entry->dst, | ||
| 40 | __entry->data_blocks, | ||
| 41 | __print_array(__get_dynamic_array(tstamps), __entry->data_blocks, 4) | ||
| 42 | ) | ||
| 43 | ); | ||
| 44 | |||
| 45 | TRACE_EVENT(out_data_block_sph, | ||
| 46 | TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer), | ||
| 47 | TP_ARGS(s, data_blocks, buffer), | ||
| 48 | TP_STRUCT__entry( | ||
| 49 | __field(int, src) | ||
| 50 | __field(int, dst) | ||
| 51 | __field(unsigned int, data_blocks) | ||
| 52 | __dynamic_array(u32, tstamps, data_blocks) | ||
| 53 | ), | ||
| 54 | TP_fast_assign( | ||
| 55 | __entry->src = fw_parent_device(s->unit)->card->node_id; | ||
| 56 | __entry->dst = fw_parent_device(s->unit)->node_id; | ||
| 57 | __entry->data_blocks = data_blocks; | ||
| 58 | copy_sph(__get_dynamic_array(tstamps), buffer, data_blocks, s->data_block_quadlets); | ||
| 59 | ), | ||
| 60 | TP_printk( | ||
| 61 | "%04x %04x %u %s", | ||
| 62 | __entry->src, | ||
| 63 | __entry->dst, | ||
| 64 | __entry->data_blocks, | ||
| 65 | __print_array(__get_dynamic_array(tstamps), __entry->data_blocks, 4) | ||
| 66 | ) | ||
| 67 | ); | ||
| 68 | |||
| 69 | TRACE_EVENT(in_data_block_message, | ||
| 70 | TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer), | ||
| 71 | TP_ARGS(s, data_blocks, buffer), | ||
| 72 | TP_STRUCT__entry( | ||
| 73 | __field(int, src) | ||
| 74 | __field(int, dst) | ||
| 75 | __field(unsigned int, data_blocks) | ||
| 76 | __dynamic_array(u64, messages, data_blocks) | ||
| 77 | ), | ||
| 78 | TP_fast_assign( | ||
| 79 | __entry->src = fw_parent_device(s->unit)->node_id; | ||
| 80 | __entry->dst = fw_parent_device(s->unit)->card->node_id; | ||
| 81 | __entry->data_blocks = data_blocks; | ||
| 82 | copy_message(__get_dynamic_array(messages), buffer, data_blocks, s->data_block_quadlets); | ||
| 83 | ), | ||
| 84 | TP_printk( | ||
| 85 | "%04x %04x %u %s", | ||
| 86 | __entry->src, | ||
| 87 | __entry->dst, | ||
| 88 | __entry->data_blocks, | ||
| 89 | __print_array(__get_dynamic_array(messages), __entry->data_blocks, 8) | ||
| 90 | ) | ||
| 91 | ); | ||
| 92 | |||
| 93 | TRACE_EVENT(out_data_block_message, | ||
| 94 | TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer), | ||
| 95 | TP_ARGS(s, data_blocks, buffer), | ||
| 96 | TP_STRUCT__entry( | ||
| 97 | __field(int, src) | ||
| 98 | __field(int, dst) | ||
| 99 | __field(unsigned int, data_blocks) | ||
| 100 | __dynamic_array(u64, messages, data_blocks) | ||
| 101 | ), | ||
| 102 | TP_fast_assign( | ||
| 103 | __entry->src = fw_parent_device(s->unit)->card->node_id; | ||
| 104 | __entry->dst = fw_parent_device(s->unit)->node_id; | ||
| 105 | __entry->data_blocks = data_blocks; | ||
| 106 | copy_message(__get_dynamic_array(messages), buffer, data_blocks, s->data_block_quadlets); | ||
| 107 | ), | ||
| 108 | TP_printk( | ||
| 109 | "%04x %04x %u %s", | ||
| 110 | __entry->src, | ||
| 111 | __entry->dst, | ||
| 112 | __entry->data_blocks, | ||
| 113 | __print_array(__get_dynamic_array(messages), __entry->data_blocks, 8) | ||
| 114 | ) | ||
| 115 | ); | ||
| 116 | |||
| 117 | #endif | ||
| 118 | |||
| 119 | #undef TRACE_INCLUDE_PATH | ||
| 120 | #define TRACE_INCLUDE_PATH . | ||
| 121 | #undef TRACE_INCLUDE_FILE | ||
| 122 | #define TRACE_INCLUDE_FILE amdtp-motu-trace | ||
| 123 | #include <trace/define_trace.h> | ||
diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c new file mode 100644 index 000000000000..96f0091144bb --- /dev/null +++ b/sound/firewire/motu/amdtp-motu.c | |||
| @@ -0,0 +1,427 @@ | |||
| 1 | /* | ||
| 2 | * amdtp-motu.c - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/slab.h> | ||
| 10 | #include <sound/pcm.h> | ||
| 11 | #include "motu.h" | ||
| 12 | |||
| 13 | #define CREATE_TRACE_POINTS | ||
| 14 | #include "amdtp-motu-trace.h" | ||
| 15 | |||
| 16 | #define CIP_FMT_MOTU 0x02 | ||
| 17 | #define CIP_FMT_MOTU_TX_V3 0x22 | ||
| 18 | #define MOTU_FDF_AM824 0x22 | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Nominally 3125 bytes/second, but the MIDI port's clock might be | ||
| 22 | * 1% too slow, and the bus clock 100 ppm too fast. | ||
| 23 | */ | ||
| 24 | #define MIDI_BYTES_PER_SECOND 3093 | ||
| 25 | |||
| 26 | struct amdtp_motu { | ||
| 27 | /* For timestamp processing. */ | ||
| 28 | unsigned int quotient_ticks_per_event; | ||
| 29 | unsigned int remainder_ticks_per_event; | ||
| 30 | unsigned int next_ticks; | ||
| 31 | unsigned int next_accumulated; | ||
| 32 | unsigned int next_cycles; | ||
| 33 | unsigned int next_seconds; | ||
| 34 | |||
| 35 | unsigned int pcm_chunks; | ||
| 36 | unsigned int pcm_byte_offset; | ||
| 37 | |||
| 38 | struct snd_rawmidi_substream *midi; | ||
| 39 | unsigned int midi_ports; | ||
| 40 | unsigned int midi_flag_offset; | ||
| 41 | unsigned int midi_byte_offset; | ||
| 42 | |||
| 43 | int midi_db_count; | ||
| 44 | unsigned int midi_db_interval; | ||
| 45 | }; | ||
| 46 | |||
| 47 | int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, | ||
| 48 | unsigned int midi_ports, | ||
| 49 | struct snd_motu_packet_format *formats) | ||
| 50 | { | ||
| 51 | static const struct { | ||
| 52 | unsigned int quotient_ticks_per_event; | ||
| 53 | unsigned int remainder_ticks_per_event; | ||
| 54 | } params[] = { | ||
| 55 | [CIP_SFC_44100] = { 557, 123 }, | ||
| 56 | [CIP_SFC_48000] = { 512, 0 }, | ||
| 57 | [CIP_SFC_88200] = { 278, 282 }, | ||
| 58 | [CIP_SFC_96000] = { 256, 0 }, | ||
| 59 | [CIP_SFC_176400] = { 139, 141 }, | ||
| 60 | [CIP_SFC_192000] = { 128, 0 }, | ||
| 61 | }; | ||
| 62 | struct amdtp_motu *p = s->protocol; | ||
| 63 | unsigned int pcm_chunks, data_chunks, data_block_quadlets; | ||
| 64 | unsigned int delay; | ||
| 65 | unsigned int mode; | ||
| 66 | int i, err; | ||
| 67 | |||
| 68 | if (amdtp_stream_running(s)) | ||
| 69 | return -EBUSY; | ||
| 70 | |||
| 71 | for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) { | ||
| 72 | if (snd_motu_clock_rates[i] == rate) { | ||
| 73 | mode = i >> 1; | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | if (i == ARRAY_SIZE(snd_motu_clock_rates)) | ||
| 78 | return -EINVAL; | ||
| 79 | |||
| 80 | pcm_chunks = formats->fixed_part_pcm_chunks[mode] + | ||
| 81 | formats->differed_part_pcm_chunks[mode]; | ||
| 82 | data_chunks = formats->msg_chunks + pcm_chunks; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * Each data block includes SPH in its head. Data chunks follow with | ||
| 86 | * 3 byte alignment. Padding follows with zero to conform to quadlet | ||
| 87 | * alignment. | ||
| 88 | */ | ||
| 89 | data_block_quadlets = 1 + DIV_ROUND_UP(data_chunks * 3, 4); | ||
| 90 | |||
| 91 | err = amdtp_stream_set_parameters(s, rate, data_block_quadlets); | ||
| 92 | if (err < 0) | ||
| 93 | return err; | ||
| 94 | |||
| 95 | p->pcm_chunks = pcm_chunks; | ||
| 96 | p->pcm_byte_offset = formats->pcm_byte_offset; | ||
| 97 | |||
| 98 | p->midi_ports = midi_ports; | ||
| 99 | p->midi_flag_offset = formats->midi_flag_offset; | ||
| 100 | p->midi_byte_offset = formats->midi_byte_offset; | ||
| 101 | |||
| 102 | p->midi_db_count = 0; | ||
| 103 | p->midi_db_interval = rate / MIDI_BYTES_PER_SECOND; | ||
| 104 | |||
| 105 | /* IEEE 1394 bus requires. */ | ||
| 106 | delay = 0x2e00; | ||
| 107 | |||
| 108 | /* For no-data or empty packets to adjust PCM sampling frequency. */ | ||
| 109 | delay += 8000 * 3072 * s->syt_interval / rate; | ||
| 110 | |||
| 111 | p->next_seconds = 0; | ||
| 112 | p->next_cycles = delay / 3072; | ||
| 113 | p->quotient_ticks_per_event = params[s->sfc].quotient_ticks_per_event; | ||
| 114 | p->remainder_ticks_per_event = params[s->sfc].remainder_ticks_per_event; | ||
| 115 | p->next_ticks = delay % 3072; | ||
| 116 | p->next_accumulated = 0; | ||
| 117 | |||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | static void read_pcm_s32(struct amdtp_stream *s, | ||
| 122 | struct snd_pcm_runtime *runtime, | ||
| 123 | __be32 *buffer, unsigned int data_blocks) | ||
| 124 | { | ||
| 125 | struct amdtp_motu *p = s->protocol; | ||
| 126 | unsigned int channels, remaining_frames, i, c; | ||
| 127 | u8 *byte; | ||
| 128 | u32 *dst; | ||
| 129 | |||
| 130 | channels = p->pcm_chunks; | ||
| 131 | dst = (void *)runtime->dma_area + | ||
| 132 | frames_to_bytes(runtime, s->pcm_buffer_pointer); | ||
| 133 | remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; | ||
| 134 | |||
| 135 | for (i = 0; i < data_blocks; ++i) { | ||
| 136 | byte = (u8 *)buffer + p->pcm_byte_offset; | ||
| 137 | |||
| 138 | for (c = 0; c < channels; ++c) { | ||
| 139 | *dst = (byte[0] << 24) | (byte[1] << 16) | byte[2]; | ||
| 140 | byte += 3; | ||
| 141 | dst++; | ||
| 142 | } | ||
| 143 | buffer += s->data_block_quadlets; | ||
| 144 | if (--remaining_frames == 0) | ||
| 145 | dst = (void *)runtime->dma_area; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | static void write_pcm_s32(struct amdtp_stream *s, | ||
| 150 | struct snd_pcm_runtime *runtime, | ||
| 151 | __be32 *buffer, unsigned int data_blocks) | ||
| 152 | { | ||
| 153 | struct amdtp_motu *p = s->protocol; | ||
| 154 | unsigned int channels, remaining_frames, i, c; | ||
| 155 | u8 *byte; | ||
| 156 | const u32 *src; | ||
| 157 | |||
| 158 | channels = p->pcm_chunks; | ||
| 159 | src = (void *)runtime->dma_area + | ||
| 160 | frames_to_bytes(runtime, s->pcm_buffer_pointer); | ||
| 161 | remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; | ||
| 162 | |||
| 163 | for (i = 0; i < data_blocks; ++i) { | ||
| 164 | byte = (u8 *)buffer + p->pcm_byte_offset; | ||
| 165 | |||
| 166 | for (c = 0; c < channels; ++c) { | ||
| 167 | byte[0] = (*src >> 24) & 0xff; | ||
| 168 | byte[1] = (*src >> 16) & 0xff; | ||
| 169 | byte[2] = (*src >> 8) & 0xff; | ||
| 170 | byte += 3; | ||
| 171 | src++; | ||
| 172 | } | ||
| 173 | |||
| 174 | buffer += s->data_block_quadlets; | ||
| 175 | if (--remaining_frames == 0) | ||
| 176 | src = (void *)runtime->dma_area; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | static void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer, | ||
| 181 | unsigned int data_blocks) | ||
| 182 | { | ||
| 183 | struct amdtp_motu *p = s->protocol; | ||
| 184 | unsigned int channels, i, c; | ||
| 185 | u8 *byte; | ||
| 186 | |||
| 187 | channels = p->pcm_chunks; | ||
| 188 | |||
| 189 | for (i = 0; i < data_blocks; ++i) { | ||
| 190 | byte = (u8 *)buffer + p->pcm_byte_offset; | ||
| 191 | |||
| 192 | for (c = 0; c < channels; ++c) { | ||
| 193 | byte[0] = 0; | ||
| 194 | byte[1] = 0; | ||
| 195 | byte[2] = 0; | ||
| 196 | byte += 3; | ||
| 197 | } | ||
| 198 | |||
| 199 | buffer += s->data_block_quadlets; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | int amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s, | ||
| 204 | struct snd_pcm_runtime *runtime) | ||
| 205 | { | ||
| 206 | int err; | ||
| 207 | |||
| 208 | /* TODO: how to set an constraint for exactly 24bit PCM sample? */ | ||
| 209 | err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | ||
| 210 | if (err < 0) | ||
| 211 | return err; | ||
| 212 | |||
| 213 | return amdtp_stream_add_pcm_hw_constraints(s, runtime); | ||
| 214 | } | ||
| 215 | |||
| 216 | void amdtp_motu_midi_trigger(struct amdtp_stream *s, unsigned int port, | ||
| 217 | struct snd_rawmidi_substream *midi) | ||
| 218 | { | ||
| 219 | struct amdtp_motu *p = s->protocol; | ||
| 220 | |||
| 221 | if (port < p->midi_ports) | ||
| 222 | WRITE_ONCE(p->midi, midi); | ||
| 223 | } | ||
| 224 | |||
| 225 | static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, | ||
| 226 | unsigned int data_blocks) | ||
| 227 | { | ||
| 228 | struct amdtp_motu *p = s->protocol; | ||
| 229 | struct snd_rawmidi_substream *midi = READ_ONCE(p->midi); | ||
| 230 | u8 *b; | ||
| 231 | int i; | ||
| 232 | |||
| 233 | for (i = 0; i < data_blocks; i++) { | ||
| 234 | b = (u8 *)buffer; | ||
| 235 | |||
| 236 | if (midi && p->midi_db_count == 0 && | ||
| 237 | snd_rawmidi_transmit(midi, b + p->midi_byte_offset, 1) == 1) { | ||
| 238 | b[p->midi_flag_offset] = 0x01; | ||
| 239 | } else { | ||
| 240 | b[p->midi_byte_offset] = 0x00; | ||
| 241 | b[p->midi_flag_offset] = 0x00; | ||
| 242 | } | ||
| 243 | |||
| 244 | buffer += s->data_block_quadlets; | ||
| 245 | |||
| 246 | if (--p->midi_db_count < 0) | ||
| 247 | p->midi_db_count = p->midi_db_interval; | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, | ||
| 252 | unsigned int data_blocks) | ||
| 253 | { | ||
| 254 | struct amdtp_motu *p = s->protocol; | ||
| 255 | struct snd_rawmidi_substream *midi; | ||
| 256 | u8 *b; | ||
| 257 | int i; | ||
| 258 | |||
| 259 | for (i = 0; i < data_blocks; i++) { | ||
| 260 | b = (u8 *)buffer; | ||
| 261 | midi = READ_ONCE(p->midi); | ||
| 262 | |||
| 263 | if (midi && (b[p->midi_flag_offset] & 0x01)) | ||
| 264 | snd_rawmidi_receive(midi, b + p->midi_byte_offset, 1); | ||
| 265 | |||
| 266 | buffer += s->data_block_quadlets; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | /* For tracepoints. */ | ||
| 271 | static void __maybe_unused copy_sph(u32 *frames, __be32 *buffer, | ||
| 272 | unsigned int data_blocks, | ||
| 273 | unsigned int data_block_quadlets) | ||
| 274 | { | ||
| 275 | unsigned int i; | ||
| 276 | |||
| 277 | for (i = 0; i < data_blocks; ++i) { | ||
| 278 | *frames = be32_to_cpu(*buffer); | ||
| 279 | buffer += data_block_quadlets; | ||
| 280 | frames++; | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | /* For tracepoints. */ | ||
| 285 | static void __maybe_unused copy_message(u64 *frames, __be32 *buffer, | ||
| 286 | unsigned int data_blocks, | ||
| 287 | unsigned int data_block_quadlets) | ||
| 288 | { | ||
| 289 | unsigned int i; | ||
| 290 | |||
| 291 | /* This is just for v2/v3 protocol. */ | ||
| 292 | for (i = 0; i < data_blocks; ++i) { | ||
| 293 | *frames = (be32_to_cpu(buffer[1]) << 16) | | ||
| 294 | (be32_to_cpu(buffer[2]) >> 16); | ||
| 295 | buffer += data_block_quadlets; | ||
| 296 | frames++; | ||
| 297 | } | ||
| 298 | } | ||
| 299 | |||
| 300 | static unsigned int process_tx_data_blocks(struct amdtp_stream *s, | ||
| 301 | __be32 *buffer, unsigned int data_blocks, | ||
| 302 | unsigned int *syt) | ||
| 303 | { | ||
| 304 | struct amdtp_motu *p = s->protocol; | ||
| 305 | struct snd_pcm_substream *pcm; | ||
| 306 | |||
| 307 | trace_in_data_block_sph(s, data_blocks, buffer); | ||
| 308 | trace_in_data_block_message(s, data_blocks, buffer); | ||
| 309 | |||
| 310 | if (p->midi_ports) | ||
| 311 | read_midi_messages(s, buffer, data_blocks); | ||
| 312 | |||
| 313 | pcm = ACCESS_ONCE(s->pcm); | ||
| 314 | if (data_blocks > 0 && pcm) | ||
| 315 | read_pcm_s32(s, pcm->runtime, buffer, data_blocks); | ||
| 316 | |||
| 317 | return data_blocks; | ||
| 318 | } | ||
| 319 | |||
| 320 | static inline void compute_next_elapse_from_start(struct amdtp_motu *p) | ||
| 321 | { | ||
| 322 | p->next_accumulated += p->remainder_ticks_per_event; | ||
| 323 | if (p->next_accumulated >= 441) { | ||
| 324 | p->next_accumulated -= 441; | ||
| 325 | p->next_ticks++; | ||
| 326 | } | ||
| 327 | |||
| 328 | p->next_ticks += p->quotient_ticks_per_event; | ||
| 329 | if (p->next_ticks >= 3072) { | ||
| 330 | p->next_ticks -= 3072; | ||
| 331 | p->next_cycles++; | ||
| 332 | } | ||
| 333 | |||
| 334 | if (p->next_cycles >= 8000) { | ||
| 335 | p->next_cycles -= 8000; | ||
| 336 | p->next_seconds++; | ||
| 337 | } | ||
| 338 | |||
| 339 | if (p->next_seconds >= 128) | ||
| 340 | p->next_seconds -= 128; | ||
| 341 | } | ||
| 342 | |||
| 343 | static void write_sph(struct amdtp_stream *s, __be32 *buffer, | ||
| 344 | unsigned int data_blocks) | ||
| 345 | { | ||
| 346 | struct amdtp_motu *p = s->protocol; | ||
| 347 | unsigned int next_cycles; | ||
| 348 | unsigned int i; | ||
| 349 | u32 sph; | ||
| 350 | |||
| 351 | for (i = 0; i < data_blocks; i++) { | ||
| 352 | next_cycles = (s->start_cycle + p->next_cycles) % 8000; | ||
| 353 | sph = ((next_cycles << 12) | p->next_ticks) & 0x01ffffff; | ||
| 354 | *buffer = cpu_to_be32(sph); | ||
| 355 | |||
| 356 | compute_next_elapse_from_start(p); | ||
| 357 | |||
| 358 | buffer += s->data_block_quadlets; | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | static unsigned int process_rx_data_blocks(struct amdtp_stream *s, | ||
| 363 | __be32 *buffer, unsigned int data_blocks, | ||
| 364 | unsigned int *syt) | ||
| 365 | { | ||
| 366 | struct amdtp_motu *p = (struct amdtp_motu *)s->protocol; | ||
| 367 | struct snd_pcm_substream *pcm; | ||
| 368 | |||
| 369 | /* Not used. */ | ||
| 370 | *syt = 0xffff; | ||
| 371 | |||
| 372 | /* TODO: how to interact control messages between userspace? */ | ||
| 373 | |||
| 374 | if (p->midi_ports) | ||
| 375 | write_midi_messages(s, buffer, data_blocks); | ||
| 376 | |||
| 377 | pcm = ACCESS_ONCE(s->pcm); | ||
| 378 | if (pcm) | ||
| 379 | write_pcm_s32(s, pcm->runtime, buffer, data_blocks); | ||
| 380 | else | ||
| 381 | write_pcm_silence(s, buffer, data_blocks); | ||
| 382 | |||
| 383 | write_sph(s, buffer, data_blocks); | ||
| 384 | |||
| 385 | trace_out_data_block_sph(s, data_blocks, buffer); | ||
| 386 | trace_out_data_block_message(s, data_blocks, buffer); | ||
| 387 | |||
| 388 | return data_blocks; | ||
| 389 | } | ||
| 390 | |||
| 391 | int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, | ||
| 392 | enum amdtp_stream_direction dir, | ||
| 393 | const struct snd_motu_protocol *const protocol) | ||
| 394 | { | ||
| 395 | amdtp_stream_process_data_blocks_t process_data_blocks; | ||
| 396 | int fmt = CIP_FMT_MOTU; | ||
| 397 | int flags = CIP_BLOCKING; | ||
| 398 | int err; | ||
| 399 | |||
| 400 | if (dir == AMDTP_IN_STREAM) { | ||
| 401 | process_data_blocks = process_tx_data_blocks; | ||
| 402 | |||
| 403 | /* | ||
| 404 | * Units of version 3 transmits packets with invalid CIP header | ||
| 405 | * against IEC 61883-1. | ||
| 406 | */ | ||
| 407 | if (protocol == &snd_motu_protocol_v3) { | ||
| 408 | flags |= CIP_WRONG_DBS | | ||
| 409 | CIP_SKIP_DBC_ZERO_CHECK | | ||
| 410 | CIP_HEADER_WITHOUT_EOH; | ||
| 411 | fmt = CIP_FMT_MOTU_TX_V3; | ||
| 412 | } | ||
| 413 | } else { | ||
| 414 | process_data_blocks = process_rx_data_blocks; | ||
| 415 | flags |= CIP_DBC_IS_END_EVENT; | ||
| 416 | } | ||
| 417 | |||
| 418 | err = amdtp_stream_init(s, unit, dir, flags, fmt, process_data_blocks, | ||
| 419 | sizeof(struct amdtp_motu)); | ||
| 420 | if (err < 0) | ||
| 421 | return err; | ||
| 422 | |||
| 423 | s->sph = 1; | ||
| 424 | s->fdf = MOTU_FDF_AM824; | ||
| 425 | |||
| 426 | return 0; | ||
| 427 | } | ||
diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c new file mode 100644 index 000000000000..b87ccb69d597 --- /dev/null +++ b/sound/firewire/motu/motu-hwdep.c | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | /* | ||
| 2 | * motu-hwdep.c - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | * This codes have five functionalities. | ||
| 11 | * | ||
| 12 | * 1.get information about firewire node | ||
| 13 | * 2.get notification about starting/stopping stream | ||
| 14 | * 3.lock/unlock streaming | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "motu.h" | ||
| 19 | |||
| 20 | static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, | ||
| 21 | loff_t *offset) | ||
| 22 | { | ||
| 23 | struct snd_motu *motu = hwdep->private_data; | ||
| 24 | DEFINE_WAIT(wait); | ||
| 25 | union snd_firewire_event event; | ||
| 26 | |||
| 27 | spin_lock_irq(&motu->lock); | ||
| 28 | |||
| 29 | while (!motu->dev_lock_changed && motu->msg == 0) { | ||
| 30 | prepare_to_wait(&motu->hwdep_wait, &wait, TASK_INTERRUPTIBLE); | ||
| 31 | spin_unlock_irq(&motu->lock); | ||
| 32 | schedule(); | ||
| 33 | finish_wait(&motu->hwdep_wait, &wait); | ||
| 34 | if (signal_pending(current)) | ||
| 35 | return -ERESTARTSYS; | ||
| 36 | spin_lock_irq(&motu->lock); | ||
| 37 | } | ||
| 38 | |||
| 39 | memset(&event, 0, sizeof(event)); | ||
| 40 | if (motu->dev_lock_changed) { | ||
| 41 | event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; | ||
| 42 | event.lock_status.status = (motu->dev_lock_count > 0); | ||
| 43 | motu->dev_lock_changed = false; | ||
| 44 | |||
| 45 | count = min_t(long, count, sizeof(event.lock_status)); | ||
| 46 | } else { | ||
| 47 | event.motu_notification.type = SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION; | ||
| 48 | event.motu_notification.message = motu->msg; | ||
| 49 | motu->msg = 0; | ||
| 50 | |||
| 51 | count = min_t(long, count, sizeof(event.motu_notification)); | ||
| 52 | } | ||
| 53 | |||
| 54 | spin_unlock_irq(&motu->lock); | ||
| 55 | |||
| 56 | if (copy_to_user(buf, &event, count)) | ||
| 57 | return -EFAULT; | ||
| 58 | |||
| 59 | return count; | ||
| 60 | } | ||
| 61 | |||
| 62 | static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file, | ||
| 63 | poll_table *wait) | ||
| 64 | { | ||
| 65 | struct snd_motu *motu = hwdep->private_data; | ||
| 66 | unsigned int events; | ||
| 67 | |||
| 68 | poll_wait(file, &motu->hwdep_wait, wait); | ||
| 69 | |||
| 70 | spin_lock_irq(&motu->lock); | ||
| 71 | if (motu->dev_lock_changed || motu->msg) | ||
| 72 | events = POLLIN | POLLRDNORM; | ||
| 73 | else | ||
| 74 | events = 0; | ||
| 75 | spin_unlock_irq(&motu->lock); | ||
| 76 | |||
| 77 | return events | POLLOUT; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int hwdep_get_info(struct snd_motu *motu, void __user *arg) | ||
| 81 | { | ||
| 82 | struct fw_device *dev = fw_parent_device(motu->unit); | ||
| 83 | struct snd_firewire_get_info info; | ||
| 84 | |||
| 85 | memset(&info, 0, sizeof(info)); | ||
| 86 | info.type = SNDRV_FIREWIRE_TYPE_MOTU; | ||
| 87 | info.card = dev->card->index; | ||
| 88 | *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); | ||
| 89 | *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); | ||
| 90 | strlcpy(info.device_name, dev_name(&dev->device), | ||
| 91 | sizeof(info.device_name)); | ||
| 92 | |||
| 93 | if (copy_to_user(arg, &info, sizeof(info))) | ||
| 94 | return -EFAULT; | ||
| 95 | |||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int hwdep_lock(struct snd_motu *motu) | ||
| 100 | { | ||
| 101 | int err; | ||
| 102 | |||
| 103 | spin_lock_irq(&motu->lock); | ||
| 104 | |||
| 105 | if (motu->dev_lock_count == 0) { | ||
| 106 | motu->dev_lock_count = -1; | ||
| 107 | err = 0; | ||
| 108 | } else { | ||
| 109 | err = -EBUSY; | ||
| 110 | } | ||
| 111 | |||
| 112 | spin_unlock_irq(&motu->lock); | ||
| 113 | |||
| 114 | return err; | ||
| 115 | } | ||
| 116 | |||
| 117 | static int hwdep_unlock(struct snd_motu *motu) | ||
| 118 | { | ||
| 119 | int err; | ||
| 120 | |||
| 121 | spin_lock_irq(&motu->lock); | ||
| 122 | |||
| 123 | if (motu->dev_lock_count == -1) { | ||
| 124 | motu->dev_lock_count = 0; | ||
| 125 | err = 0; | ||
| 126 | } else { | ||
| 127 | err = -EBADFD; | ||
| 128 | } | ||
| 129 | |||
| 130 | spin_unlock_irq(&motu->lock); | ||
| 131 | |||
| 132 | return err; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) | ||
| 136 | { | ||
| 137 | struct snd_motu *motu = hwdep->private_data; | ||
| 138 | |||
| 139 | spin_lock_irq(&motu->lock); | ||
| 140 | if (motu->dev_lock_count == -1) | ||
| 141 | motu->dev_lock_count = 0; | ||
| 142 | spin_unlock_irq(&motu->lock); | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, | ||
| 148 | unsigned int cmd, unsigned long arg) | ||
| 149 | { | ||
| 150 | struct snd_motu *motu = hwdep->private_data; | ||
| 151 | |||
| 152 | switch (cmd) { | ||
| 153 | case SNDRV_FIREWIRE_IOCTL_GET_INFO: | ||
| 154 | return hwdep_get_info(motu, (void __user *)arg); | ||
| 155 | case SNDRV_FIREWIRE_IOCTL_LOCK: | ||
| 156 | return hwdep_lock(motu); | ||
| 157 | case SNDRV_FIREWIRE_IOCTL_UNLOCK: | ||
| 158 | return hwdep_unlock(motu); | ||
| 159 | default: | ||
| 160 | return -ENOIOCTLCMD; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | #ifdef CONFIG_COMPAT | ||
| 165 | static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, | ||
| 166 | unsigned int cmd, unsigned long arg) | ||
| 167 | { | ||
| 168 | return hwdep_ioctl(hwdep, file, cmd, | ||
| 169 | (unsigned long)compat_ptr(arg)); | ||
| 170 | } | ||
| 171 | #else | ||
| 172 | #define hwdep_compat_ioctl NULL | ||
| 173 | #endif | ||
| 174 | |||
| 175 | int snd_motu_create_hwdep_device(struct snd_motu *motu) | ||
| 176 | { | ||
| 177 | static const struct snd_hwdep_ops ops = { | ||
| 178 | .read = hwdep_read, | ||
| 179 | .release = hwdep_release, | ||
| 180 | .poll = hwdep_poll, | ||
| 181 | .ioctl = hwdep_ioctl, | ||
| 182 | .ioctl_compat = hwdep_compat_ioctl, | ||
| 183 | }; | ||
| 184 | struct snd_hwdep *hwdep; | ||
| 185 | int err; | ||
| 186 | |||
| 187 | err = snd_hwdep_new(motu->card, motu->card->driver, 0, &hwdep); | ||
| 188 | if (err < 0) | ||
| 189 | return err; | ||
| 190 | |||
| 191 | strcpy(hwdep->name, "MOTU"); | ||
| 192 | hwdep->iface = SNDRV_HWDEP_IFACE_FW_MOTU; | ||
| 193 | hwdep->ops = ops; | ||
| 194 | hwdep->private_data = motu; | ||
| 195 | hwdep->exclusive = true; | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
diff --git a/sound/firewire/motu/motu-midi.c b/sound/firewire/motu/motu-midi.c new file mode 100644 index 000000000000..e3acfcc53f4e --- /dev/null +++ b/sound/firewire/motu/motu-midi.c | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * motu-midi.h - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | #include "motu.h" | ||
| 9 | |||
| 10 | static int midi_capture_open(struct snd_rawmidi_substream *substream) | ||
| 11 | { | ||
| 12 | struct snd_motu *motu = substream->rmidi->private_data; | ||
| 13 | int err; | ||
| 14 | |||
| 15 | err = snd_motu_stream_lock_try(motu); | ||
| 16 | if (err < 0) | ||
| 17 | return err; | ||
| 18 | |||
| 19 | mutex_lock(&motu->mutex); | ||
| 20 | |||
| 21 | motu->capture_substreams++; | ||
| 22 | err = snd_motu_stream_start_duplex(motu, 0); | ||
| 23 | |||
| 24 | mutex_unlock(&motu->mutex); | ||
| 25 | |||
| 26 | if (err < 0) | ||
| 27 | snd_motu_stream_lock_release(motu); | ||
| 28 | |||
| 29 | return err; | ||
| 30 | } | ||
| 31 | |||
| 32 | static int midi_playback_open(struct snd_rawmidi_substream *substream) | ||
| 33 | { | ||
| 34 | struct snd_motu *motu = substream->rmidi->private_data; | ||
| 35 | int err; | ||
| 36 | |||
| 37 | err = snd_motu_stream_lock_try(motu); | ||
| 38 | if (err < 0) | ||
| 39 | return err; | ||
| 40 | |||
| 41 | mutex_lock(&motu->mutex); | ||
| 42 | |||
| 43 | motu->playback_substreams++; | ||
| 44 | err = snd_motu_stream_start_duplex(motu, 0); | ||
| 45 | |||
| 46 | mutex_unlock(&motu->mutex); | ||
| 47 | |||
| 48 | if (err < 0) | ||
| 49 | snd_motu_stream_lock_release(motu); | ||
| 50 | |||
| 51 | return err; | ||
| 52 | } | ||
| 53 | |||
| 54 | static int midi_capture_close(struct snd_rawmidi_substream *substream) | ||
| 55 | { | ||
| 56 | struct snd_motu *motu = substream->rmidi->private_data; | ||
| 57 | |||
| 58 | mutex_lock(&motu->mutex); | ||
| 59 | |||
| 60 | motu->capture_substreams--; | ||
| 61 | snd_motu_stream_stop_duplex(motu); | ||
| 62 | |||
| 63 | mutex_unlock(&motu->mutex); | ||
| 64 | |||
| 65 | snd_motu_stream_lock_release(motu); | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int midi_playback_close(struct snd_rawmidi_substream *substream) | ||
| 70 | { | ||
| 71 | struct snd_motu *motu = substream->rmidi->private_data; | ||
| 72 | |||
| 73 | mutex_lock(&motu->mutex); | ||
| 74 | |||
| 75 | motu->playback_substreams--; | ||
| 76 | snd_motu_stream_stop_duplex(motu); | ||
| 77 | |||
| 78 | mutex_unlock(&motu->mutex); | ||
| 79 | |||
| 80 | snd_motu_stream_lock_release(motu); | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) | ||
| 85 | { | ||
| 86 | struct snd_motu *motu = substrm->rmidi->private_data; | ||
| 87 | unsigned long flags; | ||
| 88 | |||
| 89 | spin_lock_irqsave(&motu->lock, flags); | ||
| 90 | |||
| 91 | if (up) | ||
| 92 | amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, | ||
| 93 | substrm); | ||
| 94 | else | ||
| 95 | amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, | ||
| 96 | NULL); | ||
| 97 | |||
| 98 | spin_unlock_irqrestore(&motu->lock, flags); | ||
| 99 | } | ||
| 100 | |||
| 101 | static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) | ||
| 102 | { | ||
| 103 | struct snd_motu *motu = substrm->rmidi->private_data; | ||
| 104 | unsigned long flags; | ||
| 105 | |||
| 106 | spin_lock_irqsave(&motu->lock, flags); | ||
| 107 | |||
| 108 | if (up) | ||
| 109 | amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, | ||
| 110 | substrm); | ||
| 111 | else | ||
| 112 | amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, | ||
| 113 | NULL); | ||
| 114 | |||
| 115 | spin_unlock_irqrestore(&motu->lock, flags); | ||
| 116 | } | ||
| 117 | |||
| 118 | static void set_midi_substream_names(struct snd_motu *motu, | ||
| 119 | struct snd_rawmidi_str *str) | ||
| 120 | { | ||
| 121 | struct snd_rawmidi_substream *subs; | ||
| 122 | |||
| 123 | list_for_each_entry(subs, &str->substreams, list) { | ||
| 124 | snprintf(subs->name, sizeof(subs->name), | ||
| 125 | "%s MIDI %d", motu->card->shortname, subs->number + 1); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | int snd_motu_create_midi_devices(struct snd_motu *motu) | ||
| 130 | { | ||
| 131 | static struct snd_rawmidi_ops capture_ops = { | ||
| 132 | .open = midi_capture_open, | ||
| 133 | .close = midi_capture_close, | ||
| 134 | .trigger = midi_capture_trigger, | ||
| 135 | }; | ||
| 136 | static struct snd_rawmidi_ops playback_ops = { | ||
| 137 | .open = midi_playback_open, | ||
| 138 | .close = midi_playback_close, | ||
| 139 | .trigger = midi_playback_trigger, | ||
| 140 | }; | ||
| 141 | struct snd_rawmidi *rmidi; | ||
| 142 | struct snd_rawmidi_str *str; | ||
| 143 | int err; | ||
| 144 | |||
| 145 | /* create midi ports */ | ||
| 146 | err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi); | ||
| 147 | if (err < 0) | ||
| 148 | return err; | ||
| 149 | |||
| 150 | snprintf(rmidi->name, sizeof(rmidi->name), | ||
| 151 | "%s MIDI", motu->card->shortname); | ||
| 152 | rmidi->private_data = motu; | ||
| 153 | |||
| 154 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT | | ||
| 155 | SNDRV_RAWMIDI_INFO_OUTPUT | | ||
| 156 | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
| 157 | |||
| 158 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
| 159 | &capture_ops); | ||
| 160 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; | ||
| 161 | set_midi_substream_names(motu, str); | ||
| 162 | |||
| 163 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
| 164 | &playback_ops); | ||
| 165 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; | ||
| 166 | set_midi_substream_names(motu, str); | ||
| 167 | |||
| 168 | return 0; | ||
| 169 | } | ||
diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c new file mode 100644 index 000000000000..94558f3d218b --- /dev/null +++ b/sound/firewire/motu/motu-pcm.c | |||
| @@ -0,0 +1,398 @@ | |||
| 1 | /* | ||
| 2 | * motu-pcm.c - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <sound/pcm_params.h> | ||
| 10 | #include "motu.h" | ||
| 11 | |||
| 12 | static int motu_rate_constraint(struct snd_pcm_hw_params *params, | ||
| 13 | struct snd_pcm_hw_rule *rule) | ||
| 14 | { | ||
| 15 | struct snd_motu_packet_format *formats = rule->private; | ||
| 16 | |||
| 17 | const struct snd_interval *c = | ||
| 18 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
| 19 | struct snd_interval *r = | ||
| 20 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
| 21 | struct snd_interval rates = { | ||
| 22 | .min = UINT_MAX, .max = 0, .integer = 1 | ||
| 23 | }; | ||
| 24 | unsigned int i, pcm_channels, rate, mode; | ||
| 25 | |||
| 26 | for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) { | ||
| 27 | rate = snd_motu_clock_rates[i]; | ||
| 28 | mode = i / 2; | ||
| 29 | |||
| 30 | pcm_channels = formats->fixed_part_pcm_chunks[mode] + | ||
| 31 | formats->differed_part_pcm_chunks[mode]; | ||
| 32 | if (!snd_interval_test(c, pcm_channels)) | ||
| 33 | continue; | ||
| 34 | |||
| 35 | rates.min = min(rates.min, rate); | ||
| 36 | rates.max = max(rates.max, rate); | ||
| 37 | } | ||
| 38 | |||
| 39 | return snd_interval_refine(r, &rates); | ||
| 40 | } | ||
| 41 | |||
| 42 | static int motu_channels_constraint(struct snd_pcm_hw_params *params, | ||
| 43 | struct snd_pcm_hw_rule *rule) | ||
| 44 | { | ||
| 45 | struct snd_motu_packet_format *formats = rule->private; | ||
| 46 | |||
| 47 | const struct snd_interval *r = | ||
| 48 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); | ||
| 49 | struct snd_interval *c = | ||
| 50 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
| 51 | struct snd_interval channels = { | ||
| 52 | .min = UINT_MAX, .max = 0, .integer = 1 | ||
| 53 | }; | ||
| 54 | unsigned int i, pcm_channels, rate, mode; | ||
| 55 | |||
| 56 | for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) { | ||
| 57 | rate = snd_motu_clock_rates[i]; | ||
| 58 | mode = i / 2; | ||
| 59 | |||
| 60 | if (!snd_interval_test(r, rate)) | ||
| 61 | continue; | ||
| 62 | |||
| 63 | pcm_channels = formats->fixed_part_pcm_chunks[mode] + | ||
| 64 | formats->differed_part_pcm_chunks[mode]; | ||
| 65 | channels.min = min(channels.min, pcm_channels); | ||
| 66 | channels.max = max(channels.max, pcm_channels); | ||
| 67 | } | ||
| 68 | |||
| 69 | return snd_interval_refine(c, &channels); | ||
| 70 | } | ||
| 71 | |||
| 72 | static void limit_channels_and_rates(struct snd_motu *motu, | ||
| 73 | struct snd_pcm_runtime *runtime, | ||
| 74 | struct snd_motu_packet_format *formats) | ||
| 75 | { | ||
| 76 | struct snd_pcm_hardware *hw = &runtime->hw; | ||
| 77 | unsigned int i, pcm_channels, rate, mode; | ||
| 78 | |||
| 79 | hw->channels_min = UINT_MAX; | ||
| 80 | hw->channels_max = 0; | ||
| 81 | |||
| 82 | for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) { | ||
| 83 | rate = snd_motu_clock_rates[i]; | ||
| 84 | mode = i / 2; | ||
| 85 | |||
| 86 | pcm_channels = formats->fixed_part_pcm_chunks[mode] + | ||
| 87 | formats->differed_part_pcm_chunks[mode]; | ||
| 88 | if (pcm_channels == 0) | ||
| 89 | continue; | ||
| 90 | |||
| 91 | hw->rates |= snd_pcm_rate_to_rate_bit(rate); | ||
| 92 | hw->channels_min = min(hw->channels_min, pcm_channels); | ||
| 93 | hw->channels_max = max(hw->channels_max, pcm_channels); | ||
| 94 | } | ||
| 95 | |||
| 96 | snd_pcm_limit_hw_rates(runtime); | ||
| 97 | } | ||
| 98 | |||
| 99 | static void limit_period_and_buffer(struct snd_pcm_hardware *hw) | ||
| 100 | { | ||
| 101 | hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ | ||
| 102 | hw->periods_max = UINT_MAX; | ||
| 103 | |||
| 104 | hw->period_bytes_min = 4 * hw->channels_max; /* byte for a frame */ | ||
| 105 | |||
| 106 | /* Just to prevent from allocating much pages. */ | ||
| 107 | hw->period_bytes_max = hw->period_bytes_min * 2048; | ||
| 108 | hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; | ||
| 109 | } | ||
| 110 | |||
| 111 | static int init_hw_info(struct snd_motu *motu, | ||
| 112 | struct snd_pcm_substream *substream) | ||
| 113 | { | ||
| 114 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 115 | struct snd_pcm_hardware *hw = &runtime->hw; | ||
| 116 | struct amdtp_stream *stream; | ||
| 117 | struct snd_motu_packet_format *formats; | ||
| 118 | int err; | ||
| 119 | |||
| 120 | hw->info = SNDRV_PCM_INFO_MMAP | | ||
| 121 | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 122 | SNDRV_PCM_INFO_BATCH | | ||
| 123 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 124 | SNDRV_PCM_INFO_JOINT_DUPLEX | | ||
| 125 | SNDRV_PCM_INFO_BLOCK_TRANSFER; | ||
| 126 | |||
| 127 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
| 128 | hw->formats = SNDRV_PCM_FMTBIT_S32; | ||
| 129 | stream = &motu->tx_stream; | ||
| 130 | formats = &motu->tx_packet_formats; | ||
| 131 | } else { | ||
| 132 | hw->formats = SNDRV_PCM_FMTBIT_S32; | ||
| 133 | stream = &motu->rx_stream; | ||
| 134 | formats = &motu->rx_packet_formats; | ||
| 135 | } | ||
| 136 | |||
| 137 | limit_channels_and_rates(motu, runtime, formats); | ||
| 138 | limit_period_and_buffer(hw); | ||
| 139 | |||
| 140 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
| 141 | motu_rate_constraint, formats, | ||
| 142 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
| 143 | if (err < 0) | ||
| 144 | return err; | ||
| 145 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
| 146 | motu_channels_constraint, formats, | ||
| 147 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
| 148 | if (err < 0) | ||
| 149 | return err; | ||
| 150 | |||
| 151 | return amdtp_motu_add_pcm_hw_constraints(stream, runtime); | ||
| 152 | } | ||
| 153 | |||
| 154 | static int pcm_open(struct snd_pcm_substream *substream) | ||
| 155 | { | ||
| 156 | struct snd_motu *motu = substream->private_data; | ||
| 157 | const struct snd_motu_protocol *const protocol = motu->spec->protocol; | ||
| 158 | enum snd_motu_clock_source src; | ||
| 159 | unsigned int rate; | ||
| 160 | int err; | ||
| 161 | |||
| 162 | err = snd_motu_stream_lock_try(motu); | ||
| 163 | if (err < 0) | ||
| 164 | return err; | ||
| 165 | |||
| 166 | mutex_lock(&motu->mutex); | ||
| 167 | |||
| 168 | err = protocol->cache_packet_formats(motu); | ||
| 169 | if (err < 0) | ||
| 170 | goto err_locked; | ||
| 171 | |||
| 172 | err = init_hw_info(motu, substream); | ||
| 173 | if (err < 0) | ||
| 174 | goto err_locked; | ||
| 175 | |||
| 176 | /* | ||
| 177 | * When source of clock is not internal or any PCM streams are running, | ||
| 178 | * available sampling rate is limited at current sampling rate. | ||
| 179 | */ | ||
| 180 | err = protocol->get_clock_source(motu, &src); | ||
| 181 | if (err < 0) | ||
| 182 | goto err_locked; | ||
| 183 | if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL || | ||
| 184 | amdtp_stream_pcm_running(&motu->tx_stream) || | ||
| 185 | amdtp_stream_pcm_running(&motu->rx_stream)) { | ||
| 186 | err = protocol->get_clock_rate(motu, &rate); | ||
| 187 | if (err < 0) | ||
| 188 | goto err_locked; | ||
| 189 | substream->runtime->hw.rate_min = rate; | ||
| 190 | substream->runtime->hw.rate_max = rate; | ||
| 191 | } | ||
| 192 | |||
| 193 | snd_pcm_set_sync(substream); | ||
| 194 | |||
| 195 | mutex_unlock(&motu->mutex); | ||
| 196 | |||
| 197 | return err; | ||
| 198 | err_locked: | ||
| 199 | mutex_unlock(&motu->mutex); | ||
| 200 | snd_motu_stream_lock_release(motu); | ||
| 201 | return err; | ||
| 202 | } | ||
| 203 | |||
| 204 | static int pcm_close(struct snd_pcm_substream *substream) | ||
| 205 | { | ||
| 206 | struct snd_motu *motu = substream->private_data; | ||
| 207 | |||
| 208 | snd_motu_stream_lock_release(motu); | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | static int capture_hw_params(struct snd_pcm_substream *substream, | ||
| 214 | struct snd_pcm_hw_params *hw_params) | ||
| 215 | { | ||
| 216 | struct snd_motu *motu = substream->private_data; | ||
| 217 | int err; | ||
| 218 | |||
| 219 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
| 220 | params_buffer_bytes(hw_params)); | ||
| 221 | if (err < 0) | ||
| 222 | return err; | ||
| 223 | |||
| 224 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { | ||
| 225 | mutex_lock(&motu->mutex); | ||
| 226 | motu->capture_substreams++; | ||
| 227 | mutex_unlock(&motu->mutex); | ||
| 228 | } | ||
| 229 | |||
| 230 | return 0; | ||
| 231 | } | ||
| 232 | static int playback_hw_params(struct snd_pcm_substream *substream, | ||
| 233 | struct snd_pcm_hw_params *hw_params) | ||
| 234 | { | ||
| 235 | struct snd_motu *motu = substream->private_data; | ||
| 236 | int err; | ||
| 237 | |||
| 238 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
| 239 | params_buffer_bytes(hw_params)); | ||
| 240 | if (err < 0) | ||
| 241 | return err; | ||
| 242 | |||
| 243 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { | ||
| 244 | mutex_lock(&motu->mutex); | ||
| 245 | motu->playback_substreams++; | ||
| 246 | mutex_unlock(&motu->mutex); | ||
| 247 | } | ||
| 248 | |||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static int capture_hw_free(struct snd_pcm_substream *substream) | ||
| 253 | { | ||
| 254 | struct snd_motu *motu = substream->private_data; | ||
| 255 | |||
| 256 | mutex_lock(&motu->mutex); | ||
| 257 | |||
| 258 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) | ||
| 259 | motu->capture_substreams--; | ||
| 260 | |||
| 261 | snd_motu_stream_stop_duplex(motu); | ||
| 262 | |||
| 263 | mutex_unlock(&motu->mutex); | ||
| 264 | |||
| 265 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
| 266 | } | ||
| 267 | |||
| 268 | static int playback_hw_free(struct snd_pcm_substream *substream) | ||
| 269 | { | ||
| 270 | struct snd_motu *motu = substream->private_data; | ||
| 271 | |||
| 272 | mutex_lock(&motu->mutex); | ||
| 273 | |||
| 274 | if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) | ||
| 275 | motu->playback_substreams--; | ||
| 276 | |||
| 277 | snd_motu_stream_stop_duplex(motu); | ||
| 278 | |||
| 279 | mutex_unlock(&motu->mutex); | ||
| 280 | |||
| 281 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
| 282 | } | ||
| 283 | |||
| 284 | static int capture_prepare(struct snd_pcm_substream *substream) | ||
| 285 | { | ||
| 286 | struct snd_motu *motu = substream->private_data; | ||
| 287 | int err; | ||
| 288 | |||
| 289 | mutex_lock(&motu->mutex); | ||
| 290 | err = snd_motu_stream_start_duplex(motu, substream->runtime->rate); | ||
| 291 | mutex_unlock(&motu->mutex); | ||
| 292 | if (err >= 0) | ||
| 293 | amdtp_stream_pcm_prepare(&motu->tx_stream); | ||
| 294 | |||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | static int playback_prepare(struct snd_pcm_substream *substream) | ||
| 298 | { | ||
| 299 | struct snd_motu *motu = substream->private_data; | ||
| 300 | int err; | ||
| 301 | |||
| 302 | mutex_lock(&motu->mutex); | ||
| 303 | err = snd_motu_stream_start_duplex(motu, substream->runtime->rate); | ||
| 304 | mutex_unlock(&motu->mutex); | ||
| 305 | if (err >= 0) | ||
| 306 | amdtp_stream_pcm_prepare(&motu->rx_stream); | ||
| 307 | |||
| 308 | return err; | ||
| 309 | } | ||
| 310 | |||
| 311 | static int capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 312 | { | ||
| 313 | struct snd_motu *motu = substream->private_data; | ||
| 314 | |||
| 315 | switch (cmd) { | ||
| 316 | case SNDRV_PCM_TRIGGER_START: | ||
| 317 | amdtp_stream_pcm_trigger(&motu->tx_stream, substream); | ||
| 318 | break; | ||
| 319 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 320 | amdtp_stream_pcm_trigger(&motu->tx_stream, NULL); | ||
| 321 | break; | ||
| 322 | default: | ||
| 323 | return -EINVAL; | ||
| 324 | } | ||
| 325 | |||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | static int playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 329 | { | ||
| 330 | struct snd_motu *motu = substream->private_data; | ||
| 331 | |||
| 332 | switch (cmd) { | ||
| 333 | case SNDRV_PCM_TRIGGER_START: | ||
| 334 | amdtp_stream_pcm_trigger(&motu->rx_stream, substream); | ||
| 335 | break; | ||
| 336 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 337 | amdtp_stream_pcm_trigger(&motu->rx_stream, NULL); | ||
| 338 | break; | ||
| 339 | default: | ||
| 340 | return -EINVAL; | ||
| 341 | } | ||
| 342 | |||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream) | ||
| 347 | { | ||
| 348 | struct snd_motu *motu = substream->private_data; | ||
| 349 | |||
| 350 | return amdtp_stream_pcm_pointer(&motu->tx_stream); | ||
| 351 | } | ||
| 352 | static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) | ||
| 353 | { | ||
| 354 | struct snd_motu *motu = substream->private_data; | ||
| 355 | |||
| 356 | return amdtp_stream_pcm_pointer(&motu->rx_stream); | ||
| 357 | } | ||
| 358 | |||
| 359 | int snd_motu_create_pcm_devices(struct snd_motu *motu) | ||
| 360 | { | ||
| 361 | static struct snd_pcm_ops capture_ops = { | ||
| 362 | .open = pcm_open, | ||
| 363 | .close = pcm_close, | ||
| 364 | .ioctl = snd_pcm_lib_ioctl, | ||
| 365 | .hw_params = capture_hw_params, | ||
| 366 | .hw_free = capture_hw_free, | ||
| 367 | .prepare = capture_prepare, | ||
| 368 | .trigger = capture_trigger, | ||
| 369 | .pointer = capture_pointer, | ||
| 370 | .page = snd_pcm_lib_get_vmalloc_page, | ||
| 371 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 372 | }; | ||
| 373 | static struct snd_pcm_ops playback_ops = { | ||
| 374 | .open = pcm_open, | ||
| 375 | .close = pcm_close, | ||
| 376 | .ioctl = snd_pcm_lib_ioctl, | ||
| 377 | .hw_params = playback_hw_params, | ||
| 378 | .hw_free = playback_hw_free, | ||
| 379 | .prepare = playback_prepare, | ||
| 380 | .trigger = playback_trigger, | ||
| 381 | .pointer = playback_pointer, | ||
| 382 | .page = snd_pcm_lib_get_vmalloc_page, | ||
| 383 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 384 | }; | ||
| 385 | struct snd_pcm *pcm; | ||
| 386 | int err; | ||
| 387 | |||
| 388 | err = snd_pcm_new(motu->card, motu->card->driver, 0, 1, 1, &pcm); | ||
| 389 | if (err < 0) | ||
| 390 | return err; | ||
| 391 | pcm->private_data = motu; | ||
| 392 | strcpy(pcm->name, motu->card->shortname); | ||
| 393 | |||
| 394 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); | ||
| 395 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); | ||
| 396 | |||
| 397 | return 0; | ||
| 398 | } | ||
diff --git a/sound/firewire/motu/motu-proc.c b/sound/firewire/motu/motu-proc.c new file mode 100644 index 000000000000..4edc064999ed --- /dev/null +++ b/sound/firewire/motu/motu-proc.c | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | /* | ||
| 2 | * motu-proc.c - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "./motu.h" | ||
| 10 | |||
| 11 | static const char *const clock_names[] = { | ||
| 12 | [SND_MOTU_CLOCK_SOURCE_INTERNAL] = "Internal", | ||
| 13 | [SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB] = "ADAT on Dsub-9pin interface", | ||
| 14 | [SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT] = "ADAT on optical interface", | ||
| 15 | [SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A] = "ADAT on optical interface A", | ||
| 16 | [SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B] = "ADAT on optical interface B", | ||
| 17 | [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT] = "S/PDIF on optical interface", | ||
| 18 | [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A] = "S/PDIF on optical interface A", | ||
| 19 | [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B] = "S/PDIF on optical interface B", | ||
| 20 | [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PCIF on coaxial interface", | ||
| 21 | [SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR] = "AESEBU on XLR interface", | ||
| 22 | [SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC] = "Word clock on BNC interface", | ||
| 23 | }; | ||
| 24 | |||
| 25 | static void proc_read_clock(struct snd_info_entry *entry, | ||
| 26 | struct snd_info_buffer *buffer) | ||
| 27 | { | ||
| 28 | |||
| 29 | struct snd_motu *motu = entry->private_data; | ||
| 30 | const struct snd_motu_protocol *const protocol = motu->spec->protocol; | ||
| 31 | unsigned int rate; | ||
| 32 | enum snd_motu_clock_source source; | ||
| 33 | |||
| 34 | if (protocol->get_clock_rate(motu, &rate) < 0) | ||
| 35 | return; | ||
| 36 | if (protocol->get_clock_source(motu, &source) < 0) | ||
| 37 | return; | ||
| 38 | |||
| 39 | snd_iprintf(buffer, "Rate:\t%d\n", rate); | ||
| 40 | snd_iprintf(buffer, "Source:\t%s\n", clock_names[source]); | ||
| 41 | } | ||
| 42 | |||
| 43 | static void proc_read_format(struct snd_info_entry *entry, | ||
| 44 | struct snd_info_buffer *buffer) | ||
| 45 | { | ||
| 46 | struct snd_motu *motu = entry->private_data; | ||
| 47 | const struct snd_motu_protocol *const protocol = motu->spec->protocol; | ||
| 48 | unsigned int mode; | ||
| 49 | struct snd_motu_packet_format *formats; | ||
| 50 | int i; | ||
| 51 | |||
| 52 | if (protocol->cache_packet_formats(motu) < 0) | ||
| 53 | return; | ||
| 54 | |||
| 55 | snd_iprintf(buffer, "tx:\tmsg\tfixed\tdiffered\n"); | ||
| 56 | for (i = 0; i < SND_MOTU_CLOCK_RATE_COUNT; ++i) { | ||
| 57 | mode = i >> 1; | ||
| 58 | |||
| 59 | formats = &motu->tx_packet_formats; | ||
| 60 | snd_iprintf(buffer, | ||
| 61 | "%u:\t%u\t%u\t%u\n", | ||
| 62 | snd_motu_clock_rates[i], | ||
| 63 | formats->msg_chunks, | ||
| 64 | formats->fixed_part_pcm_chunks[mode], | ||
| 65 | formats->differed_part_pcm_chunks[mode]); | ||
| 66 | } | ||
| 67 | |||
| 68 | snd_iprintf(buffer, "rx:\tmsg\tfixed\tdiffered\n"); | ||
| 69 | for (i = 0; i < SND_MOTU_CLOCK_RATE_COUNT; ++i) { | ||
| 70 | mode = i >> 1; | ||
| 71 | |||
| 72 | formats = &motu->rx_packet_formats; | ||
| 73 | snd_iprintf(buffer, | ||
| 74 | "%u:\t%u\t%u\t%u\n", | ||
| 75 | snd_motu_clock_rates[i], | ||
| 76 | formats->msg_chunks, | ||
| 77 | formats->fixed_part_pcm_chunks[mode], | ||
| 78 | formats->differed_part_pcm_chunks[mode]); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | static void add_node(struct snd_motu *motu, struct snd_info_entry *root, | ||
| 83 | const char *name, | ||
| 84 | void (*op)(struct snd_info_entry *e, | ||
| 85 | struct snd_info_buffer *b)) | ||
| 86 | { | ||
| 87 | struct snd_info_entry *entry; | ||
| 88 | |||
| 89 | entry = snd_info_create_card_entry(motu->card, name, root); | ||
| 90 | if (entry == NULL) | ||
| 91 | return; | ||
| 92 | |||
| 93 | snd_info_set_text_ops(entry, motu, op); | ||
| 94 | if (snd_info_register(entry) < 0) | ||
| 95 | snd_info_free_entry(entry); | ||
| 96 | } | ||
| 97 | |||
| 98 | void snd_motu_proc_init(struct snd_motu *motu) | ||
| 99 | { | ||
| 100 | struct snd_info_entry *root; | ||
| 101 | |||
| 102 | /* | ||
| 103 | * All nodes are automatically removed at snd_card_disconnect(), | ||
| 104 | * by following to link list. | ||
| 105 | */ | ||
| 106 | root = snd_info_create_card_entry(motu->card, "firewire", | ||
| 107 | motu->card->proc_root); | ||
| 108 | if (root == NULL) | ||
| 109 | return; | ||
| 110 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
| 111 | if (snd_info_register(root) < 0) { | ||
| 112 | snd_info_free_entry(root); | ||
| 113 | return; | ||
| 114 | } | ||
| 115 | |||
| 116 | add_node(motu, root, "clock", proc_read_clock); | ||
| 117 | add_node(motu, root, "format", proc_read_format); | ||
| 118 | } | ||
diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c new file mode 100644 index 000000000000..05b5d287c2f3 --- /dev/null +++ b/sound/firewire/motu/motu-protocol-v2.c | |||
| @@ -0,0 +1,237 @@ | |||
| 1 | /* | ||
| 2 | * motu-protocol-v2.c - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "motu.h" | ||
| 10 | |||
| 11 | #define V2_CLOCK_STATUS_OFFSET 0x0b14 | ||
| 12 | #define V2_CLOCK_RATE_MASK 0x00000038 | ||
| 13 | #define V2_CLOCK_RATE_SHIFT 3 | ||
| 14 | #define V2_CLOCK_SRC_MASK 0x00000007 | ||
| 15 | #define V2_CLOCK_SRC_SHIFT 0 | ||
| 16 | |||
| 17 | #define V2_IN_OUT_CONF_OFFSET 0x0c04 | ||
| 18 | #define V2_OPT_OUT_IFACE_MASK 0x00000c00 | ||
| 19 | #define V2_OPT_OUT_IFACE_SHIFT 10 | ||
| 20 | #define V2_OPT_IN_IFACE_MASK 0x00000300 | ||
| 21 | #define V2_OPT_IN_IFACE_SHIFT 8 | ||
| 22 | #define V2_OPT_IFACE_MODE_NONE 0 | ||
| 23 | #define V2_OPT_IFACE_MODE_ADAT 1 | ||
| 24 | #define V2_OPT_IFACE_MODE_SPDIF 2 | ||
| 25 | |||
| 26 | static int v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate) | ||
| 27 | { | ||
| 28 | __be32 reg; | ||
| 29 | unsigned int index; | ||
| 30 | int err; | ||
| 31 | |||
| 32 | err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, | ||
| 33 | sizeof(reg)); | ||
| 34 | if (err < 0) | ||
| 35 | return err; | ||
| 36 | |||
| 37 | index = (be32_to_cpu(reg) & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT; | ||
| 38 | if (index >= ARRAY_SIZE(snd_motu_clock_rates)) | ||
| 39 | return -EIO; | ||
| 40 | |||
| 41 | *rate = snd_motu_clock_rates[index]; | ||
| 42 | |||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate) | ||
| 47 | { | ||
| 48 | __be32 reg; | ||
| 49 | u32 data; | ||
| 50 | int i; | ||
| 51 | int err; | ||
| 52 | |||
| 53 | for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) { | ||
| 54 | if (snd_motu_clock_rates[i] == rate) | ||
| 55 | break; | ||
| 56 | } | ||
| 57 | if (i == ARRAY_SIZE(snd_motu_clock_rates)) | ||
| 58 | return -EINVAL; | ||
| 59 | |||
| 60 | err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, | ||
| 61 | sizeof(reg)); | ||
| 62 | if (err < 0) | ||
| 63 | return err; | ||
| 64 | data = be32_to_cpu(reg); | ||
| 65 | |||
| 66 | data &= ~V2_CLOCK_RATE_MASK; | ||
| 67 | data |= i << V2_CLOCK_RATE_SHIFT; | ||
| 68 | |||
| 69 | reg = cpu_to_be32(data); | ||
| 70 | return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, ®, | ||
| 71 | sizeof(reg)); | ||
| 72 | } | ||
| 73 | |||
| 74 | static int v2_get_clock_source(struct snd_motu *motu, | ||
| 75 | enum snd_motu_clock_source *src) | ||
| 76 | { | ||
| 77 | __be32 reg; | ||
| 78 | unsigned int index; | ||
| 79 | int err; | ||
| 80 | |||
| 81 | err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, ®, | ||
| 82 | sizeof(reg)); | ||
| 83 | if (err < 0) | ||
| 84 | return err; | ||
| 85 | |||
| 86 | index = be32_to_cpu(reg) & V2_CLOCK_SRC_MASK; | ||
| 87 | if (index > 5) | ||
| 88 | return -EIO; | ||
| 89 | |||
| 90 | /* To check the configuration of optical interface. */ | ||
| 91 | err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, ®, | ||
| 92 | sizeof(reg)); | ||
| 93 | if (err < 0) | ||
| 94 | return err; | ||
| 95 | |||
| 96 | switch (index) { | ||
| 97 | case 0: | ||
| 98 | *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; | ||
| 99 | break; | ||
| 100 | case 1: | ||
| 101 | if (be32_to_cpu(reg) & 0x00000200) | ||
| 102 | *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT; | ||
| 103 | else | ||
| 104 | *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT; | ||
| 105 | break; | ||
| 106 | case 2: | ||
| 107 | *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; | ||
| 108 | break; | ||
| 109 | case 4: | ||
| 110 | *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; | ||
| 111 | break; | ||
| 112 | case 5: | ||
| 113 | *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB; | ||
| 114 | break; | ||
| 115 | default: | ||
| 116 | return -EIO; | ||
| 117 | } | ||
| 118 | |||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable) | ||
| 123 | { | ||
| 124 | /* V2 protocol doesn't have this feature. */ | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | static void calculate_fixed_part(struct snd_motu_packet_format *formats, | ||
| 129 | enum amdtp_stream_direction dir, | ||
| 130 | enum snd_motu_spec_flags flags, | ||
| 131 | unsigned char analog_ports) | ||
| 132 | { | ||
| 133 | unsigned char pcm_chunks[3] = {0, 0, 0}; | ||
| 134 | |||
| 135 | formats->msg_chunks = 2; | ||
| 136 | |||
| 137 | pcm_chunks[0] = analog_ports; | ||
| 138 | pcm_chunks[1] = analog_ports; | ||
| 139 | if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) | ||
| 140 | pcm_chunks[2] = analog_ports; | ||
| 141 | |||
| 142 | if (dir == AMDTP_IN_STREAM) { | ||
| 143 | if (flags & SND_MOTU_SPEC_TX_MICINST_CHUNK) { | ||
| 144 | pcm_chunks[0] += 2; | ||
| 145 | pcm_chunks[1] += 2; | ||
| 146 | } | ||
| 147 | if (flags & SND_MOTU_SPEC_TX_RETURN_CHUNK) { | ||
| 148 | pcm_chunks[0] += 2; | ||
| 149 | pcm_chunks[1] += 2; | ||
| 150 | } | ||
| 151 | } else { | ||
| 152 | /* | ||
| 153 | * Packets to v2 units transfer main-out-1/2 and phone-out-1/2. | ||
| 154 | */ | ||
| 155 | pcm_chunks[0] += 4; | ||
| 156 | pcm_chunks[1] += 4; | ||
| 157 | } | ||
| 158 | |||
| 159 | /* | ||
| 160 | * All of v2 models have a pair of coaxial interfaces for digital in/out | ||
| 161 | * port. At 44.1/48.0/88.2/96.0 kHz, packets includes PCM from these | ||
| 162 | * ports. | ||
| 163 | */ | ||
| 164 | pcm_chunks[0] += 2; | ||
| 165 | pcm_chunks[1] += 2; | ||
| 166 | |||
| 167 | /* This part should be multiples of 4. */ | ||
| 168 | formats->fixed_part_pcm_chunks[0] = round_up(2 + pcm_chunks[0], 4) - 2; | ||
| 169 | formats->fixed_part_pcm_chunks[1] = round_up(2 + pcm_chunks[1], 4) - 2; | ||
| 170 | if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) | ||
| 171 | formats->fixed_part_pcm_chunks[2] = | ||
| 172 | round_up(2 + pcm_chunks[2], 4) - 2; | ||
| 173 | } | ||
| 174 | |||
| 175 | static void calculate_differed_part(struct snd_motu_packet_format *formats, | ||
| 176 | enum snd_motu_spec_flags flags, | ||
| 177 | u32 data, u32 mask, u32 shift) | ||
| 178 | { | ||
| 179 | unsigned char pcm_chunks[3] = {0, 0}; | ||
| 180 | |||
| 181 | /* | ||
| 182 | * When optical interfaces are configured for S/PDIF (TOSLINK), | ||
| 183 | * the above PCM frames come from them, instead of coaxial | ||
| 184 | * interfaces. | ||
| 185 | */ | ||
| 186 | data = (data & mask) >> shift; | ||
| 187 | if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) && | ||
| 188 | data == V2_OPT_IFACE_MODE_ADAT) { | ||
| 189 | pcm_chunks[0] += 8; | ||
| 190 | pcm_chunks[1] += 4; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* At mode x4, no data chunks are supported in this part. */ | ||
| 194 | formats->differed_part_pcm_chunks[0] = pcm_chunks[0]; | ||
| 195 | formats->differed_part_pcm_chunks[1] = pcm_chunks[1]; | ||
| 196 | } | ||
| 197 | |||
| 198 | static int v2_cache_packet_formats(struct snd_motu *motu) | ||
| 199 | { | ||
| 200 | __be32 reg; | ||
| 201 | u32 data; | ||
| 202 | int err; | ||
| 203 | |||
| 204 | err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, ®, | ||
| 205 | sizeof(reg)); | ||
| 206 | if (err < 0) | ||
| 207 | return err; | ||
| 208 | data = be32_to_cpu(reg); | ||
| 209 | |||
| 210 | calculate_fixed_part(&motu->tx_packet_formats, AMDTP_IN_STREAM, | ||
| 211 | motu->spec->flags, motu->spec->analog_in_ports); | ||
| 212 | calculate_differed_part(&motu->tx_packet_formats, motu->spec->flags, | ||
| 213 | data, V2_OPT_IN_IFACE_MASK, V2_OPT_IN_IFACE_SHIFT); | ||
| 214 | |||
| 215 | calculate_fixed_part(&motu->rx_packet_formats, AMDTP_OUT_STREAM, | ||
| 216 | motu->spec->flags, motu->spec->analog_out_ports); | ||
| 217 | calculate_differed_part(&motu->rx_packet_formats, motu->spec->flags, | ||
| 218 | data, V2_OPT_OUT_IFACE_MASK, V2_OPT_OUT_IFACE_SHIFT); | ||
| 219 | |||
| 220 | motu->tx_packet_formats.midi_flag_offset = 4; | ||
| 221 | motu->tx_packet_formats.midi_byte_offset = 6; | ||
| 222 | motu->tx_packet_formats.pcm_byte_offset = 10; | ||
| 223 | |||
| 224 | motu->rx_packet_formats.midi_flag_offset = 4; | ||
| 225 | motu->rx_packet_formats.midi_byte_offset = 6; | ||
| 226 | motu->rx_packet_formats.pcm_byte_offset = 10; | ||
| 227 | |||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | const struct snd_motu_protocol snd_motu_protocol_v2 = { | ||
| 232 | .get_clock_rate = v2_get_clock_rate, | ||
| 233 | .set_clock_rate = v2_set_clock_rate, | ||
| 234 | .get_clock_source = v2_get_clock_source, | ||
| 235 | .switch_fetching_mode = v2_switch_fetching_mode, | ||
| 236 | .cache_packet_formats = v2_cache_packet_formats, | ||
| 237 | }; | ||
diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c new file mode 100644 index 000000000000..ddb647254ed2 --- /dev/null +++ b/sound/firewire/motu/motu-protocol-v3.c | |||
| @@ -0,0 +1,311 @@ | |||
| 1 | /* | ||
| 2 | * motu-protocol-v3.c - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/delay.h> | ||
| 10 | #include "motu.h" | ||
| 11 | |||
| 12 | #define V3_CLOCK_STATUS_OFFSET 0x0b14 | ||
| 13 | #define V3_FETCH_PCM_FRAMES 0x02000000 | ||
| 14 | #define V3_CLOCK_RATE_MASK 0x0000ff00 | ||
| 15 | #define V3_CLOCK_RATE_SHIFT 8 | ||
| 16 | #define V3_CLOCK_SOURCE_MASK 0x000000ff | ||
| 17 | |||
| 18 | #define V3_OPT_IFACE_MODE_OFFSET 0x0c94 | ||
| 19 | #define V3_ENABLE_OPT_IN_IFACE_A 0x00000001 | ||
| 20 | #define V3_ENABLE_OPT_IN_IFACE_B 0x00000002 | ||
| 21 | #define V3_ENABLE_OPT_OUT_IFACE_A 0x00000100 | ||
| 22 | #define V3_ENABLE_OPT_OUT_IFACE_B 0x00000200 | ||
| 23 | #define V3_NO_ADAT_OPT_IN_IFACE_A 0x00010000 | ||
| 24 | #define V3_NO_ADAT_OPT_IN_IFACE_B 0x00100000 | ||
| 25 | #define V3_NO_ADAT_OPT_OUT_IFACE_A 0x00040000 | ||
| 26 | #define V3_NO_ADAT_OPT_OUT_IFACE_B 0x00400000 | ||
| 27 | |||
| 28 | static int v3_get_clock_rate(struct snd_motu *motu, unsigned int *rate) | ||
| 29 | { | ||
| 30 | __be32 reg; | ||
| 31 | u32 data; | ||
| 32 | int err; | ||
| 33 | |||
| 34 | err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, | ||
| 35 | sizeof(reg)); | ||
| 36 | if (err < 0) | ||
| 37 | return err; | ||
| 38 | data = be32_to_cpu(reg); | ||
| 39 | |||
| 40 | data = (data & V3_CLOCK_RATE_MASK) >> V3_CLOCK_RATE_SHIFT; | ||
| 41 | if (data >= ARRAY_SIZE(snd_motu_clock_rates)) | ||
| 42 | return -EIO; | ||
| 43 | |||
| 44 | *rate = snd_motu_clock_rates[data]; | ||
| 45 | |||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | static int v3_set_clock_rate(struct snd_motu *motu, unsigned int rate) | ||
| 50 | { | ||
| 51 | __be32 reg; | ||
| 52 | u32 data; | ||
| 53 | bool need_to_wait; | ||
| 54 | int i, err; | ||
| 55 | |||
| 56 | for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) { | ||
| 57 | if (snd_motu_clock_rates[i] == rate) | ||
| 58 | break; | ||
| 59 | } | ||
| 60 | if (i == ARRAY_SIZE(snd_motu_clock_rates)) | ||
| 61 | return -EINVAL; | ||
| 62 | |||
| 63 | err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, | ||
| 64 | sizeof(reg)); | ||
| 65 | if (err < 0) | ||
| 66 | return err; | ||
| 67 | data = be32_to_cpu(reg); | ||
| 68 | |||
| 69 | data &= ~(V3_CLOCK_RATE_MASK | V3_FETCH_PCM_FRAMES); | ||
| 70 | data |= i << V3_CLOCK_RATE_SHIFT; | ||
| 71 | |||
| 72 | need_to_wait = data != be32_to_cpu(reg); | ||
| 73 | |||
| 74 | reg = cpu_to_be32(data); | ||
| 75 | err = snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, ®, | ||
| 76 | sizeof(reg)); | ||
| 77 | if (err < 0) | ||
| 78 | return err; | ||
| 79 | |||
| 80 | if (need_to_wait) { | ||
| 81 | /* Cost expensive. */ | ||
| 82 | if (msleep_interruptible(4000) > 0) | ||
| 83 | return -EINTR; | ||
| 84 | } | ||
| 85 | |||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | static int v3_get_clock_source(struct snd_motu *motu, | ||
| 90 | enum snd_motu_clock_source *src) | ||
| 91 | { | ||
| 92 | __be32 reg; | ||
| 93 | u32 data; | ||
| 94 | unsigned int val; | ||
| 95 | int err; | ||
| 96 | |||
| 97 | err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, | ||
| 98 | sizeof(reg)); | ||
| 99 | if (err < 0) | ||
| 100 | return err; | ||
| 101 | data = be32_to_cpu(reg); | ||
| 102 | |||
| 103 | val = data & V3_CLOCK_SOURCE_MASK; | ||
| 104 | if (val == 0x00) { | ||
| 105 | *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; | ||
| 106 | } else if (val == 0x01) { | ||
| 107 | *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; | ||
| 108 | } else if (val == 0x10) { | ||
| 109 | *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; | ||
| 110 | } else if (val == 0x18 || val == 0x19) { | ||
| 111 | err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, | ||
| 112 | ®, sizeof(reg)); | ||
| 113 | if (err < 0) | ||
| 114 | return err; | ||
| 115 | data = be32_to_cpu(reg); | ||
| 116 | |||
| 117 | if (val == 0x18) { | ||
| 118 | if (data & V3_NO_ADAT_OPT_IN_IFACE_A) | ||
| 119 | *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A; | ||
| 120 | else | ||
| 121 | *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A; | ||
| 122 | } else { | ||
| 123 | if (data & V3_NO_ADAT_OPT_IN_IFACE_B) | ||
| 124 | *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B; | ||
| 125 | else | ||
| 126 | *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B; | ||
| 127 | } | ||
| 128 | } else { | ||
| 129 | *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN; | ||
| 130 | } | ||
| 131 | |||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int v3_switch_fetching_mode(struct snd_motu *motu, bool enable) | ||
| 136 | { | ||
| 137 | __be32 reg; | ||
| 138 | u32 data; | ||
| 139 | int err; | ||
| 140 | |||
| 141 | err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, | ||
| 142 | sizeof(reg)); | ||
| 143 | if (err < 0) | ||
| 144 | return 0; | ||
| 145 | data = be32_to_cpu(reg); | ||
| 146 | |||
| 147 | if (enable) | ||
| 148 | data |= V3_FETCH_PCM_FRAMES; | ||
| 149 | else | ||
| 150 | data &= ~V3_FETCH_PCM_FRAMES; | ||
| 151 | |||
| 152 | reg = cpu_to_be32(data); | ||
| 153 | return snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, ®, | ||
| 154 | sizeof(reg)); | ||
| 155 | } | ||
| 156 | |||
| 157 | static void calculate_fixed_part(struct snd_motu_packet_format *formats, | ||
| 158 | enum amdtp_stream_direction dir, | ||
| 159 | enum snd_motu_spec_flags flags, | ||
| 160 | unsigned char analog_ports) | ||
| 161 | { | ||
| 162 | unsigned char pcm_chunks[3] = {0, 0, 0}; | ||
| 163 | |||
| 164 | formats->msg_chunks = 2; | ||
| 165 | |||
| 166 | pcm_chunks[0] = analog_ports; | ||
| 167 | pcm_chunks[1] = analog_ports; | ||
| 168 | if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) | ||
| 169 | pcm_chunks[2] = analog_ports; | ||
| 170 | |||
| 171 | if (dir == AMDTP_IN_STREAM) { | ||
| 172 | if (flags & SND_MOTU_SPEC_TX_MICINST_CHUNK) { | ||
| 173 | pcm_chunks[0] += 2; | ||
| 174 | pcm_chunks[1] += 2; | ||
| 175 | if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) | ||
| 176 | pcm_chunks[2] += 2; | ||
| 177 | } | ||
| 178 | |||
| 179 | if (flags & SND_MOTU_SPEC_TX_RETURN_CHUNK) { | ||
| 180 | pcm_chunks[0] += 2; | ||
| 181 | pcm_chunks[1] += 2; | ||
| 182 | if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) | ||
| 183 | pcm_chunks[2] += 2; | ||
| 184 | } | ||
| 185 | |||
| 186 | if (flags & SND_MOTU_SPEC_TX_REVERB_CHUNK) { | ||
| 187 | pcm_chunks[0] += 2; | ||
| 188 | pcm_chunks[1] += 2; | ||
| 189 | } | ||
| 190 | } else { | ||
| 191 | /* | ||
| 192 | * Packets to v2 units transfer main-out-1/2 and phone-out-1/2. | ||
| 193 | */ | ||
| 194 | pcm_chunks[0] += 4; | ||
| 195 | pcm_chunks[1] += 4; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* | ||
| 199 | * At least, packets have two data chunks for S/PDIF on coaxial | ||
| 200 | * interface. | ||
| 201 | */ | ||
| 202 | pcm_chunks[0] += 2; | ||
| 203 | pcm_chunks[1] += 2; | ||
| 204 | |||
| 205 | /* | ||
| 206 | * Fixed part consists of PCM chunks multiple of 4, with msg chunks. As | ||
| 207 | * a result, this part can includes empty data chunks. | ||
| 208 | */ | ||
| 209 | formats->fixed_part_pcm_chunks[0] = round_up(2 + pcm_chunks[0], 4) - 2; | ||
| 210 | formats->fixed_part_pcm_chunks[1] = round_up(2 + pcm_chunks[1], 4) - 2; | ||
| 211 | if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4) | ||
| 212 | formats->fixed_part_pcm_chunks[2] = | ||
| 213 | round_up(2 + pcm_chunks[2], 4) - 2; | ||
| 214 | } | ||
| 215 | |||
| 216 | static void calculate_differed_part(struct snd_motu_packet_format *formats, | ||
| 217 | enum snd_motu_spec_flags flags, u32 data, | ||
| 218 | u32 a_enable_mask, u32 a_no_adat_mask, | ||
| 219 | u32 b_enable_mask, u32 b_no_adat_mask) | ||
| 220 | { | ||
| 221 | unsigned char pcm_chunks[3] = {0, 0, 0}; | ||
| 222 | int i; | ||
| 223 | |||
| 224 | if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) && (data & a_enable_mask)) { | ||
| 225 | if (data & a_no_adat_mask) { | ||
| 226 | /* | ||
| 227 | * Additional two data chunks for S/PDIF on optical | ||
| 228 | * interface A. This includes empty data chunks. | ||
| 229 | */ | ||
| 230 | pcm_chunks[0] += 4; | ||
| 231 | pcm_chunks[1] += 4; | ||
| 232 | } else { | ||
| 233 | /* | ||
| 234 | * Additional data chunks for ADAT on optical interface | ||
| 235 | * A. | ||
| 236 | */ | ||
| 237 | pcm_chunks[0] += 8; | ||
| 238 | pcm_chunks[1] += 4; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_B) && (data & b_enable_mask)) { | ||
| 243 | if (data & b_no_adat_mask) { | ||
| 244 | /* | ||
| 245 | * Additional two data chunks for S/PDIF on optical | ||
| 246 | * interface B. This includes empty data chunks. | ||
| 247 | */ | ||
| 248 | pcm_chunks[0] += 4; | ||
| 249 | pcm_chunks[1] += 4; | ||
| 250 | } else { | ||
| 251 | /* | ||
| 252 | * Additional data chunks for ADAT on optical interface | ||
| 253 | * B. | ||
| 254 | */ | ||
| 255 | pcm_chunks[0] += 8; | ||
| 256 | pcm_chunks[1] += 4; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | for (i = 0; i < 3; ++i) { | ||
| 261 | if (pcm_chunks[i] > 0) | ||
| 262 | pcm_chunks[i] = round_up(pcm_chunks[i], 4); | ||
| 263 | |||
| 264 | formats->differed_part_pcm_chunks[i] = pcm_chunks[i]; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | static int v3_cache_packet_formats(struct snd_motu *motu) | ||
| 269 | { | ||
| 270 | __be32 reg; | ||
| 271 | u32 data; | ||
| 272 | int err; | ||
| 273 | |||
| 274 | err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, ®, | ||
| 275 | sizeof(reg)); | ||
| 276 | if (err < 0) | ||
| 277 | return err; | ||
| 278 | data = be32_to_cpu(reg); | ||
| 279 | |||
| 280 | calculate_fixed_part(&motu->tx_packet_formats, AMDTP_IN_STREAM, | ||
| 281 | motu->spec->flags, motu->spec->analog_in_ports); | ||
| 282 | calculate_differed_part(&motu->tx_packet_formats, | ||
| 283 | motu->spec->flags, data, | ||
| 284 | V3_ENABLE_OPT_IN_IFACE_A, V3_NO_ADAT_OPT_IN_IFACE_A, | ||
| 285 | V3_ENABLE_OPT_IN_IFACE_B, V3_NO_ADAT_OPT_IN_IFACE_B); | ||
| 286 | |||
| 287 | calculate_fixed_part(&motu->rx_packet_formats, AMDTP_OUT_STREAM, | ||
| 288 | motu->spec->flags, motu->spec->analog_out_ports); | ||
| 289 | calculate_differed_part(&motu->rx_packet_formats, | ||
| 290 | motu->spec->flags, data, | ||
| 291 | V3_ENABLE_OPT_OUT_IFACE_A, V3_NO_ADAT_OPT_OUT_IFACE_A, | ||
| 292 | V3_ENABLE_OPT_OUT_IFACE_B, V3_NO_ADAT_OPT_OUT_IFACE_B); | ||
| 293 | |||
| 294 | motu->tx_packet_formats.midi_flag_offset = 8; | ||
| 295 | motu->tx_packet_formats.midi_byte_offset = 7; | ||
| 296 | motu->tx_packet_formats.pcm_byte_offset = 10; | ||
| 297 | |||
| 298 | motu->rx_packet_formats.midi_flag_offset = 8; | ||
| 299 | motu->rx_packet_formats.midi_byte_offset = 7; | ||
| 300 | motu->rx_packet_formats.pcm_byte_offset = 10; | ||
| 301 | |||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | |||
| 305 | const struct snd_motu_protocol snd_motu_protocol_v3 = { | ||
| 306 | .get_clock_rate = v3_get_clock_rate, | ||
| 307 | .set_clock_rate = v3_set_clock_rate, | ||
| 308 | .get_clock_source = v3_get_clock_source, | ||
| 309 | .switch_fetching_mode = v3_switch_fetching_mode, | ||
| 310 | .cache_packet_formats = v3_cache_packet_formats, | ||
| 311 | }; | ||
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c new file mode 100644 index 000000000000..bd458029099e --- /dev/null +++ b/sound/firewire/motu/motu-stream.c | |||
| @@ -0,0 +1,381 @@ | |||
| 1 | /* | ||
| 2 | * motu-stream.c - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "motu.h" | ||
| 10 | |||
| 11 | #define CALLBACK_TIMEOUT 200 | ||
| 12 | |||
| 13 | #define ISOC_COMM_CONTROL_OFFSET 0x0b00 | ||
| 14 | #define ISOC_COMM_CONTROL_MASK 0xffff0000 | ||
| 15 | #define CHANGE_RX_ISOC_COMM_STATE 0x80000000 | ||
| 16 | #define RX_ISOC_COMM_IS_ACTIVATED 0x40000000 | ||
| 17 | #define RX_ISOC_COMM_CHANNEL_MASK 0x3f000000 | ||
| 18 | #define RX_ISOC_COMM_CHANNEL_SHIFT 24 | ||
| 19 | #define CHANGE_TX_ISOC_COMM_STATE 0x00800000 | ||
| 20 | #define TX_ISOC_COMM_IS_ACTIVATED 0x00400000 | ||
| 21 | #define TX_ISOC_COMM_CHANNEL_MASK 0x003f0000 | ||
| 22 | #define TX_ISOC_COMM_CHANNEL_SHIFT 16 | ||
| 23 | |||
| 24 | #define PACKET_FORMAT_OFFSET 0x0b10 | ||
| 25 | #define TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000080 | ||
| 26 | #define RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000040 | ||
| 27 | #define TX_PACKET_TRANSMISSION_SPEED_MASK 0x0000000f | ||
| 28 | |||
| 29 | static int start_both_streams(struct snd_motu *motu, unsigned int rate) | ||
| 30 | { | ||
| 31 | unsigned int midi_ports = 0; | ||
| 32 | __be32 reg; | ||
| 33 | u32 data; | ||
| 34 | int err; | ||
| 35 | |||
| 36 | if (motu->spec->flags & SND_MOTU_SPEC_HAS_MIDI) | ||
| 37 | midi_ports = 1; | ||
| 38 | |||
| 39 | /* Set packet formation to our packet streaming engine. */ | ||
| 40 | err = amdtp_motu_set_parameters(&motu->rx_stream, rate, midi_ports, | ||
| 41 | &motu->rx_packet_formats); | ||
| 42 | if (err < 0) | ||
| 43 | return err; | ||
| 44 | |||
| 45 | err = amdtp_motu_set_parameters(&motu->tx_stream, rate, midi_ports, | ||
| 46 | &motu->tx_packet_formats); | ||
| 47 | if (err < 0) | ||
| 48 | return err; | ||
| 49 | |||
| 50 | /* Get isochronous resources on the bus. */ | ||
| 51 | err = fw_iso_resources_allocate(&motu->rx_resources, | ||
| 52 | amdtp_stream_get_max_payload(&motu->rx_stream), | ||
| 53 | fw_parent_device(motu->unit)->max_speed); | ||
| 54 | if (err < 0) | ||
| 55 | return err; | ||
| 56 | |||
| 57 | err = fw_iso_resources_allocate(&motu->tx_resources, | ||
| 58 | amdtp_stream_get_max_payload(&motu->tx_stream), | ||
| 59 | fw_parent_device(motu->unit)->max_speed); | ||
| 60 | if (err < 0) | ||
| 61 | return err; | ||
| 62 | |||
| 63 | /* Configure the unit to start isochronous communication. */ | ||
| 64 | err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, ®, | ||
| 65 | sizeof(reg)); | ||
| 66 | if (err < 0) | ||
| 67 | return err; | ||
| 68 | data = be32_to_cpu(reg) & ~ISOC_COMM_CONTROL_MASK; | ||
| 69 | |||
| 70 | data |= CHANGE_RX_ISOC_COMM_STATE | RX_ISOC_COMM_IS_ACTIVATED | | ||
| 71 | (motu->rx_resources.channel << RX_ISOC_COMM_CHANNEL_SHIFT) | | ||
| 72 | CHANGE_TX_ISOC_COMM_STATE | TX_ISOC_COMM_IS_ACTIVATED | | ||
| 73 | (motu->tx_resources.channel << TX_ISOC_COMM_CHANNEL_SHIFT); | ||
| 74 | |||
| 75 | reg = cpu_to_be32(data); | ||
| 76 | return snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, ®, | ||
| 77 | sizeof(reg)); | ||
| 78 | } | ||
| 79 | |||
| 80 | static void stop_both_streams(struct snd_motu *motu) | ||
| 81 | { | ||
| 82 | __be32 reg; | ||
| 83 | u32 data; | ||
| 84 | int err; | ||
| 85 | |||
| 86 | err = motu->spec->protocol->switch_fetching_mode(motu, false); | ||
| 87 | if (err < 0) | ||
| 88 | return; | ||
| 89 | |||
| 90 | err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, ®, | ||
| 91 | sizeof(reg)); | ||
| 92 | if (err < 0) | ||
| 93 | return; | ||
| 94 | data = be32_to_cpu(reg); | ||
| 95 | |||
| 96 | data &= ~(RX_ISOC_COMM_IS_ACTIVATED | TX_ISOC_COMM_IS_ACTIVATED); | ||
| 97 | data |= CHANGE_RX_ISOC_COMM_STATE | CHANGE_TX_ISOC_COMM_STATE; | ||
| 98 | |||
| 99 | reg = cpu_to_be32(data); | ||
| 100 | snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, ®, | ||
| 101 | sizeof(reg)); | ||
| 102 | |||
| 103 | fw_iso_resources_free(&motu->tx_resources); | ||
| 104 | fw_iso_resources_free(&motu->rx_resources); | ||
| 105 | } | ||
| 106 | |||
| 107 | static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream) | ||
| 108 | { | ||
| 109 | struct fw_iso_resources *resources; | ||
| 110 | int err; | ||
| 111 | |||
| 112 | if (stream == &motu->rx_stream) | ||
| 113 | resources = &motu->rx_resources; | ||
| 114 | else | ||
| 115 | resources = &motu->tx_resources; | ||
| 116 | |||
| 117 | err = amdtp_stream_start(stream, resources->channel, | ||
| 118 | fw_parent_device(motu->unit)->max_speed); | ||
| 119 | if (err < 0) | ||
| 120 | return err; | ||
| 121 | |||
| 122 | if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { | ||
| 123 | amdtp_stream_stop(stream); | ||
| 124 | fw_iso_resources_free(resources); | ||
| 125 | return -ETIMEDOUT; | ||
| 126 | } | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static void stop_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream) | ||
| 132 | { | ||
| 133 | struct fw_iso_resources *resources; | ||
| 134 | |||
| 135 | if (stream == &motu->rx_stream) | ||
| 136 | resources = &motu->rx_resources; | ||
| 137 | else | ||
| 138 | resources = &motu->tx_resources; | ||
| 139 | |||
| 140 | amdtp_stream_stop(stream); | ||
| 141 | fw_iso_resources_free(resources); | ||
| 142 | } | ||
| 143 | |||
| 144 | static int ensure_packet_formats(struct snd_motu *motu) | ||
| 145 | { | ||
| 146 | __be32 reg; | ||
| 147 | u32 data; | ||
| 148 | int err; | ||
| 149 | |||
| 150 | err = snd_motu_transaction_read(motu, PACKET_FORMAT_OFFSET, ®, | ||
| 151 | sizeof(reg)); | ||
| 152 | if (err < 0) | ||
| 153 | return err; | ||
| 154 | data = be32_to_cpu(reg); | ||
| 155 | |||
| 156 | data &= ~(TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS | | ||
| 157 | RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS| | ||
| 158 | TX_PACKET_TRANSMISSION_SPEED_MASK); | ||
| 159 | if (motu->tx_packet_formats.differed_part_pcm_chunks[0] == 0) | ||
| 160 | data |= TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS; | ||
| 161 | if (motu->rx_packet_formats.differed_part_pcm_chunks[0] == 0) | ||
| 162 | data |= RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS; | ||
| 163 | data |= fw_parent_device(motu->unit)->max_speed; | ||
| 164 | |||
| 165 | reg = cpu_to_be32(data); | ||
| 166 | return snd_motu_transaction_write(motu, PACKET_FORMAT_OFFSET, ®, | ||
| 167 | sizeof(reg)); | ||
| 168 | } | ||
| 169 | |||
| 170 | int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate) | ||
| 171 | { | ||
| 172 | const struct snd_motu_protocol *protocol = motu->spec->protocol; | ||
| 173 | unsigned int curr_rate; | ||
| 174 | int err = 0; | ||
| 175 | |||
| 176 | if (motu->capture_substreams == 0 && motu->playback_substreams == 0) | ||
| 177 | return 0; | ||
| 178 | |||
| 179 | /* Some packet queueing errors. */ | ||
| 180 | if (amdtp_streaming_error(&motu->rx_stream) || | ||
| 181 | amdtp_streaming_error(&motu->tx_stream)) { | ||
| 182 | amdtp_stream_stop(&motu->rx_stream); | ||
| 183 | amdtp_stream_stop(&motu->tx_stream); | ||
| 184 | stop_both_streams(motu); | ||
| 185 | } | ||
| 186 | |||
| 187 | err = protocol->cache_packet_formats(motu); | ||
| 188 | if (err < 0) | ||
| 189 | return err; | ||
| 190 | |||
| 191 | /* Stop stream if rate is different. */ | ||
| 192 | err = protocol->get_clock_rate(motu, &curr_rate); | ||
| 193 | if (err < 0) { | ||
| 194 | dev_err(&motu->unit->device, | ||
| 195 | "fail to get sampling rate: %d\n", err); | ||
| 196 | return err; | ||
| 197 | } | ||
| 198 | if (rate == 0) | ||
| 199 | rate = curr_rate; | ||
| 200 | if (rate != curr_rate) { | ||
| 201 | amdtp_stream_stop(&motu->rx_stream); | ||
| 202 | amdtp_stream_stop(&motu->tx_stream); | ||
| 203 | stop_both_streams(motu); | ||
| 204 | } | ||
| 205 | |||
| 206 | if (!amdtp_stream_running(&motu->rx_stream)) { | ||
| 207 | err = protocol->set_clock_rate(motu, rate); | ||
| 208 | if (err < 0) { | ||
| 209 | dev_err(&motu->unit->device, | ||
| 210 | "fail to set sampling rate: %d\n", err); | ||
| 211 | return err; | ||
| 212 | } | ||
| 213 | |||
| 214 | err = ensure_packet_formats(motu); | ||
| 215 | if (err < 0) | ||
| 216 | return err; | ||
| 217 | |||
| 218 | err = start_both_streams(motu, rate); | ||
| 219 | if (err < 0) { | ||
| 220 | dev_err(&motu->unit->device, | ||
| 221 | "fail to start isochronous comm: %d\n", err); | ||
| 222 | stop_both_streams(motu); | ||
| 223 | return err; | ||
| 224 | } | ||
| 225 | |||
| 226 | err = start_isoc_ctx(motu, &motu->rx_stream); | ||
| 227 | if (err < 0) { | ||
| 228 | dev_err(&motu->unit->device, | ||
| 229 | "fail to start IT context: %d\n", err); | ||
| 230 | stop_both_streams(motu); | ||
| 231 | return err; | ||
| 232 | } | ||
| 233 | |||
| 234 | err = protocol->switch_fetching_mode(motu, true); | ||
| 235 | if (err < 0) { | ||
| 236 | dev_err(&motu->unit->device, | ||
| 237 | "fail to enable frame fetching: %d\n", err); | ||
| 238 | stop_both_streams(motu); | ||
| 239 | return err; | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | if (!amdtp_stream_running(&motu->tx_stream) && | ||
| 244 | motu->capture_substreams > 0) { | ||
| 245 | err = start_isoc_ctx(motu, &motu->tx_stream); | ||
| 246 | if (err < 0) { | ||
| 247 | dev_err(&motu->unit->device, | ||
| 248 | "fail to start IR context: %d", err); | ||
| 249 | amdtp_stream_stop(&motu->rx_stream); | ||
| 250 | stop_both_streams(motu); | ||
| 251 | return err; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | void snd_motu_stream_stop_duplex(struct snd_motu *motu) | ||
| 259 | { | ||
| 260 | if (motu->capture_substreams == 0) { | ||
| 261 | if (amdtp_stream_running(&motu->tx_stream)) | ||
| 262 | stop_isoc_ctx(motu, &motu->tx_stream); | ||
| 263 | |||
| 264 | if (motu->playback_substreams == 0) { | ||
| 265 | if (amdtp_stream_running(&motu->rx_stream)) | ||
| 266 | stop_isoc_ctx(motu, &motu->rx_stream); | ||
| 267 | stop_both_streams(motu); | ||
| 268 | } | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | static int init_stream(struct snd_motu *motu, enum amdtp_stream_direction dir) | ||
| 273 | { | ||
| 274 | int err; | ||
| 275 | struct amdtp_stream *stream; | ||
| 276 | struct fw_iso_resources *resources; | ||
| 277 | |||
| 278 | if (dir == AMDTP_IN_STREAM) { | ||
| 279 | stream = &motu->tx_stream; | ||
| 280 | resources = &motu->tx_resources; | ||
| 281 | } else { | ||
| 282 | stream = &motu->rx_stream; | ||
| 283 | resources = &motu->rx_resources; | ||
| 284 | } | ||
| 285 | |||
| 286 | err = fw_iso_resources_init(resources, motu->unit); | ||
| 287 | if (err < 0) | ||
| 288 | return err; | ||
| 289 | |||
| 290 | err = amdtp_motu_init(stream, motu->unit, dir, motu->spec->protocol); | ||
| 291 | if (err < 0) { | ||
| 292 | amdtp_stream_destroy(stream); | ||
| 293 | fw_iso_resources_destroy(resources); | ||
| 294 | } | ||
| 295 | |||
| 296 | return err; | ||
| 297 | } | ||
| 298 | |||
| 299 | static void destroy_stream(struct snd_motu *motu, | ||
| 300 | enum amdtp_stream_direction dir) | ||
| 301 | { | ||
| 302 | struct amdtp_stream *stream; | ||
| 303 | struct fw_iso_resources *resources; | ||
| 304 | |||
| 305 | if (dir == AMDTP_IN_STREAM) { | ||
| 306 | stream = &motu->tx_stream; | ||
| 307 | resources = &motu->tx_resources; | ||
| 308 | } else { | ||
| 309 | stream = &motu->rx_stream; | ||
| 310 | resources = &motu->rx_resources; | ||
| 311 | } | ||
| 312 | |||
| 313 | amdtp_stream_destroy(stream); | ||
| 314 | fw_iso_resources_free(resources); | ||
| 315 | } | ||
| 316 | |||
| 317 | int snd_motu_stream_init_duplex(struct snd_motu *motu) | ||
| 318 | { | ||
| 319 | int err; | ||
| 320 | |||
| 321 | err = init_stream(motu, AMDTP_IN_STREAM); | ||
| 322 | if (err < 0) | ||
| 323 | return err; | ||
| 324 | |||
| 325 | err = init_stream(motu, AMDTP_OUT_STREAM); | ||
| 326 | if (err < 0) | ||
| 327 | destroy_stream(motu, AMDTP_IN_STREAM); | ||
| 328 | |||
| 329 | return err; | ||
| 330 | } | ||
| 331 | |||
| 332 | /* | ||
| 333 | * This function should be called before starting streams or after stopping | ||
| 334 | * streams. | ||
| 335 | */ | ||
| 336 | void snd_motu_stream_destroy_duplex(struct snd_motu *motu) | ||
| 337 | { | ||
| 338 | destroy_stream(motu, AMDTP_IN_STREAM); | ||
| 339 | destroy_stream(motu, AMDTP_OUT_STREAM); | ||
| 340 | |||
| 341 | motu->playback_substreams = 0; | ||
| 342 | motu->capture_substreams = 0; | ||
| 343 | } | ||
| 344 | |||
| 345 | static void motu_lock_changed(struct snd_motu *motu) | ||
| 346 | { | ||
| 347 | motu->dev_lock_changed = true; | ||
| 348 | wake_up(&motu->hwdep_wait); | ||
| 349 | } | ||
| 350 | |||
| 351 | int snd_motu_stream_lock_try(struct snd_motu *motu) | ||
| 352 | { | ||
| 353 | int err; | ||
| 354 | |||
| 355 | spin_lock_irq(&motu->lock); | ||
| 356 | |||
| 357 | if (motu->dev_lock_count < 0) { | ||
| 358 | err = -EBUSY; | ||
| 359 | goto out; | ||
| 360 | } | ||
| 361 | |||
| 362 | if (motu->dev_lock_count++ == 0) | ||
| 363 | motu_lock_changed(motu); | ||
| 364 | err = 0; | ||
| 365 | out: | ||
| 366 | spin_unlock_irq(&motu->lock); | ||
| 367 | return err; | ||
| 368 | } | ||
| 369 | |||
| 370 | void snd_motu_stream_lock_release(struct snd_motu *motu) | ||
| 371 | { | ||
| 372 | spin_lock_irq(&motu->lock); | ||
| 373 | |||
| 374 | if (WARN_ON(motu->dev_lock_count <= 0)) | ||
| 375 | goto out; | ||
| 376 | |||
| 377 | if (--motu->dev_lock_count == 0) | ||
| 378 | motu_lock_changed(motu); | ||
| 379 | out: | ||
| 380 | spin_unlock_irq(&motu->lock); | ||
| 381 | } | ||
diff --git a/sound/firewire/motu/motu-transaction.c b/sound/firewire/motu/motu-transaction.c new file mode 100644 index 000000000000..7fc30091e0de --- /dev/null +++ b/sound/firewire/motu/motu-transaction.c | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | /* | ||
| 2 | * motu-transaction.c - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | |||
| 10 | #include "motu.h" | ||
| 11 | |||
| 12 | #define SND_MOTU_ADDR_BASE 0xfffff0000000ULL | ||
| 13 | #define ASYNC_ADDR_HI 0x0b04 | ||
| 14 | #define ASYNC_ADDR_LO 0x0b08 | ||
| 15 | |||
| 16 | int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg, | ||
| 17 | size_t size) | ||
| 18 | { | ||
| 19 | int tcode; | ||
| 20 | |||
| 21 | if (size % sizeof(__be32) > 0 || size <= 0) | ||
| 22 | return -EINVAL; | ||
| 23 | if (size == sizeof(__be32)) | ||
| 24 | tcode = TCODE_READ_QUADLET_REQUEST; | ||
| 25 | else | ||
| 26 | tcode = TCODE_READ_BLOCK_REQUEST; | ||
| 27 | |||
| 28 | return snd_fw_transaction(motu->unit, tcode, | ||
| 29 | SND_MOTU_ADDR_BASE + offset, reg, size, 0); | ||
| 30 | } | ||
| 31 | |||
| 32 | int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg, | ||
| 33 | size_t size) | ||
| 34 | { | ||
| 35 | int tcode; | ||
| 36 | |||
| 37 | if (size % sizeof(__be32) > 0 || size <= 0) | ||
| 38 | return -EINVAL; | ||
| 39 | if (size == sizeof(__be32)) | ||
| 40 | tcode = TCODE_WRITE_QUADLET_REQUEST; | ||
| 41 | else | ||
| 42 | tcode = TCODE_WRITE_BLOCK_REQUEST; | ||
| 43 | |||
| 44 | return snd_fw_transaction(motu->unit, tcode, | ||
| 45 | SND_MOTU_ADDR_BASE + offset, reg, size, 0); | ||
| 46 | } | ||
| 47 | |||
| 48 | static void handle_message(struct fw_card *card, struct fw_request *request, | ||
| 49 | int tcode, int destination, int source, | ||
| 50 | int generation, unsigned long long offset, | ||
| 51 | void *data, size_t length, void *callback_data) | ||
| 52 | { | ||
| 53 | struct snd_motu *motu = callback_data; | ||
| 54 | __be32 *buf = (__be32 *)data; | ||
| 55 | unsigned long flags; | ||
| 56 | |||
| 57 | if (tcode != TCODE_WRITE_QUADLET_REQUEST) { | ||
| 58 | fw_send_response(card, request, RCODE_COMPLETE); | ||
| 59 | return; | ||
| 60 | } | ||
| 61 | |||
| 62 | if (offset != motu->async_handler.offset || length != 4) { | ||
| 63 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | |||
| 67 | spin_lock_irqsave(&motu->lock, flags); | ||
| 68 | motu->msg = be32_to_cpu(*buf); | ||
| 69 | spin_unlock_irqrestore(&motu->lock, flags); | ||
| 70 | |||
| 71 | fw_send_response(card, request, RCODE_COMPLETE); | ||
| 72 | |||
| 73 | wake_up(&motu->hwdep_wait); | ||
| 74 | } | ||
| 75 | |||
| 76 | int snd_motu_transaction_reregister(struct snd_motu *motu) | ||
| 77 | { | ||
| 78 | struct fw_device *device = fw_parent_device(motu->unit); | ||
| 79 | __be32 data; | ||
| 80 | int err; | ||
| 81 | |||
| 82 | if (motu->async_handler.callback_data == NULL) | ||
| 83 | return -EINVAL; | ||
| 84 | |||
| 85 | /* Register messaging address. Block transaction is not allowed. */ | ||
| 86 | data = cpu_to_be32((device->card->node_id << 16) | | ||
| 87 | (motu->async_handler.offset >> 32)); | ||
| 88 | err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, | ||
| 89 | sizeof(data)); | ||
| 90 | if (err < 0) | ||
| 91 | return err; | ||
| 92 | |||
| 93 | data = cpu_to_be32(motu->async_handler.offset); | ||
| 94 | return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, | ||
| 95 | sizeof(data)); | ||
| 96 | } | ||
| 97 | |||
| 98 | int snd_motu_transaction_register(struct snd_motu *motu) | ||
| 99 | { | ||
| 100 | static const struct fw_address_region resp_register_region = { | ||
| 101 | .start = 0xffffe0000000ull, | ||
| 102 | .end = 0xffffe000ffffull, | ||
| 103 | }; | ||
| 104 | int err; | ||
| 105 | |||
| 106 | /* Perhaps, 4 byte messages are transferred. */ | ||
| 107 | motu->async_handler.length = 4; | ||
| 108 | motu->async_handler.address_callback = handle_message; | ||
| 109 | motu->async_handler.callback_data = motu; | ||
| 110 | |||
| 111 | err = fw_core_add_address_handler(&motu->async_handler, | ||
| 112 | &resp_register_region); | ||
| 113 | if (err < 0) | ||
| 114 | return err; | ||
| 115 | |||
| 116 | err = snd_motu_transaction_reregister(motu); | ||
| 117 | if (err < 0) { | ||
| 118 | fw_core_remove_address_handler(&motu->async_handler); | ||
| 119 | motu->async_handler.address_callback = NULL; | ||
| 120 | } | ||
| 121 | |||
| 122 | return err; | ||
| 123 | } | ||
| 124 | |||
| 125 | void snd_motu_transaction_unregister(struct snd_motu *motu) | ||
| 126 | { | ||
| 127 | __be32 data; | ||
| 128 | |||
| 129 | if (motu->async_handler.address_callback != NULL) | ||
| 130 | fw_core_remove_address_handler(&motu->async_handler); | ||
| 131 | motu->async_handler.address_callback = NULL; | ||
| 132 | |||
| 133 | /* Unregister the address. */ | ||
| 134 | data = cpu_to_be32(0x00000000); | ||
| 135 | snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data)); | ||
| 136 | snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data)); | ||
| 137 | } | ||
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c new file mode 100644 index 000000000000..bf779cfeef0d --- /dev/null +++ b/sound/firewire/motu/motu.c | |||
| @@ -0,0 +1,264 @@ | |||
| 1 | /* | ||
| 2 | * motu.c - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "motu.h" | ||
| 10 | |||
| 11 | #define OUI_MOTU 0x0001f2 | ||
| 12 | |||
| 13 | MODULE_DESCRIPTION("MOTU FireWire driver"); | ||
| 14 | MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>"); | ||
| 15 | MODULE_LICENSE("GPL v2"); | ||
| 16 | |||
| 17 | const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT] = { | ||
| 18 | /* mode 0 */ | ||
| 19 | [0] = 44100, | ||
| 20 | [1] = 48000, | ||
| 21 | /* mode 1 */ | ||
| 22 | [2] = 88200, | ||
| 23 | [3] = 96000, | ||
| 24 | /* mode 2 */ | ||
| 25 | [4] = 176400, | ||
| 26 | [5] = 192000, | ||
| 27 | }; | ||
| 28 | |||
| 29 | static void name_card(struct snd_motu *motu) | ||
| 30 | { | ||
| 31 | struct fw_device *fw_dev = fw_parent_device(motu->unit); | ||
| 32 | struct fw_csr_iterator it; | ||
| 33 | int key, val; | ||
| 34 | u32 version = 0; | ||
| 35 | |||
| 36 | fw_csr_iterator_init(&it, motu->unit->directory); | ||
| 37 | while (fw_csr_iterator_next(&it, &key, &val)) { | ||
| 38 | switch (key) { | ||
| 39 | case CSR_VERSION: | ||
| 40 | version = val; | ||
| 41 | break; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | strcpy(motu->card->driver, "FW-MOTU"); | ||
| 46 | strcpy(motu->card->shortname, motu->spec->name); | ||
| 47 | strcpy(motu->card->mixername, motu->spec->name); | ||
| 48 | snprintf(motu->card->longname, sizeof(motu->card->longname), | ||
| 49 | "MOTU %s (version:%d), GUID %08x%08x at %s, S%d", | ||
| 50 | motu->spec->name, version, | ||
| 51 | fw_dev->config_rom[3], fw_dev->config_rom[4], | ||
| 52 | dev_name(&motu->unit->device), 100 << fw_dev->max_speed); | ||
| 53 | } | ||
| 54 | |||
| 55 | static void motu_free(struct snd_motu *motu) | ||
| 56 | { | ||
| 57 | snd_motu_transaction_unregister(motu); | ||
| 58 | |||
| 59 | snd_motu_stream_destroy_duplex(motu); | ||
| 60 | fw_unit_put(motu->unit); | ||
| 61 | |||
| 62 | mutex_destroy(&motu->mutex); | ||
| 63 | kfree(motu); | ||
| 64 | } | ||
| 65 | |||
| 66 | /* | ||
| 67 | * This module releases the FireWire unit data after all ALSA character devices | ||
| 68 | * are released by applications. This is for releasing stream data or finishing | ||
| 69 | * transactions safely. Thus at returning from .remove(), this module still keep | ||
| 70 | * references for the unit. | ||
| 71 | */ | ||
| 72 | static void motu_card_free(struct snd_card *card) | ||
| 73 | { | ||
| 74 | motu_free(card->private_data); | ||
| 75 | } | ||
| 76 | |||
| 77 | static void do_registration(struct work_struct *work) | ||
| 78 | { | ||
| 79 | struct snd_motu *motu = container_of(work, struct snd_motu, dwork.work); | ||
| 80 | int err; | ||
| 81 | |||
| 82 | if (motu->registered) | ||
| 83 | return; | ||
| 84 | |||
| 85 | err = snd_card_new(&motu->unit->device, -1, NULL, THIS_MODULE, 0, | ||
| 86 | &motu->card); | ||
| 87 | if (err < 0) | ||
| 88 | return; | ||
| 89 | |||
| 90 | name_card(motu); | ||
| 91 | |||
| 92 | err = snd_motu_transaction_register(motu); | ||
| 93 | if (err < 0) | ||
| 94 | goto error; | ||
| 95 | |||
| 96 | err = snd_motu_stream_init_duplex(motu); | ||
| 97 | if (err < 0) | ||
| 98 | goto error; | ||
| 99 | |||
| 100 | snd_motu_proc_init(motu); | ||
| 101 | |||
| 102 | err = snd_motu_create_pcm_devices(motu); | ||
| 103 | if (err < 0) | ||
| 104 | goto error; | ||
| 105 | |||
| 106 | if (motu->spec->flags & SND_MOTU_SPEC_HAS_MIDI) { | ||
| 107 | err = snd_motu_create_midi_devices(motu); | ||
| 108 | if (err < 0) | ||
| 109 | goto error; | ||
| 110 | } | ||
| 111 | |||
| 112 | err = snd_motu_create_hwdep_device(motu); | ||
| 113 | if (err < 0) | ||
| 114 | goto error; | ||
| 115 | |||
| 116 | err = snd_card_register(motu->card); | ||
| 117 | if (err < 0) | ||
| 118 | goto error; | ||
| 119 | |||
| 120 | /* | ||
| 121 | * After registered, motu instance can be released corresponding to | ||
| 122 | * releasing the sound card instance. | ||
| 123 | */ | ||
| 124 | motu->card->private_free = motu_card_free; | ||
| 125 | motu->card->private_data = motu; | ||
| 126 | motu->registered = true; | ||
| 127 | |||
| 128 | return; | ||
| 129 | error: | ||
| 130 | snd_motu_transaction_unregister(motu); | ||
| 131 | snd_card_free(motu->card); | ||
| 132 | dev_info(&motu->unit->device, | ||
| 133 | "Sound card registration failed: %d\n", err); | ||
| 134 | } | ||
| 135 | |||
| 136 | static int motu_probe(struct fw_unit *unit, | ||
| 137 | const struct ieee1394_device_id *entry) | ||
| 138 | { | ||
| 139 | struct snd_motu *motu; | ||
| 140 | |||
| 141 | /* Allocate this independently of sound card instance. */ | ||
| 142 | motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL); | ||
| 143 | if (motu == NULL) | ||
| 144 | return -ENOMEM; | ||
| 145 | |||
| 146 | motu->spec = (const struct snd_motu_spec *)entry->driver_data; | ||
| 147 | motu->unit = fw_unit_get(unit); | ||
| 148 | dev_set_drvdata(&unit->device, motu); | ||
| 149 | |||
| 150 | mutex_init(&motu->mutex); | ||
| 151 | spin_lock_init(&motu->lock); | ||
| 152 | init_waitqueue_head(&motu->hwdep_wait); | ||
| 153 | |||
| 154 | /* Allocate and register this sound card later. */ | ||
| 155 | INIT_DEFERRABLE_WORK(&motu->dwork, do_registration); | ||
| 156 | snd_fw_schedule_registration(unit, &motu->dwork); | ||
| 157 | |||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | static void motu_remove(struct fw_unit *unit) | ||
| 162 | { | ||
| 163 | struct snd_motu *motu = dev_get_drvdata(&unit->device); | ||
| 164 | |||
| 165 | /* | ||
| 166 | * Confirm to stop the work for registration before the sound card is | ||
| 167 | * going to be released. The work is not scheduled again because bus | ||
| 168 | * reset handler is not called anymore. | ||
| 169 | */ | ||
| 170 | cancel_delayed_work_sync(&motu->dwork); | ||
| 171 | |||
| 172 | if (motu->registered) { | ||
| 173 | /* No need to wait for releasing card object in this context. */ | ||
| 174 | snd_card_free_when_closed(motu->card); | ||
| 175 | } else { | ||
| 176 | /* Don't forget this case. */ | ||
| 177 | motu_free(motu); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | static void motu_bus_update(struct fw_unit *unit) | ||
| 182 | { | ||
| 183 | struct snd_motu *motu = dev_get_drvdata(&unit->device); | ||
| 184 | |||
| 185 | /* Postpone a workqueue for deferred registration. */ | ||
| 186 | if (!motu->registered) | ||
| 187 | snd_fw_schedule_registration(unit, &motu->dwork); | ||
| 188 | |||
| 189 | /* The handler address register becomes initialized. */ | ||
| 190 | snd_motu_transaction_reregister(motu); | ||
| 191 | } | ||
| 192 | |||
| 193 | static struct snd_motu_spec motu_828mk2 = { | ||
| 194 | .name = "828mk2", | ||
| 195 | .protocol = &snd_motu_protocol_v2, | ||
| 196 | .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | | ||
| 197 | SND_MOTU_SPEC_TX_MICINST_CHUNK | | ||
| 198 | SND_MOTU_SPEC_TX_RETURN_CHUNK | | ||
| 199 | SND_MOTU_SPEC_HAS_OPT_IFACE_A | | ||
| 200 | SND_MOTU_SPEC_HAS_MIDI, | ||
| 201 | |||
| 202 | .analog_in_ports = 8, | ||
| 203 | .analog_out_ports = 8, | ||
| 204 | }; | ||
| 205 | |||
| 206 | static struct snd_motu_spec motu_828mk3 = { | ||
| 207 | .name = "828mk3", | ||
| 208 | .protocol = &snd_motu_protocol_v3, | ||
| 209 | .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | | ||
| 210 | SND_MOTU_SPEC_SUPPORT_CLOCK_X4 | | ||
| 211 | SND_MOTU_SPEC_TX_MICINST_CHUNK | | ||
| 212 | SND_MOTU_SPEC_TX_RETURN_CHUNK | | ||
| 213 | SND_MOTU_SPEC_TX_REVERB_CHUNK | | ||
| 214 | SND_MOTU_SPEC_HAS_OPT_IFACE_A | | ||
| 215 | SND_MOTU_SPEC_HAS_OPT_IFACE_B | | ||
| 216 | SND_MOTU_SPEC_HAS_MIDI, | ||
| 217 | |||
| 218 | .analog_in_ports = 8, | ||
| 219 | .analog_out_ports = 8, | ||
| 220 | }; | ||
| 221 | |||
| 222 | #define SND_MOTU_DEV_ENTRY(model, data) \ | ||
| 223 | { \ | ||
| 224 | .match_flags = IEEE1394_MATCH_VENDOR_ID | \ | ||
| 225 | IEEE1394_MATCH_MODEL_ID | \ | ||
| 226 | IEEE1394_MATCH_SPECIFIER_ID, \ | ||
| 227 | .vendor_id = OUI_MOTU, \ | ||
| 228 | .model_id = model, \ | ||
| 229 | .specifier_id = OUI_MOTU, \ | ||
| 230 | .driver_data = (kernel_ulong_t)data, \ | ||
| 231 | } | ||
| 232 | |||
| 233 | static const struct ieee1394_device_id motu_id_table[] = { | ||
| 234 | SND_MOTU_DEV_ENTRY(0x101800, &motu_828mk2), | ||
| 235 | SND_MOTU_DEV_ENTRY(0x106800, &motu_828mk3), /* FireWire only. */ | ||
| 236 | SND_MOTU_DEV_ENTRY(0x100800, &motu_828mk3), /* Hybrid. */ | ||
| 237 | { } | ||
| 238 | }; | ||
| 239 | MODULE_DEVICE_TABLE(ieee1394, motu_id_table); | ||
| 240 | |||
| 241 | static struct fw_driver motu_driver = { | ||
| 242 | .driver = { | ||
| 243 | .owner = THIS_MODULE, | ||
| 244 | .name = KBUILD_MODNAME, | ||
| 245 | .bus = &fw_bus_type, | ||
| 246 | }, | ||
| 247 | .probe = motu_probe, | ||
| 248 | .update = motu_bus_update, | ||
| 249 | .remove = motu_remove, | ||
| 250 | .id_table = motu_id_table, | ||
| 251 | }; | ||
| 252 | |||
| 253 | static int __init alsa_motu_init(void) | ||
| 254 | { | ||
| 255 | return driver_register(&motu_driver.driver); | ||
| 256 | } | ||
| 257 | |||
| 258 | static void __exit alsa_motu_exit(void) | ||
| 259 | { | ||
| 260 | driver_unregister(&motu_driver.driver); | ||
| 261 | } | ||
| 262 | |||
| 263 | module_init(alsa_motu_init); | ||
| 264 | module_exit(alsa_motu_exit); | ||
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h new file mode 100644 index 000000000000..8d6a4a3af9cc --- /dev/null +++ b/sound/firewire/motu/motu.h | |||
| @@ -0,0 +1,161 @@ | |||
| 1 | /* | ||
| 2 | * motu.h - a part of driver for MOTU FireWire series | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
| 5 | * | ||
| 6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef SOUND_FIREWIRE_MOTU_H_INCLUDED | ||
| 10 | #define SOUND_FIREWIRE_MOTU_H_INCLUDED | ||
| 11 | |||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/firewire.h> | ||
| 14 | #include <linux/firewire-constants.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/mod_devicetable.h> | ||
| 17 | #include <linux/mutex.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/compat.h> | ||
| 20 | #include <linux/sched/signal.h> | ||
| 21 | |||
| 22 | #include <sound/control.h> | ||
| 23 | #include <sound/core.h> | ||
| 24 | #include <sound/pcm.h> | ||
| 25 | #include <sound/info.h> | ||
| 26 | #include <sound/rawmidi.h> | ||
| 27 | #include <sound/firewire.h> | ||
| 28 | #include <sound/hwdep.h> | ||
| 29 | |||
| 30 | #include "../lib.h" | ||
| 31 | #include "../amdtp-stream.h" | ||
| 32 | #include "../iso-resources.h" | ||
| 33 | |||
| 34 | struct snd_motu_packet_format { | ||
| 35 | unsigned char midi_flag_offset; | ||
| 36 | unsigned char midi_byte_offset; | ||
| 37 | unsigned char pcm_byte_offset; | ||
| 38 | |||
| 39 | unsigned char msg_chunks; | ||
| 40 | unsigned char fixed_part_pcm_chunks[3]; | ||
| 41 | unsigned char differed_part_pcm_chunks[3]; | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct snd_motu { | ||
| 45 | struct snd_card *card; | ||
| 46 | struct fw_unit *unit; | ||
| 47 | struct mutex mutex; | ||
| 48 | spinlock_t lock; | ||
| 49 | |||
| 50 | bool registered; | ||
| 51 | struct delayed_work dwork; | ||
| 52 | |||
| 53 | /* Model dependent information. */ | ||
| 54 | const struct snd_motu_spec *spec; | ||
| 55 | |||
| 56 | /* For packet streaming */ | ||
| 57 | struct snd_motu_packet_format tx_packet_formats; | ||
| 58 | struct snd_motu_packet_format rx_packet_formats; | ||
| 59 | struct amdtp_stream tx_stream; | ||
| 60 | struct amdtp_stream rx_stream; | ||
| 61 | struct fw_iso_resources tx_resources; | ||
| 62 | struct fw_iso_resources rx_resources; | ||
| 63 | unsigned int capture_substreams; | ||
| 64 | unsigned int playback_substreams; | ||
| 65 | |||
| 66 | /* For notification. */ | ||
| 67 | struct fw_address_handler async_handler; | ||
| 68 | u32 msg; | ||
| 69 | |||
| 70 | /* For uapi */ | ||
| 71 | int dev_lock_count; | ||
| 72 | bool dev_lock_changed; | ||
| 73 | wait_queue_head_t hwdep_wait; | ||
| 74 | }; | ||
| 75 | |||
| 76 | enum snd_motu_spec_flags { | ||
| 77 | SND_MOTU_SPEC_SUPPORT_CLOCK_X2 = 0x0001, | ||
| 78 | SND_MOTU_SPEC_SUPPORT_CLOCK_X4 = 0x0002, | ||
| 79 | SND_MOTU_SPEC_TX_MICINST_CHUNK = 0x0004, | ||
| 80 | SND_MOTU_SPEC_TX_RETURN_CHUNK = 0x0008, | ||
| 81 | SND_MOTU_SPEC_TX_REVERB_CHUNK = 0x0010, | ||
| 82 | SND_MOTU_SPEC_TX_AESEBU_CHUNK = 0x0020, | ||
| 83 | SND_MOTU_SPEC_HAS_OPT_IFACE_A = 0x0040, | ||
| 84 | SND_MOTU_SPEC_HAS_OPT_IFACE_B = 0x0080, | ||
| 85 | SND_MOTU_SPEC_HAS_MIDI = 0x0100, | ||
| 86 | }; | ||
| 87 | |||
| 88 | #define SND_MOTU_CLOCK_RATE_COUNT 6 | ||
| 89 | extern const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT]; | ||
| 90 | |||
| 91 | enum snd_motu_clock_source { | ||
| 92 | SND_MOTU_CLOCK_SOURCE_INTERNAL, | ||
| 93 | SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB, | ||
| 94 | SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT, | ||
| 95 | SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A, | ||
| 96 | SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B, | ||
| 97 | SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT, | ||
| 98 | SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A, | ||
| 99 | SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B, | ||
| 100 | SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX, | ||
| 101 | SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR, | ||
| 102 | SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC, | ||
| 103 | SND_MOTU_CLOCK_SOURCE_UNKNOWN, | ||
| 104 | }; | ||
| 105 | |||
| 106 | struct snd_motu_protocol { | ||
| 107 | int (*get_clock_rate)(struct snd_motu *motu, unsigned int *rate); | ||
| 108 | int (*set_clock_rate)(struct snd_motu *motu, unsigned int rate); | ||
| 109 | int (*get_clock_source)(struct snd_motu *motu, | ||
| 110 | enum snd_motu_clock_source *source); | ||
| 111 | int (*switch_fetching_mode)(struct snd_motu *motu, bool enable); | ||
| 112 | int (*cache_packet_formats)(struct snd_motu *motu); | ||
| 113 | }; | ||
| 114 | |||
| 115 | struct snd_motu_spec { | ||
| 116 | const char *const name; | ||
| 117 | enum snd_motu_spec_flags flags; | ||
| 118 | |||
| 119 | unsigned char analog_in_ports; | ||
| 120 | unsigned char analog_out_ports; | ||
| 121 | |||
| 122 | const struct snd_motu_protocol *const protocol; | ||
| 123 | }; | ||
| 124 | |||
| 125 | extern const struct snd_motu_protocol snd_motu_protocol_v2; | ||
| 126 | extern const struct snd_motu_protocol snd_motu_protocol_v3; | ||
| 127 | |||
| 128 | int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, | ||
| 129 | enum amdtp_stream_direction dir, | ||
| 130 | const struct snd_motu_protocol *const protocol); | ||
| 131 | int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, | ||
| 132 | unsigned int midi_ports, | ||
| 133 | struct snd_motu_packet_format *formats); | ||
| 134 | int amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s, | ||
| 135 | struct snd_pcm_runtime *runtime); | ||
| 136 | void amdtp_motu_midi_trigger(struct amdtp_stream *s, unsigned int port, | ||
| 137 | struct snd_rawmidi_substream *midi); | ||
| 138 | |||
| 139 | int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg, | ||
| 140 | size_t size); | ||
| 141 | int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg, | ||
| 142 | size_t size); | ||
| 143 | int snd_motu_transaction_register(struct snd_motu *motu); | ||
| 144 | int snd_motu_transaction_reregister(struct snd_motu *motu); | ||
| 145 | void snd_motu_transaction_unregister(struct snd_motu *motu); | ||
| 146 | |||
| 147 | int snd_motu_stream_init_duplex(struct snd_motu *motu); | ||
| 148 | void snd_motu_stream_destroy_duplex(struct snd_motu *motu); | ||
| 149 | int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate); | ||
| 150 | void snd_motu_stream_stop_duplex(struct snd_motu *motu); | ||
| 151 | int snd_motu_stream_lock_try(struct snd_motu *motu); | ||
| 152 | void snd_motu_stream_lock_release(struct snd_motu *motu); | ||
| 153 | |||
| 154 | void snd_motu_proc_init(struct snd_motu *motu); | ||
| 155 | |||
| 156 | int snd_motu_create_pcm_devices(struct snd_motu *motu); | ||
| 157 | |||
| 158 | int snd_motu_create_midi_devices(struct snd_motu *motu); | ||
| 159 | |||
| 160 | int snd_motu_create_hwdep_device(struct snd_motu *motu); | ||
| 161 | #endif | ||
diff --git a/sound/firewire/oxfw/oxfw-command.c b/sound/firewire/oxfw/oxfw-command.c index 12ef3253bc89..ac3e2e301666 100644 --- a/sound/firewire/oxfw/oxfw-command.c +++ b/sound/firewire/oxfw/oxfw-command.c | |||
| @@ -34,7 +34,9 @@ int avc_stream_set_format(struct fw_unit *unit, enum avc_general_plug_dir dir, | |||
| 34 | err = fcp_avc_transaction(unit, buf, len + 10, buf, len + 10, | 34 | err = fcp_avc_transaction(unit, buf, len + 10, buf, len + 10, |
| 35 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | 35 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | |
| 36 | BIT(6) | BIT(7) | BIT(8)); | 36 | BIT(6) | BIT(7) | BIT(8)); |
| 37 | if ((err > 0) && (err < len + 10)) | 37 | if (err < 0) |
| 38 | ; | ||
| 39 | else if (err < len + 10) | ||
| 38 | err = -EIO; | 40 | err = -EIO; |
| 39 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 41 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 40 | err = -ENOSYS; | 42 | err = -ENOSYS; |
| @@ -77,7 +79,9 @@ int avc_stream_get_format(struct fw_unit *unit, | |||
| 77 | err = fcp_avc_transaction(unit, buf, 12, buf, *len, | 79 | err = fcp_avc_transaction(unit, buf, 12, buf, *len, |
| 78 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | 80 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | |
| 79 | BIT(6) | BIT(7)); | 81 | BIT(6) | BIT(7)); |
| 80 | if ((err > 0) && (err < 10)) | 82 | if (err < 0) |
| 83 | ; | ||
| 84 | else if (err < 12) | ||
| 81 | err = -EIO; | 85 | err = -EIO; |
| 82 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 86 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 83 | err = -ENOSYS; | 87 | err = -ENOSYS; |
| @@ -139,7 +143,9 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate, | |||
| 139 | /* do transaction and check buf[1-5] are the same against command */ | 143 | /* do transaction and check buf[1-5] are the same against command */ |
| 140 | err = fcp_avc_transaction(unit, buf, 8, buf, 8, | 144 | err = fcp_avc_transaction(unit, buf, 8, buf, 8, |
| 141 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)); | 145 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)); |
| 142 | if ((err > 0) && (err < 8)) | 146 | if (err < 0) |
| 147 | ; | ||
| 148 | else if (err < 8) | ||
| 143 | err = -EIO; | 149 | err = -EIO; |
| 144 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | 150 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ |
| 145 | err = -ENOSYS; | 151 | err = -ENOSYS; |
diff --git a/sound/firewire/tascam/tascam-midi.c b/sound/firewire/tascam/tascam-midi.c index df4f95d65925..4a741570d536 100644 --- a/sound/firewire/tascam/tascam-midi.c +++ b/sound/firewire/tascam/tascam-midi.c | |||
| @@ -18,9 +18,8 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) | |||
| 18 | { | 18 | { |
| 19 | struct snd_tscm *tscm = substream->rmidi->private_data; | 19 | struct snd_tscm *tscm = substream->rmidi->private_data; |
| 20 | 20 | ||
| 21 | /* Initialize internal status. */ | 21 | snd_fw_async_midi_port_init(&tscm->out_ports[substream->number]); |
| 22 | tscm->running_status[substream->number] = 0; | 22 | |
| 23 | tscm->on_sysex[substream->number] = 0; | ||
| 24 | return 0; | 23 | return 0; |
| 25 | } | 24 | } |
| 26 | 25 | ||
| @@ -32,11 +31,14 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream) | |||
| 32 | 31 | ||
| 33 | static int midi_playback_close(struct snd_rawmidi_substream *substream) | 32 | static int midi_playback_close(struct snd_rawmidi_substream *substream) |
| 34 | { | 33 | { |
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | static void midi_playback_drain(struct snd_rawmidi_substream *substream) | ||
| 38 | { | ||
| 35 | struct snd_tscm *tscm = substream->rmidi->private_data; | 39 | struct snd_tscm *tscm = substream->rmidi->private_data; |
| 36 | 40 | ||
| 37 | snd_fw_async_midi_port_finish(&tscm->out_ports[substream->number]); | 41 | snd_fw_async_midi_port_finish(&tscm->out_ports[substream->number]); |
| 38 | |||
| 39 | return 0; | ||
| 40 | } | 42 | } |
| 41 | 43 | ||
| 42 | static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) | 44 | static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) |
| @@ -78,6 +80,7 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm) | |||
| 78 | static const struct snd_rawmidi_ops playback_ops = { | 80 | static const struct snd_rawmidi_ops playback_ops = { |
| 79 | .open = midi_playback_open, | 81 | .open = midi_playback_open, |
| 80 | .close = midi_playback_close, | 82 | .close = midi_playback_close, |
| 83 | .drain = midi_playback_drain, | ||
| 81 | .trigger = midi_playback_trigger, | 84 | .trigger = midi_playback_trigger, |
| 82 | }; | 85 | }; |
| 83 | struct snd_rawmidi *rmidi; | 86 | struct snd_rawmidi *rmidi; |
diff --git a/sound/firewire/tascam/tascam-transaction.c b/sound/firewire/tascam/tascam-transaction.c index 040a96d1ba8e..8967c52f5032 100644 --- a/sound/firewire/tascam/tascam-transaction.c +++ b/sound/firewire/tascam/tascam-transaction.c | |||
| @@ -58,39 +58,38 @@ static inline int calculate_message_bytes(u8 status) | |||
| 58 | return -EINVAL; | 58 | return -EINVAL; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | static int fill_message(struct snd_rawmidi_substream *substream, u8 *buf) | 61 | static int fill_message(struct snd_fw_async_midi_port *port, |
| 62 | struct snd_rawmidi_substream *substream) | ||
| 62 | { | 63 | { |
| 63 | struct snd_tscm *tscm = substream->rmidi->private_data; | ||
| 64 | unsigned int port = substream->number; | ||
| 65 | int i, len, consume; | 64 | int i, len, consume; |
| 66 | u8 *label, *msg; | 65 | u8 *label, *msg; |
| 67 | u8 status; | 66 | u8 status; |
| 68 | 67 | ||
| 69 | /* The first byte is used for label, the rest for MIDI bytes. */ | 68 | /* The first byte is used for label, the rest for MIDI bytes. */ |
| 70 | label = buf; | 69 | label = port->buf; |
| 71 | msg = buf + 1; | 70 | msg = port->buf + 1; |
| 72 | 71 | ||
| 73 | consume = snd_rawmidi_transmit_peek(substream, msg, 3); | 72 | consume = snd_rawmidi_transmit_peek(substream, msg, 3); |
| 74 | if (consume == 0) | 73 | if (consume == 0) |
| 75 | return 0; | 74 | return 0; |
| 76 | 75 | ||
| 77 | /* On exclusive message. */ | 76 | /* On exclusive message. */ |
| 78 | if (tscm->on_sysex[port]) { | 77 | if (port->on_sysex) { |
| 79 | /* Seek the end of exclusives. */ | 78 | /* Seek the end of exclusives. */ |
| 80 | for (i = 0; i < consume; ++i) { | 79 | for (i = 0; i < consume; ++i) { |
| 81 | if (msg[i] == 0xf7) { | 80 | if (msg[i] == 0xf7) { |
| 82 | tscm->on_sysex[port] = false; | 81 | port->on_sysex = false; |
| 83 | break; | 82 | break; |
| 84 | } | 83 | } |
| 85 | } | 84 | } |
| 86 | 85 | ||
| 87 | /* At the end of exclusive message, use label 0x07. */ | 86 | /* At the end of exclusive message, use label 0x07. */ |
| 88 | if (!tscm->on_sysex[port]) { | 87 | if (!port->on_sysex) { |
| 89 | consume = i + 1; | 88 | consume = i + 1; |
| 90 | *label = (port << 4) | 0x07; | 89 | *label = (substream->number << 4) | 0x07; |
| 91 | /* During exclusive message, use label 0x04. */ | 90 | /* During exclusive message, use label 0x04. */ |
| 92 | } else if (consume == 3) { | 91 | } else if (consume == 3) { |
| 93 | *label = (port << 4) | 0x04; | 92 | *label = (substream->number << 4) | 0x04; |
| 94 | /* We need to fill whole 3 bytes. Go to next change. */ | 93 | /* We need to fill whole 3 bytes. Go to next change. */ |
| 95 | } else { | 94 | } else { |
| 96 | return 0; | 95 | return 0; |
| @@ -101,12 +100,12 @@ static int fill_message(struct snd_rawmidi_substream *substream, u8 *buf) | |||
| 101 | /* The beginning of exclusives. */ | 100 | /* The beginning of exclusives. */ |
| 102 | if (msg[0] == 0xf0) { | 101 | if (msg[0] == 0xf0) { |
| 103 | /* Transfer it in next chance in another condition. */ | 102 | /* Transfer it in next chance in another condition. */ |
| 104 | tscm->on_sysex[port] = true; | 103 | port->on_sysex = true; |
| 105 | return 0; | 104 | return 0; |
| 106 | } else { | 105 | } else { |
| 107 | /* On running-status. */ | 106 | /* On running-status. */ |
| 108 | if ((msg[0] & 0x80) != 0x80) | 107 | if ((msg[0] & 0x80) != 0x80) |
| 109 | status = tscm->running_status[port]; | 108 | status = port->running_status; |
| 110 | else | 109 | else |
| 111 | status = msg[0]; | 110 | status = msg[0]; |
| 112 | 111 | ||
| @@ -124,18 +123,18 @@ static int fill_message(struct snd_rawmidi_substream *substream, u8 *buf) | |||
| 124 | 123 | ||
| 125 | msg[2] = msg[1]; | 124 | msg[2] = msg[1]; |
| 126 | msg[1] = msg[0]; | 125 | msg[1] = msg[0]; |
| 127 | msg[0] = tscm->running_status[port]; | 126 | msg[0] = port->running_status; |
| 128 | } else { | 127 | } else { |
| 129 | /* Enough MIDI bytes were not retrieved. */ | 128 | /* Enough MIDI bytes were not retrieved. */ |
| 130 | if (consume < len) | 129 | if (consume < len) |
| 131 | return 0; | 130 | return 0; |
| 132 | consume = len; | 131 | consume = len; |
| 133 | 132 | ||
| 134 | tscm->running_status[port] = msg[0]; | 133 | port->running_status = msg[0]; |
| 135 | } | 134 | } |
| 136 | } | 135 | } |
| 137 | 136 | ||
| 138 | *label = (port << 4) | (msg[0] >> 4); | 137 | *label = (substream->number << 4) | (msg[0] >> 4); |
| 139 | } | 138 | } |
| 140 | 139 | ||
| 141 | if (len > 0 && len < 3) | 140 | if (len > 0 && len < 3) |
| @@ -144,6 +143,106 @@ static int fill_message(struct snd_rawmidi_substream *substream, u8 *buf) | |||
| 144 | return consume; | 143 | return consume; |
| 145 | } | 144 | } |
| 146 | 145 | ||
| 146 | static void async_midi_port_callback(struct fw_card *card, int rcode, | ||
| 147 | void *data, size_t length, | ||
| 148 | void *callback_data) | ||
| 149 | { | ||
| 150 | struct snd_fw_async_midi_port *port = callback_data; | ||
| 151 | struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream); | ||
| 152 | |||
| 153 | /* This port is closed. */ | ||
| 154 | if (substream == NULL) | ||
| 155 | return; | ||
| 156 | |||
| 157 | if (rcode == RCODE_COMPLETE) | ||
| 158 | snd_rawmidi_transmit_ack(substream, port->consume_bytes); | ||
| 159 | else if (!rcode_is_permanent_error(rcode)) | ||
| 160 | /* To start next transaction immediately for recovery. */ | ||
| 161 | port->next_ktime = 0; | ||
| 162 | else | ||
| 163 | /* Don't continue processing. */ | ||
| 164 | port->error = true; | ||
| 165 | |||
| 166 | port->idling = true; | ||
| 167 | |||
| 168 | if (!snd_rawmidi_transmit_empty(substream)) | ||
| 169 | schedule_work(&port->work); | ||
| 170 | } | ||
| 171 | |||
| 172 | static void midi_port_work(struct work_struct *work) | ||
| 173 | { | ||
| 174 | struct snd_fw_async_midi_port *port = | ||
| 175 | container_of(work, struct snd_fw_async_midi_port, work); | ||
| 176 | struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream); | ||
| 177 | int generation; | ||
| 178 | |||
| 179 | /* Under transacting or error state. */ | ||
| 180 | if (!port->idling || port->error) | ||
| 181 | return; | ||
| 182 | |||
| 183 | /* Nothing to do. */ | ||
| 184 | if (substream == NULL || snd_rawmidi_transmit_empty(substream)) | ||
| 185 | return; | ||
| 186 | |||
| 187 | /* Do it in next chance. */ | ||
| 188 | if (ktime_after(port->next_ktime, ktime_get())) { | ||
| 189 | schedule_work(&port->work); | ||
| 190 | return; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* | ||
| 194 | * Fill the buffer. The callee must use snd_rawmidi_transmit_peek(). | ||
| 195 | * Later, snd_rawmidi_transmit_ack() is called. | ||
| 196 | */ | ||
| 197 | memset(port->buf, 0, 4); | ||
| 198 | port->consume_bytes = fill_message(port, substream); | ||
| 199 | if (port->consume_bytes <= 0) { | ||
| 200 | /* Do it in next chance, immediately. */ | ||
| 201 | if (port->consume_bytes == 0) { | ||
| 202 | port->next_ktime = 0; | ||
| 203 | schedule_work(&port->work); | ||
| 204 | } else { | ||
| 205 | /* Fatal error. */ | ||
| 206 | port->error = true; | ||
| 207 | } | ||
| 208 | return; | ||
| 209 | } | ||
| 210 | |||
| 211 | /* Set interval to next transaction. */ | ||
| 212 | port->next_ktime = ktime_add_ns(ktime_get(), | ||
| 213 | port->consume_bytes * 8 * NSEC_PER_SEC / 31250); | ||
| 214 | |||
| 215 | /* Start this transaction. */ | ||
| 216 | port->idling = false; | ||
| 217 | |||
| 218 | /* | ||
| 219 | * In Linux FireWire core, when generation is updated with memory | ||
| 220 | * barrier, node id has already been updated. In this module, After | ||
| 221 | * this smp_rmb(), load/store instructions to memory are completed. | ||
| 222 | * Thus, both of generation and node id are available with recent | ||
| 223 | * values. This is a light-serialization solution to handle bus reset | ||
| 224 | * events on IEEE 1394 bus. | ||
| 225 | */ | ||
| 226 | generation = port->parent->generation; | ||
| 227 | smp_rmb(); | ||
| 228 | |||
| 229 | fw_send_request(port->parent->card, &port->transaction, | ||
| 230 | TCODE_WRITE_QUADLET_REQUEST, | ||
| 231 | port->parent->node_id, generation, | ||
| 232 | port->parent->max_speed, | ||
| 233 | TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_RX_QUAD, | ||
| 234 | port->buf, 4, async_midi_port_callback, | ||
| 235 | port); | ||
| 236 | } | ||
| 237 | |||
| 238 | void snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port) | ||
| 239 | { | ||
| 240 | port->idling = true; | ||
| 241 | port->error = false; | ||
| 242 | port->running_status = 0; | ||
| 243 | port->on_sysex = false; | ||
| 244 | } | ||
| 245 | |||
| 147 | static void handle_midi_tx(struct fw_card *card, struct fw_request *request, | 246 | static void handle_midi_tx(struct fw_card *card, struct fw_request *request, |
| 148 | int tcode, int destination, int source, | 247 | int tcode, int destination, int source, |
| 149 | int generation, unsigned long long offset, | 248 | int generation, unsigned long long offset, |
| @@ -219,12 +318,9 @@ int snd_tscm_transaction_register(struct snd_tscm *tscm) | |||
| 219 | goto error; | 318 | goto error; |
| 220 | 319 | ||
| 221 | for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++) { | 320 | for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++) { |
| 222 | err = snd_fw_async_midi_port_init( | 321 | tscm->out_ports[i].parent = fw_parent_device(tscm->unit); |
| 223 | &tscm->out_ports[i], tscm->unit, | 322 | tscm->out_ports[i].next_ktime = 0; |
| 224 | TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_RX_QUAD, | 323 | INIT_WORK(&tscm->out_ports[i].work, midi_port_work); |
| 225 | 4, fill_message); | ||
| 226 | if (err < 0) | ||
| 227 | goto error; | ||
| 228 | } | 324 | } |
| 229 | 325 | ||
| 230 | return err; | 326 | return err; |
| @@ -275,7 +371,6 @@ int snd_tscm_transaction_reregister(struct snd_tscm *tscm) | |||
| 275 | void snd_tscm_transaction_unregister(struct snd_tscm *tscm) | 371 | void snd_tscm_transaction_unregister(struct snd_tscm *tscm) |
| 276 | { | 372 | { |
| 277 | __be32 reg; | 373 | __be32 reg; |
| 278 | unsigned int i; | ||
| 279 | 374 | ||
| 280 | if (tscm->async_handler.callback_data == NULL) | 375 | if (tscm->async_handler.callback_data == NULL) |
| 281 | return; | 376 | return; |
| @@ -302,7 +397,4 @@ void snd_tscm_transaction_unregister(struct snd_tscm *tscm) | |||
| 302 | 397 | ||
| 303 | fw_core_remove_address_handler(&tscm->async_handler); | 398 | fw_core_remove_address_handler(&tscm->async_handler); |
| 304 | tscm->async_handler.callback_data = NULL; | 399 | tscm->async_handler.callback_data = NULL; |
| 305 | |||
| 306 | for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++) | ||
| 307 | snd_fw_async_midi_port_destroy(&tscm->out_ports[i]); | ||
| 308 | } | 400 | } |
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index d3cd4065722b..08ecfae5c584 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h | |||
| @@ -45,6 +45,23 @@ struct snd_tscm_spec { | |||
| 45 | #define TSCM_MIDI_IN_PORT_MAX 4 | 45 | #define TSCM_MIDI_IN_PORT_MAX 4 |
| 46 | #define TSCM_MIDI_OUT_PORT_MAX 4 | 46 | #define TSCM_MIDI_OUT_PORT_MAX 4 |
| 47 | 47 | ||
| 48 | struct snd_fw_async_midi_port { | ||
| 49 | struct fw_device *parent; | ||
| 50 | struct work_struct work; | ||
| 51 | bool idling; | ||
| 52 | ktime_t next_ktime; | ||
| 53 | bool error; | ||
| 54 | |||
| 55 | struct fw_transaction transaction; | ||
| 56 | |||
| 57 | u8 buf[4]; | ||
| 58 | u8 running_status; | ||
| 59 | bool on_sysex; | ||
| 60 | |||
| 61 | struct snd_rawmidi_substream *substream; | ||
| 62 | int consume_bytes; | ||
| 63 | }; | ||
| 64 | |||
| 48 | struct snd_tscm { | 65 | struct snd_tscm { |
| 49 | struct snd_card *card; | 66 | struct snd_card *card; |
| 50 | struct fw_unit *unit; | 67 | struct fw_unit *unit; |
| @@ -72,8 +89,6 @@ struct snd_tscm { | |||
| 72 | 89 | ||
| 73 | /* For MIDI message outgoing transactions. */ | 90 | /* For MIDI message outgoing transactions. */ |
| 74 | struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX]; | 91 | struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX]; |
| 75 | u8 running_status[TSCM_MIDI_OUT_PORT_MAX]; | ||
| 76 | bool on_sysex[TSCM_MIDI_OUT_PORT_MAX]; | ||
| 77 | }; | 92 | }; |
| 78 | 93 | ||
| 79 | #define TSCM_ADDR_BASE 0xffff00000000ull | 94 | #define TSCM_ADDR_BASE 0xffff00000000ull |
| @@ -131,6 +146,26 @@ void snd_tscm_stream_lock_changed(struct snd_tscm *tscm); | |||
| 131 | int snd_tscm_stream_lock_try(struct snd_tscm *tscm); | 146 | int snd_tscm_stream_lock_try(struct snd_tscm *tscm); |
| 132 | void snd_tscm_stream_lock_release(struct snd_tscm *tscm); | 147 | void snd_tscm_stream_lock_release(struct snd_tscm *tscm); |
| 133 | 148 | ||
| 149 | void snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port); | ||
| 150 | |||
| 151 | static inline void | ||
| 152 | snd_fw_async_midi_port_run(struct snd_fw_async_midi_port *port, | ||
| 153 | struct snd_rawmidi_substream *substream) | ||
| 154 | { | ||
| 155 | if (!port->error) { | ||
| 156 | port->substream = substream; | ||
| 157 | schedule_work(&port->work); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | static inline void | ||
| 162 | snd_fw_async_midi_port_finish(struct snd_fw_async_midi_port *port) | ||
| 163 | { | ||
| 164 | port->substream = NULL; | ||
| 165 | cancel_work_sync(&port->work); | ||
| 166 | port->error = false; | ||
| 167 | } | ||
| 168 | |||
| 134 | int snd_tscm_transaction_register(struct snd_tscm *tscm); | 169 | int snd_tscm_transaction_register(struct snd_tscm *tscm); |
| 135 | int snd_tscm_transaction_reregister(struct snd_tscm *tscm); | 170 | int snd_tscm_transaction_reregister(struct snd_tscm *tscm); |
| 136 | void snd_tscm_transaction_unregister(struct snd_tscm *tscm); | 171 | void snd_tscm_transaction_unregister(struct snd_tscm *tscm); |
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 261469188566..84f3b8168716 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c | |||
| @@ -171,7 +171,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) | |||
| 171 | { | 171 | { |
| 172 | int timeout; | 172 | int timeout; |
| 173 | u32 val; | 173 | u32 val; |
| 174 | int mask = (1 << AZX_MLCTL_CPA); | 174 | int mask = (1 << AZX_MLCTL_CPA_SHIFT); |
| 175 | 175 | ||
| 176 | udelay(3); | 176 | udelay(3); |
| 177 | timeout = 150; | 177 | timeout = 150; |
| @@ -179,10 +179,10 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) | |||
| 179 | do { | 179 | do { |
| 180 | val = readl(link->ml_addr + AZX_REG_ML_LCTL); | 180 | val = readl(link->ml_addr + AZX_REG_ML_LCTL); |
| 181 | if (enable) { | 181 | if (enable) { |
| 182 | if (((val & mask) >> AZX_MLCTL_CPA)) | 182 | if (((val & mask) >> AZX_MLCTL_CPA_SHIFT)) |
| 183 | return 0; | 183 | return 0; |
| 184 | } else { | 184 | } else { |
| 185 | if (!((val & mask) >> AZX_MLCTL_CPA)) | 185 | if (!((val & mask) >> AZX_MLCTL_CPA_SHIFT)) |
| 186 | return 0; | 186 | return 0; |
| 187 | } | 187 | } |
| 188 | udelay(3); | 188 | udelay(3); |
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 043065867656..d15b653de0bf 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c | |||
| @@ -272,7 +272,7 @@ int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus) | |||
| 272 | 272 | ||
| 273 | /* Lets walk the linked capabilities list */ | 273 | /* Lets walk the linked capabilities list */ |
| 274 | do { | 274 | do { |
| 275 | cur_cap = _snd_hdac_chip_read(l, bus, offset); | 275 | cur_cap = _snd_hdac_chip_readl(bus, offset); |
| 276 | 276 | ||
| 277 | dev_dbg(bus->dev, "Capability version: 0x%x\n", | 277 | dev_dbg(bus->dev, "Capability version: 0x%x\n", |
| 278 | (cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF); | 278 | (cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF); |
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index c6994ebb4567..e1472c7ab6c1 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c | |||
| @@ -555,12 +555,12 @@ void snd_hdac_stream_sync_trigger(struct hdac_stream *azx_dev, bool set, | |||
| 555 | 555 | ||
| 556 | if (!reg) | 556 | if (!reg) |
| 557 | reg = AZX_REG_SSYNC; | 557 | reg = AZX_REG_SSYNC; |
| 558 | val = _snd_hdac_chip_read(l, bus, reg); | 558 | val = _snd_hdac_chip_readl(bus, reg); |
| 559 | if (set) | 559 | if (set) |
| 560 | val |= streams; | 560 | val |= streams; |
| 561 | else | 561 | else |
| 562 | val &= ~streams; | 562 | val &= ~streams; |
| 563 | _snd_hdac_chip_write(l, bus, reg, val); | 563 | _snd_hdac_chip_writel(bus, reg, val); |
| 564 | } | 564 | } |
| 565 | EXPORT_SYMBOL_GPL(snd_hdac_stream_sync_trigger); | 565 | EXPORT_SYMBOL_GPL(snd_hdac_stream_sync_trigger); |
| 566 | 566 | ||
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index e2cf508841b1..81cf26fa28d6 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c | |||
| @@ -742,7 +742,7 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device) | |||
| 742 | 742 | ||
| 743 | pcm->private_data = chip; | 743 | pcm->private_data = chip; |
| 744 | pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; | 744 | pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; |
| 745 | sprintf(pcm->name, snd_es1688_chip_id(chip)); | 745 | strcpy(pcm->name, snd_es1688_chip_id(chip)); |
| 746 | chip->pcm = pcm; | 746 | chip->pcm = pcm; |
| 747 | 747 | ||
| 748 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 748 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 92b819e4f729..34bbc2e730a6 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c | |||
| @@ -1339,7 +1339,7 @@ static int snd_ali_prepare(struct snd_pcm_substream *substream) | |||
| 1339 | rate = snd_ali_get_spdif_in_rate(codec); | 1339 | rate = snd_ali_get_spdif_in_rate(codec); |
| 1340 | if (rate == 0) { | 1340 | if (rate == 0) { |
| 1341 | dev_warn(codec->card->dev, | 1341 | dev_warn(codec->card->dev, |
| 1342 | "ali_capture_preapre: spdif rate detect err!\n"); | 1342 | "ali_capture_prepare: spdif rate detect err!\n"); |
| 1343 | rate = 48000; | 1343 | rate = 48000; |
| 1344 | } | 1344 | } |
| 1345 | spin_lock_irq(&codec->reg_lock); | 1345 | spin_lock_irq(&codec->reg_lock); |
diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index ab0f87312911..7a4558a70fb9 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c | |||
| @@ -846,7 +846,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol, | |||
| 846 | return changed; | 846 | return changed; |
| 847 | } | 847 | } |
| 848 | 848 | ||
| 849 | static struct snd_kcontrol_new vortex_a3d_kcontrol = { | 849 | static const struct snd_kcontrol_new vortex_a3d_kcontrol = { |
| 850 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 850 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 851 | .name = "Playback PCM advanced processing", | 851 | .name = "Playback PCM advanced processing", |
| 852 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | 852 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index e1af24f87566..c308a4f70550 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c | |||
| @@ -2279,6 +2279,9 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, | |||
| 2279 | } else { | 2279 | } else { |
| 2280 | int src[2], mix[2]; | 2280 | int src[2], mix[2]; |
| 2281 | 2281 | ||
| 2282 | if (nr_ch < 1) | ||
| 2283 | return -EINVAL; | ||
| 2284 | |||
| 2282 | /* Get SRC and MIXER hardware resources. */ | 2285 | /* Get SRC and MIXER hardware resources. */ |
| 2283 | for (i = 0; i < nr_ch; i++) { | 2286 | for (i = 0; i < nr_ch; i++) { |
| 2284 | if ((mix[i] = | 2287 | if ((mix[i] = |
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index 9585c5c63b96..b566b44e4da7 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c | |||
| @@ -757,7 +757,7 @@ snd_vortex_eqtoggle_put(struct snd_kcontrol *kcontrol, | |||
| 757 | return 1; /* Allways changes */ | 757 | return 1; /* Allways changes */ |
| 758 | } | 758 | } |
| 759 | 759 | ||
| 760 | static struct snd_kcontrol_new vortex_eqtoggle_kcontrol = { | 760 | static const struct snd_kcontrol_new vortex_eqtoggle_kcontrol = { |
| 761 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 761 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 762 | .name = "EQ Enable", | 762 | .name = "EQ Enable", |
| 763 | .index = 0, | 763 | .index = 0, |
| @@ -815,7 +815,7 @@ snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucon | |||
| 815 | return changed; | 815 | return changed; |
| 816 | } | 816 | } |
| 817 | 817 | ||
| 818 | static struct snd_kcontrol_new vortex_eq_kcontrol = { | 818 | static const struct snd_kcontrol_new vortex_eq_kcontrol = { |
| 819 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 819 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 820 | .name = " .", | 820 | .name = " .", |
| 821 | .index = 0, | 821 | .index = 0, |
| @@ -855,7 +855,7 @@ snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u | |||
| 855 | return 0; | 855 | return 0; |
| 856 | } | 856 | } |
| 857 | 857 | ||
| 858 | static struct snd_kcontrol_new vortex_levels_kcontrol = { | 858 | static const struct snd_kcontrol_new vortex_levels_kcontrol = { |
| 859 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 859 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 860 | .name = "EQ Peaks", | 860 | .name = "EQ Peaks", |
| 861 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 861 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index df5741a78fd2..335979a753fe 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c | |||
| @@ -601,7 +601,7 @@ static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
| 601 | 601 | ||
| 602 | static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); | 602 | static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); |
| 603 | 603 | ||
| 604 | static struct snd_kcontrol_new snd_vortex_pcm_vol = { | 604 | static const struct snd_kcontrol_new snd_vortex_pcm_vol = { |
| 605 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 605 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 606 | .name = "PCM Playback Volume", | 606 | .name = "PCM Playback Volume", |
| 607 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 607 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 57bbb87d0c62..8356180bfe0e 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c | |||
| @@ -202,7 +202,7 @@ static const struct snd_pcm_ops snd_aw2_capture_ops = { | |||
| 202 | .pointer = snd_aw2_pcm_pointer_capture, | 202 | .pointer = snd_aw2_pcm_pointer_capture, |
| 203 | }; | 203 | }; |
| 204 | 204 | ||
| 205 | static struct snd_kcontrol_new aw2_control = { | 205 | static const struct snd_kcontrol_new aw2_control = { |
| 206 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 206 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 207 | .name = "PCM Capture Route", | 207 | .name = "PCM Capture Route", |
| 208 | .index = 0, | 208 | .index = 0, |
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index f2c0709d7441..099efb046b1c 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c | |||
| @@ -598,7 +598,7 @@ static int snd_bt87x_capture_volume_put(struct snd_kcontrol *kcontrol, | |||
| 598 | return changed; | 598 | return changed; |
| 599 | } | 599 | } |
| 600 | 600 | ||
| 601 | static struct snd_kcontrol_new snd_bt87x_capture_volume = { | 601 | static const struct snd_kcontrol_new snd_bt87x_capture_volume = { |
| 602 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 602 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 603 | .name = "Capture Volume", | 603 | .name = "Capture Volume", |
| 604 | .info = snd_bt87x_capture_volume_info, | 604 | .info = snd_bt87x_capture_volume_info, |
| @@ -634,7 +634,7 @@ static int snd_bt87x_capture_boost_put(struct snd_kcontrol *kcontrol, | |||
| 634 | return changed; | 634 | return changed; |
| 635 | } | 635 | } |
| 636 | 636 | ||
| 637 | static struct snd_kcontrol_new snd_bt87x_capture_boost = { | 637 | static const struct snd_kcontrol_new snd_bt87x_capture_boost = { |
| 638 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 638 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 639 | .name = "Capture Boost", | 639 | .name = "Capture Boost", |
| 640 | .info = snd_bt87x_capture_boost_info, | 640 | .info = snd_bt87x_capture_boost_info, |
| @@ -676,7 +676,7 @@ static int snd_bt87x_capture_source_put(struct snd_kcontrol *kcontrol, | |||
| 676 | return changed; | 676 | return changed; |
| 677 | } | 677 | } |
| 678 | 678 | ||
| 679 | static struct snd_kcontrol_new snd_bt87x_capture_source = { | 679 | static const struct snd_kcontrol_new snd_bt87x_capture_source = { |
| 680 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 680 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 681 | .name = "Capture Source", | 681 | .name = "Capture Source", |
| 682 | .info = snd_bt87x_capture_source_info, | 682 | .info = snd_bt87x_capture_source_info, |
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 025805cba779..b4d3415331f6 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
| @@ -301,7 +301,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, | |||
| 301 | return change; | 301 | return change; |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in = | 304 | static const struct snd_kcontrol_new snd_ca0106_capture_mic_line_in = |
| 305 | { | 305 | { |
| 306 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 306 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 307 | .name = "Shared Mic/Line in Capture Switch", | 307 | .name = "Shared Mic/Line in Capture Switch", |
| @@ -310,7 +310,7 @@ static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in = | |||
| 310 | .put = snd_ca0106_capture_mic_line_in_put | 310 | .put = snd_ca0106_capture_mic_line_in_put |
| 311 | }; | 311 | }; |
| 312 | 312 | ||
| 313 | static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out = | 313 | static const struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out = |
| 314 | { | 314 | { |
| 315 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 315 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 316 | .name = "Shared Line in/Side out Capture Switch", | 316 | .name = "Shared Line in/Side out Capture Switch", |
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index aeedc270ed9b..227c9d3802b8 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
| @@ -1045,7 +1045,7 @@ static int snd_cmipci_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
| 1045 | return change; | 1045 | return change; |
| 1046 | } | 1046 | } |
| 1047 | 1047 | ||
| 1048 | static struct snd_kcontrol_new snd_cmipci_spdif_default = | 1048 | static const struct snd_kcontrol_new snd_cmipci_spdif_default = |
| 1049 | { | 1049 | { |
| 1050 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1050 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1051 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | 1051 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), |
| @@ -1072,7 +1072,7 @@ static int snd_cmipci_spdif_mask_get(struct snd_kcontrol *kcontrol, | |||
| 1072 | return 0; | 1072 | return 0; |
| 1073 | } | 1073 | } |
| 1074 | 1074 | ||
| 1075 | static struct snd_kcontrol_new snd_cmipci_spdif_mask = | 1075 | static const struct snd_kcontrol_new snd_cmipci_spdif_mask = |
| 1076 | { | 1076 | { |
| 1077 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1077 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1078 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1078 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1119,7 +1119,7 @@ static int snd_cmipci_spdif_stream_put(struct snd_kcontrol *kcontrol, | |||
| 1119 | return change; | 1119 | return change; |
| 1120 | } | 1120 | } |
| 1121 | 1121 | ||
| 1122 | static struct snd_kcontrol_new snd_cmipci_spdif_stream = | 1122 | static const struct snd_kcontrol_new snd_cmipci_spdif_stream = |
| 1123 | { | 1123 | { |
| 1124 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | 1124 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
| 1125 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1125 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index fa7c51684dd2..f870697aca67 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
| @@ -1055,7 +1055,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol, | |||
| 1055 | 1055 | ||
| 1056 | static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); | 1056 | static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); |
| 1057 | 1057 | ||
| 1058 | static struct snd_kcontrol_new snd_cs4281_fm_vol = | 1058 | static const struct snd_kcontrol_new snd_cs4281_fm_vol = |
| 1059 | { | 1059 | { |
| 1060 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1060 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1061 | .name = "Synth Playback Volume", | 1061 | .name = "Synth Playback Volume", |
| @@ -1066,7 +1066,7 @@ static struct snd_kcontrol_new snd_cs4281_fm_vol = | |||
| 1066 | .tlv = { .p = db_scale_dsp }, | 1066 | .tlv = { .p = db_scale_dsp }, |
| 1067 | }; | 1067 | }; |
| 1068 | 1068 | ||
| 1069 | static struct snd_kcontrol_new snd_cs4281_pcm_vol = | 1069 | static const struct snd_kcontrol_new snd_cs4281_pcm_vol = |
| 1070 | { | 1070 | { |
| 1071 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1071 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1072 | .name = "PCM Stream Playback Volume", | 1072 | .name = "PCM Stream Playback Volume", |
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 937071760bc4..d15ecf9febbf 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c | |||
| @@ -1039,7 +1039,7 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, | |||
| 1039 | 1039 | ||
| 1040 | #ifdef ECHOCARD_HAS_LINE_OUT_GAIN | 1040 | #ifdef ECHOCARD_HAS_LINE_OUT_GAIN |
| 1041 | /* On the Mia this one controls the line-out volume */ | 1041 | /* On the Mia this one controls the line-out volume */ |
| 1042 | static struct snd_kcontrol_new snd_echo_line_output_gain = { | 1042 | static const struct snd_kcontrol_new snd_echo_line_output_gain = { |
| 1043 | .name = "Line Playback Volume", | 1043 | .name = "Line Playback Volume", |
| 1044 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1044 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1045 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 1045 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| @@ -1050,7 +1050,7 @@ static struct snd_kcontrol_new snd_echo_line_output_gain = { | |||
| 1050 | .tlv = {.p = db_scale_output_gain}, | 1050 | .tlv = {.p = db_scale_output_gain}, |
| 1051 | }; | 1051 | }; |
| 1052 | #else | 1052 | #else |
| 1053 | static struct snd_kcontrol_new snd_echo_pcm_output_gain = { | 1053 | static const struct snd_kcontrol_new snd_echo_pcm_output_gain = { |
| 1054 | .name = "PCM Playback Volume", | 1054 | .name = "PCM Playback Volume", |
| 1055 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1055 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1056 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 1056 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, |
| @@ -1120,7 +1120,7 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, | |||
| 1120 | 1120 | ||
| 1121 | static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); | 1121 | static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); |
| 1122 | 1122 | ||
| 1123 | static struct snd_kcontrol_new snd_echo_line_input_gain = { | 1123 | static const struct snd_kcontrol_new snd_echo_line_input_gain = { |
| 1124 | .name = "Line Capture Volume", | 1124 | .name = "Line Capture Volume", |
| 1125 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1125 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1126 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 1126 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, |
| @@ -1184,7 +1184,7 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol, | |||
| 1184 | return changed; | 1184 | return changed; |
| 1185 | } | 1185 | } |
| 1186 | 1186 | ||
| 1187 | static struct snd_kcontrol_new snd_echo_output_nominal_level = { | 1187 | static const struct snd_kcontrol_new snd_echo_output_nominal_level = { |
| 1188 | .name = "Line Playback Switch (-10dBV)", | 1188 | .name = "Line Playback Switch (-10dBV)", |
| 1189 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1189 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1190 | .info = snd_echo_output_nominal_info, | 1190 | .info = snd_echo_output_nominal_info, |
| @@ -1250,7 +1250,7 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol, | |||
| 1250 | return changed; | 1250 | return changed; |
| 1251 | } | 1251 | } |
| 1252 | 1252 | ||
| 1253 | static struct snd_kcontrol_new snd_echo_intput_nominal_level = { | 1253 | static const struct snd_kcontrol_new snd_echo_intput_nominal_level = { |
| 1254 | .name = "Line Capture Switch (-10dBV)", | 1254 | .name = "Line Capture Switch (-10dBV)", |
| 1255 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1255 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1256 | .info = snd_echo_input_nominal_info, | 1256 | .info = snd_echo_input_nominal_info, |
| @@ -1477,7 +1477,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, | |||
| 1477 | return changed; | 1477 | return changed; |
| 1478 | } | 1478 | } |
| 1479 | 1479 | ||
| 1480 | static struct snd_kcontrol_new snd_echo_digital_mode_switch = { | 1480 | static const struct snd_kcontrol_new snd_echo_digital_mode_switch = { |
| 1481 | .name = "Digital mode Switch", | 1481 | .name = "Digital mode Switch", |
| 1482 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 1482 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
| 1483 | .info = snd_echo_digital_mode_info, | 1483 | .info = snd_echo_digital_mode_info, |
| @@ -1527,7 +1527,7 @@ static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol, | |||
| 1527 | return 0; | 1527 | return 0; |
| 1528 | } | 1528 | } |
| 1529 | 1529 | ||
| 1530 | static struct snd_kcontrol_new snd_echo_spdif_mode_switch = { | 1530 | static const struct snd_kcontrol_new snd_echo_spdif_mode_switch = { |
| 1531 | .name = "S/PDIF mode Switch", | 1531 | .name = "S/PDIF mode Switch", |
| 1532 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 1532 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
| 1533 | .info = snd_echo_spdif_mode_info, | 1533 | .info = snd_echo_spdif_mode_info, |
| @@ -1600,7 +1600,7 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, | |||
| 1600 | return changed; | 1600 | return changed; |
| 1601 | } | 1601 | } |
| 1602 | 1602 | ||
| 1603 | static struct snd_kcontrol_new snd_echo_clock_source_switch = { | 1603 | static const struct snd_kcontrol_new snd_echo_clock_source_switch = { |
| 1604 | .name = "Sample Clock Source", | 1604 | .name = "Sample Clock Source", |
| 1605 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1605 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1606 | .info = snd_echo_clock_source_info, | 1606 | .info = snd_echo_clock_source_info, |
| @@ -1643,7 +1643,7 @@ static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol, | |||
| 1643 | return changed; | 1643 | return changed; |
| 1644 | } | 1644 | } |
| 1645 | 1645 | ||
| 1646 | static struct snd_kcontrol_new snd_echo_phantom_power_switch = { | 1646 | static const struct snd_kcontrol_new snd_echo_phantom_power_switch = { |
| 1647 | .name = "Phantom power Switch", | 1647 | .name = "Phantom power Switch", |
| 1648 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 1648 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
| 1649 | .info = snd_echo_phantom_power_info, | 1649 | .info = snd_echo_phantom_power_info, |
| @@ -1686,7 +1686,7 @@ static int snd_echo_automute_put(struct snd_kcontrol *kcontrol, | |||
| 1686 | return changed; | 1686 | return changed; |
| 1687 | } | 1687 | } |
| 1688 | 1688 | ||
| 1689 | static struct snd_kcontrol_new snd_echo_automute_switch = { | 1689 | static const struct snd_kcontrol_new snd_echo_automute_switch = { |
| 1690 | .name = "Digital Capture Switch (automute)", | 1690 | .name = "Digital Capture Switch (automute)", |
| 1691 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 1691 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
| 1692 | .info = snd_echo_automute_info, | 1692 | .info = snd_echo_automute_info, |
| @@ -1713,7 +1713,7 @@ static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol, | |||
| 1713 | return 1; | 1713 | return 1; |
| 1714 | } | 1714 | } |
| 1715 | 1715 | ||
| 1716 | static struct snd_kcontrol_new snd_echo_vumeters_switch = { | 1716 | static const struct snd_kcontrol_new snd_echo_vumeters_switch = { |
| 1717 | .name = "VU-meters Switch", | 1717 | .name = "VU-meters Switch", |
| 1718 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 1718 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
| 1719 | .access = SNDRV_CTL_ELEM_ACCESS_WRITE, | 1719 | .access = SNDRV_CTL_ELEM_ACCESS_WRITE, |
| @@ -1751,7 +1751,7 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol, | |||
| 1751 | return 0; | 1751 | return 0; |
| 1752 | } | 1752 | } |
| 1753 | 1753 | ||
| 1754 | static struct snd_kcontrol_new snd_echo_vumeters = { | 1754 | static const struct snd_kcontrol_new snd_echo_vumeters = { |
| 1755 | .name = "VU-meters", | 1755 | .name = "VU-meters", |
| 1756 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1756 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1757 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | 1757 | .access = SNDRV_CTL_ELEM_ACCESS_READ | |
| @@ -1804,7 +1804,7 @@ static int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol, | |||
| 1804 | return 0; | 1804 | return 0; |
| 1805 | } | 1805 | } |
| 1806 | 1806 | ||
| 1807 | static struct snd_kcontrol_new snd_echo_channels_info = { | 1807 | static const struct snd_kcontrol_new snd_echo_channels_info = { |
| 1808 | .name = "Channels info", | 1808 | .name = "Channels info", |
| 1809 | .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, | 1809 | .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, |
| 1810 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 1810 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 32842734ada6..77a4413f4564 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
| @@ -1112,7 +1112,7 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
| 1112 | return change; | 1112 | return change; |
| 1113 | } | 1113 | } |
| 1114 | 1114 | ||
| 1115 | static struct snd_kcontrol_new snd_emu10k1x_shared_spdif = | 1115 | static const struct snd_kcontrol_new snd_emu10k1x_shared_spdif = |
| 1116 | { | 1116 | { |
| 1117 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1117 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1118 | .name = "Analog/Digital Output Jack", | 1118 | .name = "Analog/Digital Output Jack", |
| @@ -1171,7 +1171,7 @@ static int snd_emu10k1x_spdif_put(struct snd_kcontrol *kcontrol, | |||
| 1171 | return change; | 1171 | return change; |
| 1172 | } | 1172 | } |
| 1173 | 1173 | ||
| 1174 | static struct snd_kcontrol_new snd_emu10k1x_spdif_mask_control = | 1174 | static const struct snd_kcontrol_new snd_emu10k1x_spdif_mask_control = |
| 1175 | { | 1175 | { |
| 1176 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1176 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1177 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1177 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1181,7 +1181,7 @@ static struct snd_kcontrol_new snd_emu10k1x_spdif_mask_control = | |||
| 1181 | .get = snd_emu10k1x_spdif_get_mask | 1181 | .get = snd_emu10k1x_spdif_get_mask |
| 1182 | }; | 1182 | }; |
| 1183 | 1183 | ||
| 1184 | static struct snd_kcontrol_new snd_emu10k1x_spdif_control = | 1184 | static const struct snd_kcontrol_new snd_emu10k1x_spdif_control = |
| 1185 | { | 1185 | { |
| 1186 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1186 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1187 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | 1187 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), |
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 076b117009c5..b2219a73c17c 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
| @@ -795,7 +795,7 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, | |||
| 795 | return change; | 795 | return change; |
| 796 | } | 796 | } |
| 797 | 797 | ||
| 798 | static struct snd_kcontrol_new snd_emu1010_internal_clock = | 798 | static const struct snd_kcontrol_new snd_emu1010_internal_clock = |
| 799 | { | 799 | { |
| 800 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | 800 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
| 801 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 801 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| @@ -847,7 +847,7 @@ static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, | |||
| 847 | return change; | 847 | return change; |
| 848 | } | 848 | } |
| 849 | 849 | ||
| 850 | static struct snd_kcontrol_new snd_emu1010_optical_out = { | 850 | static const struct snd_kcontrol_new snd_emu1010_optical_out = { |
| 851 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | 851 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
| 852 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 852 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 853 | .name = "Optical Output Mode", | 853 | .name = "Optical Output Mode", |
| @@ -898,7 +898,7 @@ static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, | |||
| 898 | return change; | 898 | return change; |
| 899 | } | 899 | } |
| 900 | 900 | ||
| 901 | static struct snd_kcontrol_new snd_emu1010_optical_in = { | 901 | static const struct snd_kcontrol_new snd_emu1010_optical_in = { |
| 902 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | 902 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
| 903 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 903 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 904 | .name = "Optical Input Mode", | 904 | .name = "Optical Input Mode", |
| @@ -978,7 +978,7 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, | |||
| 978 | return change; | 978 | return change; |
| 979 | } | 979 | } |
| 980 | 980 | ||
| 981 | static struct snd_kcontrol_new snd_audigy_i2c_capture_source = | 981 | static const struct snd_kcontrol_new snd_audigy_i2c_capture_source = |
| 982 | { | 982 | { |
| 983 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 983 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 984 | .name = "Capture Source", | 984 | .name = "Capture Source", |
| @@ -1177,7 +1177,7 @@ static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, | |||
| 1177 | return change; | 1177 | return change; |
| 1178 | } | 1178 | } |
| 1179 | 1179 | ||
| 1180 | static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = | 1180 | static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = |
| 1181 | { | 1181 | { |
| 1182 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1182 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1183 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1183 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1187,7 +1187,7 @@ static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = | |||
| 1187 | .get = snd_emu10k1_spdif_get_mask | 1187 | .get = snd_emu10k1_spdif_get_mask |
| 1188 | }; | 1188 | }; |
| 1189 | 1189 | ||
| 1190 | static struct snd_kcontrol_new snd_emu10k1_spdif_control = | 1190 | static const struct snd_kcontrol_new snd_emu10k1_spdif_control = |
| 1191 | { | 1191 | { |
| 1192 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1192 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1193 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | 1193 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), |
| @@ -1293,7 +1293,7 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, | |||
| 1293 | return change; | 1293 | return change; |
| 1294 | } | 1294 | } |
| 1295 | 1295 | ||
| 1296 | static struct snd_kcontrol_new snd_emu10k1_send_routing_control = | 1296 | static const struct snd_kcontrol_new snd_emu10k1_send_routing_control = |
| 1297 | { | 1297 | { |
| 1298 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | 1298 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
| 1299 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1299 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1364,7 +1364,7 @@ static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, | |||
| 1364 | return change; | 1364 | return change; |
| 1365 | } | 1365 | } |
| 1366 | 1366 | ||
| 1367 | static struct snd_kcontrol_new snd_emu10k1_send_volume_control = | 1367 | static const struct snd_kcontrol_new snd_emu10k1_send_volume_control = |
| 1368 | { | 1368 | { |
| 1369 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | 1369 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
| 1370 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1370 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1429,7 +1429,7 @@ static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, | |||
| 1429 | return change; | 1429 | return change; |
| 1430 | } | 1430 | } |
| 1431 | 1431 | ||
| 1432 | static struct snd_kcontrol_new snd_emu10k1_attn_control = | 1432 | static const struct snd_kcontrol_new snd_emu10k1_attn_control = |
| 1433 | { | 1433 | { |
| 1434 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | 1434 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
| 1435 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1435 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1501,7 +1501,7 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, | |||
| 1501 | return change; | 1501 | return change; |
| 1502 | } | 1502 | } |
| 1503 | 1503 | ||
| 1504 | static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = | 1504 | static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = |
| 1505 | { | 1505 | { |
| 1506 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | 1506 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
| 1507 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1507 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1568,7 +1568,7 @@ static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, | |||
| 1568 | } | 1568 | } |
| 1569 | 1569 | ||
| 1570 | 1570 | ||
| 1571 | static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = | 1571 | static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = |
| 1572 | { | 1572 | { |
| 1573 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | 1573 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
| 1574 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1574 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1626,7 +1626,7 @@ static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, | |||
| 1626 | return change; | 1626 | return change; |
| 1627 | } | 1627 | } |
| 1628 | 1628 | ||
| 1629 | static struct snd_kcontrol_new snd_emu10k1_efx_attn_control = | 1629 | static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control = |
| 1630 | { | 1630 | { |
| 1631 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | 1631 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
| 1632 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1632 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1691,7 +1691,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
| 1691 | return change; | 1691 | return change; |
| 1692 | } | 1692 | } |
| 1693 | 1693 | ||
| 1694 | static struct snd_kcontrol_new snd_emu10k1_shared_spdif = | 1694 | static const struct snd_kcontrol_new snd_emu10k1_shared_spdif = |
| 1695 | { | 1695 | { |
| 1696 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1696 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1697 | .name = "SB Live Analog/Digital Output Jack", | 1697 | .name = "SB Live Analog/Digital Output Jack", |
| @@ -1700,7 +1700,7 @@ static struct snd_kcontrol_new snd_emu10k1_shared_spdif = | |||
| 1700 | .put = snd_emu10k1_shared_spdif_put | 1700 | .put = snd_emu10k1_shared_spdif_put |
| 1701 | }; | 1701 | }; |
| 1702 | 1702 | ||
| 1703 | static struct snd_kcontrol_new snd_audigy_shared_spdif = | 1703 | static const struct snd_kcontrol_new snd_audigy_shared_spdif = |
| 1704 | { | 1704 | { |
| 1705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1706 | .name = "Audigy Analog/Digital Output Jack", | 1706 | .name = "Audigy Analog/Digital Output Jack", |
| @@ -1738,7 +1738,7 @@ static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, | |||
| 1738 | return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); | 1738 | return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); |
| 1739 | } | 1739 | } |
| 1740 | 1740 | ||
| 1741 | static struct snd_kcontrol_new snd_audigy_capture_boost = | 1741 | static const struct snd_kcontrol_new snd_audigy_capture_boost = |
| 1742 | { | 1742 | { |
| 1743 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1743 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1744 | .name = "Mic Extra Boost", | 1744 | .name = "Mic Extra Boost", |
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 37be1e14d756..ef1cf530c929 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
| @@ -1542,7 +1542,7 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st | |||
| 1542 | return change; | 1542 | return change; |
| 1543 | } | 1543 | } |
| 1544 | 1544 | ||
| 1545 | static struct snd_kcontrol_new snd_emu10k1_pcm_efx_voices_mask = { | 1545 | static const struct snd_kcontrol_new snd_emu10k1_pcm_efx_voices_mask = { |
| 1546 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1546 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1547 | .name = "Captured FX8010 Outputs", | 1547 | .name = "Captured FX8010 Outputs", |
| 1548 | .info = snd_emu10k1_pcm_efx_voices_mask_info, | 1548 | .info = snd_emu10k1_pcm_efx_voices_mask_info, |
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 164adad91650..5d10349d11ce 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c | |||
| @@ -1530,7 +1530,7 @@ static int snd_es1373_rear_put(struct snd_kcontrol *kcontrol, | |||
| 1530 | return change; | 1530 | return change; |
| 1531 | } | 1531 | } |
| 1532 | 1532 | ||
| 1533 | static struct snd_kcontrol_new snd_ens1373_rear = | 1533 | static const struct snd_kcontrol_new snd_ens1373_rear = |
| 1534 | { | 1534 | { |
| 1535 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1535 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1536 | .name = "AC97 2ch->4ch Copy Switch", | 1536 | .name = "AC97 2ch->4ch Copy Switch", |
| @@ -1575,7 +1575,7 @@ static int snd_es1373_line_put(struct snd_kcontrol *kcontrol, | |||
| 1575 | return changed; | 1575 | return changed; |
| 1576 | } | 1576 | } |
| 1577 | 1577 | ||
| 1578 | static struct snd_kcontrol_new snd_ens1373_line = | 1578 | static const struct snd_kcontrol_new snd_ens1373_line = |
| 1579 | { | 1579 | { |
| 1580 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1580 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1581 | .name = "Line In->Rear Out Switch", | 1581 | .name = "Line In->Rear Out Switch", |
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index a03cf68d0bcd..d3ea73171a3d 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c | |||
| @@ -580,6 +580,7 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec, | |||
| 580 | has_multiple_pins = 1; | 580 | has_multiple_pins = 1; |
| 581 | if (has_multiple_pins && type == AUTO_PIN_MIC) | 581 | if (has_multiple_pins && type == AUTO_PIN_MIC) |
| 582 | has_multiple_pins &= check_mic_location_need(codec, cfg, input); | 582 | has_multiple_pins &= check_mic_location_need(codec, cfg, input); |
| 583 | has_multiple_pins |= codec->force_pin_prefix; | ||
| 583 | return hda_get_input_pin_label(codec, &cfg->inputs[input], | 584 | return hda_get_input_pin_label(codec, &cfg->inputs[input], |
| 584 | cfg->inputs[input].pin, | 585 | cfg->inputs[input].pin, |
| 585 | has_multiple_pins); | 586 | has_multiple_pins); |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8fd745cb3f36..70bb365a08d2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
| @@ -1965,7 +1965,7 @@ static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol, | |||
| 1965 | return 1; | 1965 | return 1; |
| 1966 | } | 1966 | } |
| 1967 | 1967 | ||
| 1968 | static struct snd_kcontrol_new vmaster_mute_mode = { | 1968 | static const struct snd_kcontrol_new vmaster_mute_mode = { |
| 1969 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1969 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1970 | .name = "Mute-LED Mode", | 1970 | .name = "Mute-LED Mode", |
| 1971 | .info = vmaster_mute_mode_info, | 1971 | .info = vmaster_mute_mode_info, |
| @@ -2705,7 +2705,7 @@ static int spdif_share_sw_put(struct snd_kcontrol *kcontrol, | |||
| 2705 | return 0; | 2705 | return 0; |
| 2706 | } | 2706 | } |
| 2707 | 2707 | ||
| 2708 | static struct snd_kcontrol_new spdif_share_sw = { | 2708 | static const struct snd_kcontrol_new spdif_share_sw = { |
| 2709 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2709 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2710 | .name = "IEC958 Default PCM Playback Switch", | 2710 | .name = "IEC958 Default PCM Playback Switch", |
| 2711 | .info = snd_ctl_boolean_mono_info, | 2711 | .info = snd_ctl_boolean_mono_info, |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index f17f25245e52..d6fb2d5d01a7 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
| @@ -256,6 +256,7 @@ struct hda_codec { | |||
| 256 | unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ | 256 | unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ |
| 257 | unsigned int power_save_node:1; /* advanced PM for each widget */ | 257 | unsigned int power_save_node:1; /* advanced PM for each widget */ |
| 258 | unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */ | 258 | unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */ |
| 259 | unsigned int force_pin_prefix:1; /* Add location prefix */ | ||
| 259 | #ifdef CONFIG_PM | 260 | #ifdef CONFIG_PM |
| 260 | unsigned long power_on_acct; | 261 | unsigned long power_on_acct; |
| 261 | unsigned long power_off_acct; | 262 | unsigned long power_off_acct; |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index e7c8f4f076d5..2842c82363c0 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
| @@ -196,6 +196,9 @@ static void parse_user_hints(struct hda_codec *codec) | |||
| 196 | val = snd_hda_get_bool_hint(codec, "hp_mic_detect"); | 196 | val = snd_hda_get_bool_hint(codec, "hp_mic_detect"); |
| 197 | if (val >= 0) | 197 | if (val >= 0) |
| 198 | spec->suppress_hp_mic_detect = !val; | 198 | spec->suppress_hp_mic_detect = !val; |
| 199 | val = snd_hda_get_bool_hint(codec, "vmaster"); | ||
| 200 | if (val >= 0) | ||
| 201 | spec->suppress_vmaster = !val; | ||
| 199 | 202 | ||
| 200 | if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) | 203 | if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) |
| 201 | spec->mixer_nid = val; | 204 | spec->mixer_nid = val; |
| @@ -1125,6 +1128,7 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch, | |||
| 1125 | 1128 | ||
| 1126 | *index = 0; | 1129 | *index = 0; |
| 1127 | if (cfg->line_outs == 1 && !spec->multi_ios && | 1130 | if (cfg->line_outs == 1 && !spec->multi_ios && |
| 1131 | !codec->force_pin_prefix && | ||
| 1128 | !cfg->hp_outs && !cfg->speaker_outs) | 1132 | !cfg->hp_outs && !cfg->speaker_outs) |
| 1129 | return spec->vmaster_mute.hook ? "PCM" : "Master"; | 1133 | return spec->vmaster_mute.hook ? "PCM" : "Master"; |
| 1130 | 1134 | ||
| @@ -1132,6 +1136,7 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch, | |||
| 1132 | * use it master (or "PCM" if a vmaster hook is present) | 1136 | * use it master (or "PCM" if a vmaster hook is present) |
| 1133 | */ | 1137 | */ |
| 1134 | if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && | 1138 | if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && |
| 1139 | !codec->force_pin_prefix && | ||
| 1135 | !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) | 1140 | !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) |
| 1136 | return spec->vmaster_mute.hook ? "PCM" : "Master"; | 1141 | return spec->vmaster_mute.hook ? "PCM" : "Master"; |
| 1137 | 1142 | ||
| @@ -5031,7 +5036,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec) | |||
| 5031 | } | 5036 | } |
| 5032 | 5037 | ||
| 5033 | /* if we have no master control, let's create it */ | 5038 | /* if we have no master control, let's create it */ |
| 5034 | if (!spec->no_analog && | 5039 | if (!spec->no_analog && !spec->suppress_vmaster && |
| 5035 | !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | 5040 | !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { |
| 5036 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | 5041 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", |
| 5037 | spec->vmaster_tlv, slave_pfxs, | 5042 | spec->vmaster_tlv, slave_pfxs, |
| @@ -5039,7 +5044,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec) | |||
| 5039 | if (err < 0) | 5044 | if (err < 0) |
| 5040 | return err; | 5045 | return err; |
| 5041 | } | 5046 | } |
| 5042 | if (!spec->no_analog && | 5047 | if (!spec->no_analog && !spec->suppress_vmaster && |
| 5043 | !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | 5048 | !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { |
| 5044 | err = __snd_hda_add_vmaster(codec, "Master Playback Switch", | 5049 | err = __snd_hda_add_vmaster(codec, "Master Playback Switch", |
| 5045 | NULL, slave_pfxs, | 5050 | NULL, slave_pfxs, |
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index f66fc7e25e07..61772317de46 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h | |||
| @@ -229,6 +229,7 @@ struct hda_gen_spec { | |||
| 229 | unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */ | 229 | unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */ |
| 230 | unsigned int power_down_unused:1; /* power down unused widgets */ | 230 | unsigned int power_down_unused:1; /* power down unused widgets */ |
| 231 | unsigned int dac_min_mute:1; /* minimal = mute for DACs */ | 231 | unsigned int dac_min_mute:1; /* minimal = mute for DACs */ |
| 232 | unsigned int suppress_vmaster:1; /* don't create vmaster kctls */ | ||
| 232 | 233 | ||
| 233 | /* other internal flags */ | 234 | /* other internal flags */ |
| 234 | unsigned int no_analog:1; /* digital I/O only */ | 235 | unsigned int no_analog:1; /* digital I/O only */ |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c8256a89375a..b786fbab029f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
| @@ -77,6 +77,7 @@ enum { | |||
| 77 | POS_FIX_POSBUF, | 77 | POS_FIX_POSBUF, |
| 78 | POS_FIX_VIACOMBO, | 78 | POS_FIX_VIACOMBO, |
| 79 | POS_FIX_COMBO, | 79 | POS_FIX_COMBO, |
| 80 | POS_FIX_SKL, | ||
| 80 | }; | 81 | }; |
| 81 | 82 | ||
| 82 | /* Defines for ATI HD Audio support in SB450 south bridge */ | 83 | /* Defines for ATI HD Audio support in SB450 south bridge */ |
| @@ -148,7 +149,7 @@ module_param_array(model, charp, NULL, 0444); | |||
| 148 | MODULE_PARM_DESC(model, "Use the given board model."); | 149 | MODULE_PARM_DESC(model, "Use the given board model."); |
| 149 | module_param_array(position_fix, int, NULL, 0444); | 150 | module_param_array(position_fix, int, NULL, 0444); |
| 150 | MODULE_PARM_DESC(position_fix, "DMA pointer read method." | 151 | MODULE_PARM_DESC(position_fix, "DMA pointer read method." |
| 151 | "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO)."); | 152 | "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+)."); |
| 152 | module_param_array(bdl_pos_adj, int, NULL, 0644); | 153 | module_param_array(bdl_pos_adj, int, NULL, 0644); |
| 153 | MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); | 154 | MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); |
| 154 | module_param_array(probe_mask, int, NULL, 0444); | 155 | module_param_array(probe_mask, int, NULL, 0444); |
| @@ -369,8 +370,10 @@ enum { | |||
| 369 | #define IS_KBL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d71) | 370 | #define IS_KBL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d71) |
| 370 | #define IS_KBL_H(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa2f0) | 371 | #define IS_KBL_H(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa2f0) |
| 371 | #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) | 372 | #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) |
| 373 | #define IS_GLK(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x3198) | ||
| 372 | #define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) || \ | 374 | #define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) || \ |
| 373 | IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci) | 375 | IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci) || \ |
| 376 | IS_GLK(pci) | ||
| 374 | 377 | ||
| 375 | static char *driver_short_names[] = { | 378 | static char *driver_short_names[] = { |
| 376 | [AZX_DRIVER_ICH] = "HDA Intel", | 379 | [AZX_DRIVER_ICH] = "HDA Intel", |
| @@ -534,9 +537,101 @@ static void bxt_reduce_dma_latency(struct azx *chip) | |||
| 534 | { | 537 | { |
| 535 | u32 val; | 538 | u32 val; |
| 536 | 539 | ||
| 537 | val = azx_readl(chip, SKL_EM4L); | 540 | val = azx_readl(chip, VS_EM4L); |
| 538 | val &= (0x3 << 20); | 541 | val &= (0x3 << 20); |
| 539 | azx_writel(chip, SKL_EM4L, val); | 542 | azx_writel(chip, VS_EM4L, val); |
| 543 | } | ||
| 544 | |||
| 545 | /* | ||
| 546 | * ML_LCAP bits: | ||
| 547 | * bit 0: 6 MHz Supported | ||
| 548 | * bit 1: 12 MHz Supported | ||
| 549 | * bit 2: 24 MHz Supported | ||
| 550 | * bit 3: 48 MHz Supported | ||
| 551 | * bit 4: 96 MHz Supported | ||
| 552 | * bit 5: 192 MHz Supported | ||
| 553 | */ | ||
| 554 | static int intel_get_lctl_scf(struct azx *chip) | ||
| 555 | { | ||
| 556 | struct hdac_bus *bus = azx_bus(chip); | ||
| 557 | static int preferred_bits[] = { 2, 3, 1, 4, 5 }; | ||
| 558 | u32 val, t; | ||
| 559 | int i; | ||
| 560 | |||
| 561 | val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCAP); | ||
| 562 | |||
| 563 | for (i = 0; i < ARRAY_SIZE(preferred_bits); i++) { | ||
| 564 | t = preferred_bits[i]; | ||
| 565 | if (val & (1 << t)) | ||
| 566 | return t; | ||
| 567 | } | ||
| 568 | |||
| 569 | dev_warn(chip->card->dev, "set audio clock frequency to 6MHz"); | ||
| 570 | return 0; | ||
| 571 | } | ||
| 572 | |||
| 573 | static int intel_ml_lctl_set_power(struct azx *chip, int state) | ||
| 574 | { | ||
| 575 | struct hdac_bus *bus = azx_bus(chip); | ||
| 576 | u32 val; | ||
| 577 | int timeout; | ||
| 578 | |||
| 579 | /* | ||
| 580 | * the codecs are sharing the first link setting by default | ||
| 581 | * If other links are enabled for stream, they need similar fix | ||
| 582 | */ | ||
| 583 | val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL); | ||
| 584 | val &= ~AZX_MLCTL_SPA; | ||
| 585 | val |= state << AZX_MLCTL_SPA_SHIFT; | ||
| 586 | writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL); | ||
| 587 | /* wait for CPA */ | ||
| 588 | timeout = 50; | ||
| 589 | while (timeout) { | ||
| 590 | if (((readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL)) & | ||
| 591 | AZX_MLCTL_CPA) == (state << AZX_MLCTL_CPA_SHIFT)) | ||
| 592 | return 0; | ||
| 593 | timeout--; | ||
| 594 | udelay(10); | ||
| 595 | } | ||
| 596 | |||
| 597 | return -1; | ||
| 598 | } | ||
| 599 | |||
| 600 | static void intel_init_lctl(struct azx *chip) | ||
| 601 | { | ||
| 602 | struct hdac_bus *bus = azx_bus(chip); | ||
| 603 | u32 val; | ||
| 604 | int ret; | ||
| 605 | |||
| 606 | /* 0. check lctl register value is correct or not */ | ||
| 607 | val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL); | ||
| 608 | /* if SCF is already set, let's use it */ | ||
| 609 | if ((val & ML_LCTL_SCF_MASK) != 0) | ||
| 610 | return; | ||
| 611 | |||
| 612 | /* | ||
| 613 | * Before operating on SPA, CPA must match SPA. | ||
| 614 | * Any deviation may result in undefined behavior. | ||
| 615 | */ | ||
| 616 | if (((val & AZX_MLCTL_SPA) >> AZX_MLCTL_SPA_SHIFT) != | ||
| 617 | ((val & AZX_MLCTL_CPA) >> AZX_MLCTL_CPA_SHIFT)) | ||
| 618 | return; | ||
| 619 | |||
| 620 | /* 1. turn link down: set SPA to 0 and wait CPA to 0 */ | ||
| 621 | ret = intel_ml_lctl_set_power(chip, 0); | ||
| 622 | udelay(100); | ||
| 623 | if (ret) | ||
| 624 | goto set_spa; | ||
| 625 | |||
| 626 | /* 2. update SCF to select a properly audio clock*/ | ||
| 627 | val &= ~ML_LCTL_SCF_MASK; | ||
| 628 | val |= intel_get_lctl_scf(chip); | ||
| 629 | writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL); | ||
| 630 | |||
| 631 | set_spa: | ||
| 632 | /* 4. turn link up: set SPA to 1 and wait CPA to 1 */ | ||
| 633 | intel_ml_lctl_set_power(chip, 1); | ||
| 634 | udelay(100); | ||
| 540 | } | 635 | } |
| 541 | 636 | ||
| 542 | static void hda_intel_init_chip(struct azx *chip, bool full_reset) | 637 | static void hda_intel_init_chip(struct azx *chip, bool full_reset) |
| @@ -564,6 +659,9 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) | |||
| 564 | /* reduce dma latency to avoid noise */ | 659 | /* reduce dma latency to avoid noise */ |
| 565 | if (IS_BXT(pci)) | 660 | if (IS_BXT(pci)) |
| 566 | bxt_reduce_dma_latency(chip); | 661 | bxt_reduce_dma_latency(chip); |
| 662 | |||
| 663 | if (bus->mlcap != NULL) | ||
| 664 | intel_init_lctl(chip); | ||
| 567 | } | 665 | } |
| 568 | 666 | ||
| 569 | /* calculate runtime delay from LPIB */ | 667 | /* calculate runtime delay from LPIB */ |
| @@ -815,6 +913,31 @@ static unsigned int azx_via_get_position(struct azx *chip, | |||
| 815 | return bound_pos + mod_dma_pos; | 913 | return bound_pos + mod_dma_pos; |
| 816 | } | 914 | } |
| 817 | 915 | ||
| 916 | static unsigned int azx_skl_get_dpib_pos(struct azx *chip, | ||
| 917 | struct azx_dev *azx_dev) | ||
| 918 | { | ||
| 919 | return _snd_hdac_chip_readl(azx_bus(chip), | ||
| 920 | AZX_REG_VS_SDXDPIB_XBASE + | ||
| 921 | (AZX_REG_VS_SDXDPIB_XINTERVAL * | ||
| 922 | azx_dev->core.index)); | ||
| 923 | } | ||
| 924 | |||
| 925 | /* get the current DMA position with correction on SKL+ chips */ | ||
| 926 | static unsigned int azx_get_pos_skl(struct azx *chip, struct azx_dev *azx_dev) | ||
| 927 | { | ||
| 928 | /* DPIB register gives a more accurate position for playback */ | ||
| 929 | if (azx_dev->core.substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 930 | return azx_skl_get_dpib_pos(chip, azx_dev); | ||
| 931 | |||
| 932 | /* For capture, we need to read posbuf, but it requires a delay | ||
| 933 | * for the possible boundary overlap; the read of DPIB fetches the | ||
| 934 | * actual posbuf | ||
| 935 | */ | ||
| 936 | udelay(20); | ||
| 937 | azx_skl_get_dpib_pos(chip, azx_dev); | ||
| 938 | return azx_get_pos_posbuf(chip, azx_dev); | ||
| 939 | } | ||
| 940 | |||
| 818 | #ifdef CONFIG_PM | 941 | #ifdef CONFIG_PM |
| 819 | static DEFINE_MUTEX(card_list_lock); | 942 | static DEFINE_MUTEX(card_list_lock); |
| 820 | static LIST_HEAD(card_list); | 943 | static LIST_HEAD(card_list); |
| @@ -1351,6 +1474,7 @@ static int check_position_fix(struct azx *chip, int fix) | |||
| 1351 | case POS_FIX_POSBUF: | 1474 | case POS_FIX_POSBUF: |
| 1352 | case POS_FIX_VIACOMBO: | 1475 | case POS_FIX_VIACOMBO: |
| 1353 | case POS_FIX_COMBO: | 1476 | case POS_FIX_COMBO: |
| 1477 | case POS_FIX_SKL: | ||
| 1354 | return fix; | 1478 | return fix; |
| 1355 | } | 1479 | } |
| 1356 | 1480 | ||
| @@ -1371,6 +1495,10 @@ static int check_position_fix(struct azx *chip, int fix) | |||
| 1371 | dev_dbg(chip->card->dev, "Using LPIB position fix\n"); | 1495 | dev_dbg(chip->card->dev, "Using LPIB position fix\n"); |
| 1372 | return POS_FIX_LPIB; | 1496 | return POS_FIX_LPIB; |
| 1373 | } | 1497 | } |
| 1498 | if (IS_SKL_PLUS(chip->pci)) { | ||
| 1499 | dev_dbg(chip->card->dev, "Using SKL position fix\n"); | ||
| 1500 | return POS_FIX_SKL; | ||
| 1501 | } | ||
| 1374 | return POS_FIX_AUTO; | 1502 | return POS_FIX_AUTO; |
| 1375 | } | 1503 | } |
| 1376 | 1504 | ||
| @@ -1382,6 +1510,7 @@ static void assign_position_fix(struct azx *chip, int fix) | |||
| 1382 | [POS_FIX_POSBUF] = azx_get_pos_posbuf, | 1510 | [POS_FIX_POSBUF] = azx_get_pos_posbuf, |
| 1383 | [POS_FIX_VIACOMBO] = azx_via_get_position, | 1511 | [POS_FIX_VIACOMBO] = azx_via_get_position, |
| 1384 | [POS_FIX_COMBO] = azx_get_pos_lpib, | 1512 | [POS_FIX_COMBO] = azx_get_pos_lpib, |
| 1513 | [POS_FIX_SKL] = azx_get_pos_skl, | ||
| 1385 | }; | 1514 | }; |
| 1386 | 1515 | ||
| 1387 | chip->get_position[0] = chip->get_position[1] = callbacks[fix]; | 1516 | chip->get_position[0] = chip->get_position[1] = callbacks[fix]; |
| @@ -1390,7 +1519,7 @@ static void assign_position_fix(struct azx *chip, int fix) | |||
| 1390 | if (fix == POS_FIX_COMBO) | 1519 | if (fix == POS_FIX_COMBO) |
| 1391 | chip->get_position[1] = NULL; | 1520 | chip->get_position[1] = NULL; |
| 1392 | 1521 | ||
| 1393 | if (fix == POS_FIX_POSBUF && | 1522 | if ((fix == POS_FIX_POSBUF || fix == POS_FIX_SKL) && |
| 1394 | (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { | 1523 | (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { |
| 1395 | chip->get_delay[0] = chip->get_delay[1] = | 1524 | chip->get_delay[0] = chip->get_delay[1] = |
| 1396 | azx_get_delay_from_lpib; | 1525 | azx_get_delay_from_lpib; |
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 07a9deb17477..a148176c16a9 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c | |||
| @@ -857,7 +857,7 @@ static int chipio_write_address(struct hda_codec *codec, | |||
| 857 | chip_addx >> 16); | 857 | chip_addx >> 16); |
| 858 | } | 858 | } |
| 859 | 859 | ||
| 860 | spec->curr_chip_addx = (res < 0) ? ~0UL : chip_addx; | 860 | spec->curr_chip_addx = (res < 0) ? ~0U : chip_addx; |
| 861 | 861 | ||
| 862 | return res; | 862 | return res; |
| 863 | } | 863 | } |
| @@ -882,7 +882,7 @@ static int chipio_write_data(struct hda_codec *codec, unsigned int data) | |||
| 882 | /*If no error encountered, automatically increment the address | 882 | /*If no error encountered, automatically increment the address |
| 883 | as per chip behaviour*/ | 883 | as per chip behaviour*/ |
| 884 | spec->curr_chip_addx = (res != -EIO) ? | 884 | spec->curr_chip_addx = (res != -EIO) ? |
| 885 | (spec->curr_chip_addx + 4) : ~0UL; | 885 | (spec->curr_chip_addx + 4) : ~0U; |
| 886 | return res; | 886 | return res; |
| 887 | } | 887 | } |
| 888 | 888 | ||
| @@ -933,7 +933,7 @@ static int chipio_read_data(struct hda_codec *codec, unsigned int *data) | |||
| 933 | /*If no error encountered, automatically increment the address | 933 | /*If no error encountered, automatically increment the address |
| 934 | as per chip behaviour*/ | 934 | as per chip behaviour*/ |
| 935 | spec->curr_chip_addx = (res != -EIO) ? | 935 | spec->curr_chip_addx = (res != -EIO) ? |
| 936 | (spec->curr_chip_addx + 4) : ~0UL; | 936 | (spec->curr_chip_addx + 4) : ~0U; |
| 937 | return res; | 937 | return res; |
| 938 | } | 938 | } |
| 939 | 939 | ||
| @@ -1168,7 +1168,7 @@ static int dspio_write_multiple(struct hda_codec *codec, | |||
| 1168 | int status = 0; | 1168 | int status = 0; |
| 1169 | unsigned int count; | 1169 | unsigned int count; |
| 1170 | 1170 | ||
| 1171 | if ((buffer == NULL)) | 1171 | if (buffer == NULL) |
| 1172 | return -EINVAL; | 1172 | return -EINVAL; |
| 1173 | 1173 | ||
| 1174 | count = 0; | 1174 | count = 0; |
| @@ -1210,7 +1210,7 @@ static int dspio_read_multiple(struct hda_codec *codec, unsigned int *buffer, | |||
| 1210 | unsigned int skip_count; | 1210 | unsigned int skip_count; |
| 1211 | unsigned int dummy; | 1211 | unsigned int dummy; |
| 1212 | 1212 | ||
| 1213 | if ((buffer == NULL)) | 1213 | if (buffer == NULL) |
| 1214 | return -1; | 1214 | return -1; |
| 1215 | 1215 | ||
| 1216 | count = 0; | 1216 | count = 0; |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 69266b8ea2ad..e8253737c47a 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
| @@ -52,6 +52,12 @@ struct conexant_spec { | |||
| 52 | bool dc_enable; | 52 | bool dc_enable; |
| 53 | unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ | 53 | unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ |
| 54 | struct nid_path *dc_mode_path; | 54 | struct nid_path *dc_mode_path; |
| 55 | |||
| 56 | int mute_led_polarity; | ||
| 57 | unsigned int gpio_led; | ||
| 58 | unsigned int gpio_mute_led_mask; | ||
| 59 | unsigned int gpio_mic_led_mask; | ||
| 60 | |||
| 55 | }; | 61 | }; |
| 56 | 62 | ||
| 57 | 63 | ||
| @@ -264,6 +270,7 @@ enum { | |||
| 264 | CXT_FIXUP_HP_DOCK, | 270 | CXT_FIXUP_HP_DOCK, |
| 265 | CXT_FIXUP_HP_SPECTRE, | 271 | CXT_FIXUP_HP_SPECTRE, |
| 266 | CXT_FIXUP_HP_GATE_MIC, | 272 | CXT_FIXUP_HP_GATE_MIC, |
| 273 | CXT_FIXUP_MUTE_LED_GPIO, | ||
| 267 | }; | 274 | }; |
| 268 | 275 | ||
| 269 | /* for hda_fixup_thinkpad_acpi() */ | 276 | /* for hda_fixup_thinkpad_acpi() */ |
| @@ -646,6 +653,74 @@ static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec, | |||
| 646 | snd_hda_jack_set_gating_jack(codec, 0x19, 0x16); | 653 | snd_hda_jack_set_gating_jack(codec, 0x19, 0x16); |
| 647 | } | 654 | } |
| 648 | 655 | ||
| 656 | /* update LED status via GPIO */ | ||
| 657 | static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask, | ||
| 658 | bool enabled) | ||
| 659 | { | ||
| 660 | struct conexant_spec *spec = codec->spec; | ||
| 661 | unsigned int oldval = spec->gpio_led; | ||
| 662 | |||
| 663 | if (spec->mute_led_polarity) | ||
| 664 | enabled = !enabled; | ||
| 665 | |||
| 666 | if (enabled) | ||
| 667 | spec->gpio_led &= ~mask; | ||
| 668 | else | ||
| 669 | spec->gpio_led |= mask; | ||
| 670 | if (spec->gpio_led != oldval) | ||
| 671 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
| 672 | spec->gpio_led); | ||
| 673 | } | ||
| 674 | |||
| 675 | /* turn on/off mute LED via GPIO per vmaster hook */ | ||
| 676 | static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled) | ||
| 677 | { | ||
| 678 | struct hda_codec *codec = private_data; | ||
| 679 | struct conexant_spec *spec = codec->spec; | ||
| 680 | |||
| 681 | cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled); | ||
| 682 | } | ||
| 683 | |||
| 684 | /* turn on/off mic-mute LED via GPIO per capture hook */ | ||
| 685 | static void cxt_fixup_gpio_mic_mute_hook(struct hda_codec *codec, | ||
| 686 | struct snd_kcontrol *kcontrol, | ||
| 687 | struct snd_ctl_elem_value *ucontrol) | ||
| 688 | { | ||
| 689 | struct conexant_spec *spec = codec->spec; | ||
| 690 | |||
| 691 | if (ucontrol) | ||
| 692 | cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, | ||
| 693 | ucontrol->value.integer.value[0] || | ||
| 694 | ucontrol->value.integer.value[1]); | ||
| 695 | } | ||
| 696 | |||
| 697 | |||
| 698 | static void cxt_fixup_mute_led_gpio(struct hda_codec *codec, | ||
| 699 | const struct hda_fixup *fix, int action) | ||
| 700 | { | ||
| 701 | struct conexant_spec *spec = codec->spec; | ||
| 702 | static const struct hda_verb gpio_init[] = { | ||
| 703 | { 0x01, AC_VERB_SET_GPIO_MASK, 0x03 }, | ||
| 704 | { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 }, | ||
| 705 | {} | ||
| 706 | }; | ||
| 707 | codec_info(codec, "action: %d gpio_led: %d\n", action, spec->gpio_led); | ||
| 708 | |||
| 709 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | ||
| 710 | spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook; | ||
| 711 | spec->gen.cap_sync_hook = cxt_fixup_gpio_mic_mute_hook; | ||
| 712 | spec->gpio_led = 0; | ||
| 713 | spec->mute_led_polarity = 0; | ||
| 714 | spec->gpio_mute_led_mask = 0x01; | ||
| 715 | spec->gpio_mic_led_mask = 0x02; | ||
| 716 | } | ||
| 717 | snd_hda_add_verbs(codec, gpio_init); | ||
| 718 | if (spec->gpio_led) | ||
| 719 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
| 720 | spec->gpio_led); | ||
| 721 | } | ||
| 722 | |||
| 723 | |||
| 649 | /* ThinkPad X200 & co with cxt5051 */ | 724 | /* ThinkPad X200 & co with cxt5051 */ |
| 650 | static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { | 725 | static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { |
| 651 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ | 726 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ |
| @@ -799,6 +874,10 @@ static const struct hda_fixup cxt_fixups[] = { | |||
| 799 | .type = HDA_FIXUP_FUNC, | 874 | .type = HDA_FIXUP_FUNC, |
| 800 | .v.func = cxt_fixup_hp_gate_mic_jack, | 875 | .v.func = cxt_fixup_hp_gate_mic_jack, |
| 801 | }, | 876 | }, |
| 877 | [CXT_FIXUP_MUTE_LED_GPIO] = { | ||
| 878 | .type = HDA_FIXUP_FUNC, | ||
| 879 | .v.func = cxt_fixup_mute_led_gpio, | ||
| 880 | }, | ||
| 802 | }; | 881 | }; |
| 803 | 882 | ||
| 804 | static const struct snd_pci_quirk cxt5045_fixups[] = { | 883 | static const struct snd_pci_quirk cxt5045_fixups[] = { |
| @@ -851,6 +930,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { | |||
| 851 | SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), | 930 | SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), |
| 852 | SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), | 931 | SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), |
| 853 | SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), | 932 | SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), |
| 933 | SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), | ||
| 854 | SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), | 934 | SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), |
| 855 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), | 935 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), |
| 856 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), | 936 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), |
| @@ -882,6 +962,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { | |||
| 882 | { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, | 962 | { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, |
| 883 | { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" }, | 963 | { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" }, |
| 884 | { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" }, | 964 | { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" }, |
| 965 | { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" }, | ||
| 885 | {} | 966 | {} |
| 886 | }; | 967 | }; |
| 887 | 968 | ||
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 1461ef8eb749..90e4ff87445e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
| @@ -177,6 +177,7 @@ struct hdmi_spec { | |||
| 177 | bool i915_bound; /* was i915 bound in this driver? */ | 177 | bool i915_bound; /* was i915 bound in this driver? */ |
| 178 | 178 | ||
| 179 | struct hdac_chmap chmap; | 179 | struct hdac_chmap chmap; |
| 180 | hda_nid_t vendor_nid; | ||
| 180 | }; | 181 | }; |
| 181 | 182 | ||
| 182 | #ifdef CONFIG_SND_HDA_I915 | 183 | #ifdef CONFIG_SND_HDA_I915 |
| @@ -383,7 +384,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, | |||
| 383 | return 0; | 384 | return 0; |
| 384 | } | 385 | } |
| 385 | 386 | ||
| 386 | static struct snd_kcontrol_new eld_bytes_ctl = { | 387 | static const struct snd_kcontrol_new eld_bytes_ctl = { |
| 387 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 388 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
| 388 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 389 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 389 | .name = "ELD", | 390 | .name = "ELD", |
| @@ -2372,6 +2373,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec, | |||
| 2372 | } | 2373 | } |
| 2373 | 2374 | ||
| 2374 | #define INTEL_VENDOR_NID 0x08 | 2375 | #define INTEL_VENDOR_NID 0x08 |
| 2376 | #define INTEL_GLK_VENDOR_NID 0x0B | ||
| 2375 | #define INTEL_GET_VENDOR_VERB 0xf81 | 2377 | #define INTEL_GET_VENDOR_VERB 0xf81 |
| 2376 | #define INTEL_SET_VENDOR_VERB 0x781 | 2378 | #define INTEL_SET_VENDOR_VERB 0x781 |
| 2377 | #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ | 2379 | #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ |
| @@ -2381,14 +2383,15 @@ static void intel_haswell_enable_all_pins(struct hda_codec *codec, | |||
| 2381 | bool update_tree) | 2383 | bool update_tree) |
| 2382 | { | 2384 | { |
| 2383 | unsigned int vendor_param; | 2385 | unsigned int vendor_param; |
| 2386 | struct hdmi_spec *spec = codec->spec; | ||
| 2384 | 2387 | ||
| 2385 | vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0, | 2388 | vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0, |
| 2386 | INTEL_GET_VENDOR_VERB, 0); | 2389 | INTEL_GET_VENDOR_VERB, 0); |
| 2387 | if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) | 2390 | if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) |
| 2388 | return; | 2391 | return; |
| 2389 | 2392 | ||
| 2390 | vendor_param |= INTEL_EN_ALL_PIN_CVTS; | 2393 | vendor_param |= INTEL_EN_ALL_PIN_CVTS; |
| 2391 | vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0, | 2394 | vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0, |
| 2392 | INTEL_SET_VENDOR_VERB, vendor_param); | 2395 | INTEL_SET_VENDOR_VERB, vendor_param); |
| 2393 | if (vendor_param == -1) | 2396 | if (vendor_param == -1) |
| 2394 | return; | 2397 | return; |
| @@ -2400,8 +2403,9 @@ static void intel_haswell_enable_all_pins(struct hda_codec *codec, | |||
| 2400 | static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec) | 2403 | static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec) |
| 2401 | { | 2404 | { |
| 2402 | unsigned int vendor_param; | 2405 | unsigned int vendor_param; |
| 2406 | struct hdmi_spec *spec = codec->spec; | ||
| 2403 | 2407 | ||
| 2404 | vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0, | 2408 | vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0, |
| 2405 | INTEL_GET_VENDOR_VERB, 0); | 2409 | INTEL_GET_VENDOR_VERB, 0); |
| 2406 | if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) | 2410 | if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) |
| 2407 | return; | 2411 | return; |
| @@ -2409,7 +2413,7 @@ static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec) | |||
| 2409 | /* enable DP1.2 mode */ | 2413 | /* enable DP1.2 mode */ |
| 2410 | vendor_param |= INTEL_EN_DP12; | 2414 | vendor_param |= INTEL_EN_DP12; |
| 2411 | snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB); | 2415 | snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB); |
| 2412 | snd_hda_codec_write_cache(codec, INTEL_VENDOR_NID, 0, | 2416 | snd_hda_codec_write_cache(codec, spec->vendor_nid, 0, |
| 2413 | INTEL_SET_VENDOR_VERB, vendor_param); | 2417 | INTEL_SET_VENDOR_VERB, vendor_param); |
| 2414 | } | 2418 | } |
| 2415 | 2419 | ||
| @@ -2503,7 +2507,7 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec, | |||
| 2503 | } | 2507 | } |
| 2504 | 2508 | ||
| 2505 | /* Intel Haswell and onwards; audio component with eld notifier */ | 2509 | /* Intel Haswell and onwards; audio component with eld notifier */ |
| 2506 | static int patch_i915_hsw_hdmi(struct hda_codec *codec) | 2510 | static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) |
| 2507 | { | 2511 | { |
| 2508 | struct hdmi_spec *spec; | 2512 | struct hdmi_spec *spec; |
| 2509 | int err; | 2513 | int err; |
| @@ -2520,6 +2524,7 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec) | |||
| 2520 | spec = codec->spec; | 2524 | spec = codec->spec; |
| 2521 | codec->dp_mst = true; | 2525 | codec->dp_mst = true; |
| 2522 | spec->dyn_pcm_assign = true; | 2526 | spec->dyn_pcm_assign = true; |
| 2527 | spec->vendor_nid = vendor_nid; | ||
| 2523 | 2528 | ||
| 2524 | intel_haswell_enable_all_pins(codec, true); | 2529 | intel_haswell_enable_all_pins(codec, true); |
| 2525 | intel_haswell_fixup_enable_dp12(codec); | 2530 | intel_haswell_fixup_enable_dp12(codec); |
| @@ -2548,6 +2553,16 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec) | |||
| 2548 | return 0; | 2553 | return 0; |
| 2549 | } | 2554 | } |
| 2550 | 2555 | ||
| 2556 | static int patch_i915_hsw_hdmi(struct hda_codec *codec) | ||
| 2557 | { | ||
| 2558 | return intel_hsw_common_init(codec, INTEL_VENDOR_NID); | ||
| 2559 | } | ||
| 2560 | |||
| 2561 | static int patch_i915_glk_hdmi(struct hda_codec *codec) | ||
| 2562 | { | ||
| 2563 | return intel_hsw_common_init(codec, INTEL_GLK_VENDOR_NID); | ||
| 2564 | } | ||
| 2565 | |||
| 2551 | /* Intel Baytrail and Braswell; with eld notifier */ | 2566 | /* Intel Baytrail and Braswell; with eld notifier */ |
| 2552 | static int patch_i915_byt_hdmi(struct hda_codec *codec) | 2567 | static int patch_i915_byt_hdmi(struct hda_codec *codec) |
| 2553 | { | 2568 | { |
| @@ -3800,7 +3815,7 @@ HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi), | |||
| 3800 | HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi), | 3815 | HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi), |
| 3801 | HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi), | 3816 | HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi), |
| 3802 | HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi), | 3817 | HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi), |
| 3803 | HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_hsw_hdmi), | 3818 | HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi), |
| 3804 | HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), | 3819 | HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), |
| 3805 | HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), | 3820 | HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), |
| 3806 | HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), | 3821 | HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 299835d1fbaa..58df440013c5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
| @@ -1800,6 +1800,7 @@ enum { | |||
| 1800 | ALC882_FIXUP_NO_PRIMARY_HP, | 1800 | ALC882_FIXUP_NO_PRIMARY_HP, |
| 1801 | ALC887_FIXUP_ASUS_BASS, | 1801 | ALC887_FIXUP_ASUS_BASS, |
| 1802 | ALC887_FIXUP_BASS_CHMAP, | 1802 | ALC887_FIXUP_BASS_CHMAP, |
| 1803 | ALC1220_FIXUP_GB_DUAL_CODECS, | ||
| 1803 | }; | 1804 | }; |
| 1804 | 1805 | ||
| 1805 | static void alc889_fixup_coef(struct hda_codec *codec, | 1806 | static void alc889_fixup_coef(struct hda_codec *codec, |
| @@ -1962,6 +1963,61 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec, | |||
| 1962 | static void alc_fixup_bass_chmap(struct hda_codec *codec, | 1963 | static void alc_fixup_bass_chmap(struct hda_codec *codec, |
| 1963 | const struct hda_fixup *fix, int action); | 1964 | const struct hda_fixup *fix, int action); |
| 1964 | 1965 | ||
| 1966 | /* For dual-codec configuration, we need to disable some features to avoid | ||
| 1967 | * conflicts of kctls and PCM streams | ||
| 1968 | */ | ||
| 1969 | static void alc_fixup_dual_codecs(struct hda_codec *codec, | ||
| 1970 | const struct hda_fixup *fix, int action) | ||
| 1971 | { | ||
| 1972 | struct alc_spec *spec = codec->spec; | ||
| 1973 | |||
| 1974 | if (action != HDA_FIXUP_ACT_PRE_PROBE) | ||
| 1975 | return; | ||
| 1976 | /* disable vmaster */ | ||
| 1977 | spec->gen.suppress_vmaster = 1; | ||
| 1978 | /* auto-mute and auto-mic switch don't work with multiple codecs */ | ||
| 1979 | spec->gen.suppress_auto_mute = 1; | ||
| 1980 | spec->gen.suppress_auto_mic = 1; | ||
| 1981 | /* disable aamix as well */ | ||
| 1982 | spec->gen.mixer_nid = 0; | ||
| 1983 | /* add location prefix to avoid conflicts */ | ||
| 1984 | codec->force_pin_prefix = 1; | ||
| 1985 | } | ||
| 1986 | |||
| 1987 | static void rename_ctl(struct hda_codec *codec, const char *oldname, | ||
| 1988 | const char *newname) | ||
| 1989 | { | ||
| 1990 | struct snd_kcontrol *kctl; | ||
| 1991 | |||
| 1992 | kctl = snd_hda_find_mixer_ctl(codec, oldname); | ||
| 1993 | if (kctl) | ||
| 1994 | strcpy(kctl->id.name, newname); | ||
| 1995 | } | ||
| 1996 | |||
| 1997 | static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec, | ||
| 1998 | const struct hda_fixup *fix, | ||
| 1999 | int action) | ||
| 2000 | { | ||
| 2001 | alc_fixup_dual_codecs(codec, fix, action); | ||
| 2002 | switch (action) { | ||
| 2003 | case HDA_FIXUP_ACT_PRE_PROBE: | ||
| 2004 | /* override card longname to provide a unique UCM profile */ | ||
| 2005 | strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs"); | ||
| 2006 | break; | ||
| 2007 | case HDA_FIXUP_ACT_BUILD: | ||
| 2008 | /* rename Capture controls depending on the codec */ | ||
| 2009 | rename_ctl(codec, "Capture Volume", | ||
| 2010 | codec->addr == 0 ? | ||
| 2011 | "Rear-Panel Capture Volume" : | ||
| 2012 | "Front-Panel Capture Volume"); | ||
| 2013 | rename_ctl(codec, "Capture Switch", | ||
| 2014 | codec->addr == 0 ? | ||
| 2015 | "Rear-Panel Capture Switch" : | ||
| 2016 | "Front-Panel Capture Switch"); | ||
| 2017 | break; | ||
| 2018 | } | ||
| 2019 | } | ||
| 2020 | |||
| 1965 | static const struct hda_fixup alc882_fixups[] = { | 2021 | static const struct hda_fixup alc882_fixups[] = { |
| 1966 | [ALC882_FIXUP_ABIT_AW9D_MAX] = { | 2022 | [ALC882_FIXUP_ABIT_AW9D_MAX] = { |
| 1967 | .type = HDA_FIXUP_PINS, | 2023 | .type = HDA_FIXUP_PINS, |
| @@ -2198,6 +2254,10 @@ static const struct hda_fixup alc882_fixups[] = { | |||
| 2198 | .type = HDA_FIXUP_FUNC, | 2254 | .type = HDA_FIXUP_FUNC, |
| 2199 | .v.func = alc_fixup_bass_chmap, | 2255 | .v.func = alc_fixup_bass_chmap, |
| 2200 | }, | 2256 | }, |
| 2257 | [ALC1220_FIXUP_GB_DUAL_CODECS] = { | ||
| 2258 | .type = HDA_FIXUP_FUNC, | ||
| 2259 | .v.func = alc1220_fixup_gb_dual_codecs, | ||
| 2260 | }, | ||
| 2201 | }; | 2261 | }; |
| 2202 | 2262 | ||
| 2203 | static const struct snd_pci_quirk alc882_fixup_tbl[] = { | 2263 | static const struct snd_pci_quirk alc882_fixup_tbl[] = { |
| @@ -2267,6 +2327,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { | |||
| 2267 | SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), | 2327 | SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), |
| 2268 | SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), | 2328 | SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), |
| 2269 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE), | 2329 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE), |
| 2330 | SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), | ||
| 2270 | SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), | 2331 | SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), |
| 2271 | SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), | 2332 | SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), |
| 2272 | SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), | 2333 | SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), |
| @@ -4663,7 +4724,6 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec, | |||
| 4663 | { 0x1b, 0x21114000 }, /* dock speaker pin */ | 4724 | { 0x1b, 0x21114000 }, /* dock speaker pin */ |
| 4664 | {} | 4725 | {} |
| 4665 | }; | 4726 | }; |
| 4666 | struct snd_kcontrol *kctl; | ||
| 4667 | 4727 | ||
| 4668 | switch (action) { | 4728 | switch (action) { |
| 4669 | case HDA_FIXUP_ACT_PRE_PROBE: | 4729 | case HDA_FIXUP_ACT_PRE_PROBE: |
| @@ -4678,12 +4738,10 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec, | |||
| 4678 | /* this is a bit tricky; give more sane names for the main | 4738 | /* this is a bit tricky; give more sane names for the main |
| 4679 | * (tablet) speaker and the dock speaker, respectively | 4739 | * (tablet) speaker and the dock speaker, respectively |
| 4680 | */ | 4740 | */ |
| 4681 | kctl = snd_hda_find_mixer_ctl(codec, "Speaker Playback Switch"); | 4741 | rename_ctl(codec, "Speaker Playback Switch", |
| 4682 | if (kctl) | 4742 | "Dock Speaker Playback Switch"); |
| 4683 | strcpy(kctl->id.name, "Dock Speaker Playback Switch"); | 4743 | rename_ctl(codec, "Bass Speaker Playback Switch", |
| 4684 | kctl = snd_hda_find_mixer_ctl(codec, "Bass Speaker Playback Switch"); | 4744 | "Speaker Playback Switch"); |
| 4685 | if (kctl) | ||
| 4686 | strcpy(kctl->id.name, "Speaker Playback Switch"); | ||
| 4687 | break; | 4745 | break; |
| 4688 | } | 4746 | } |
| 4689 | } | 4747 | } |
| @@ -4766,6 +4824,30 @@ static void alc280_fixup_hp_9480m(struct hda_codec *codec, | |||
| 4766 | } | 4824 | } |
| 4767 | } | 4825 | } |
| 4768 | 4826 | ||
| 4827 | static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec, | ||
| 4828 | const struct hda_fixup *fix, | ||
| 4829 | int action) | ||
| 4830 | { | ||
| 4831 | alc_fixup_dual_codecs(codec, fix, action); | ||
| 4832 | switch (action) { | ||
| 4833 | case HDA_FIXUP_ACT_PRE_PROBE: | ||
| 4834 | /* override card longname to provide a unique UCM profile */ | ||
| 4835 | strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs"); | ||
| 4836 | break; | ||
| 4837 | case HDA_FIXUP_ACT_BUILD: | ||
| 4838 | /* rename Capture controls depending on the codec */ | ||
| 4839 | rename_ctl(codec, "Capture Volume", | ||
| 4840 | codec->addr == 0 ? | ||
| 4841 | "Rear-Panel Capture Volume" : | ||
| 4842 | "Front-Panel Capture Volume"); | ||
| 4843 | rename_ctl(codec, "Capture Switch", | ||
| 4844 | codec->addr == 0 ? | ||
| 4845 | "Rear-Panel Capture Switch" : | ||
| 4846 | "Front-Panel Capture Switch"); | ||
| 4847 | break; | ||
| 4848 | } | ||
| 4849 | } | ||
| 4850 | |||
| 4769 | /* for hda_fixup_thinkpad_acpi() */ | 4851 | /* for hda_fixup_thinkpad_acpi() */ |
| 4770 | #include "thinkpad_helper.c" | 4852 | #include "thinkpad_helper.c" |
| 4771 | 4853 | ||
| @@ -4833,6 +4915,8 @@ enum { | |||
| 4833 | ALC290_FIXUP_SUBWOOFER_HSJACK, | 4915 | ALC290_FIXUP_SUBWOOFER_HSJACK, |
| 4834 | ALC269_FIXUP_THINKPAD_ACPI, | 4916 | ALC269_FIXUP_THINKPAD_ACPI, |
| 4835 | ALC269_FIXUP_DMIC_THINKPAD_ACPI, | 4917 | ALC269_FIXUP_DMIC_THINKPAD_ACPI, |
| 4918 | ALC255_FIXUP_ACER_MIC_NO_PRESENCE, | ||
| 4919 | ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, | ||
| 4836 | ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 4920 | ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
| 4837 | ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, | 4921 | ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, |
| 4838 | ALC255_FIXUP_HEADSET_MODE, | 4922 | ALC255_FIXUP_HEADSET_MODE, |
| @@ -4872,6 +4956,12 @@ enum { | |||
| 4872 | ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, | 4956 | ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, |
| 4873 | ALC269_FIXUP_ATIV_BOOK_8, | 4957 | ALC269_FIXUP_ATIV_BOOK_8, |
| 4874 | ALC221_FIXUP_HP_MIC_NO_PRESENCE, | 4958 | ALC221_FIXUP_HP_MIC_NO_PRESENCE, |
| 4959 | ALC256_FIXUP_ASUS_HEADSET_MODE, | ||
| 4960 | ALC256_FIXUP_ASUS_MIC, | ||
| 4961 | ALC256_FIXUP_ASUS_AIO_GPIO2, | ||
| 4962 | ALC233_FIXUP_ASUS_MIC_NO_PRESENCE, | ||
| 4963 | ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE, | ||
| 4964 | ALC233_FIXUP_LENOVO_MULTI_CODECS, | ||
| 4875 | }; | 4965 | }; |
| 4876 | 4966 | ||
| 4877 | static const struct hda_fixup alc269_fixups[] = { | 4967 | static const struct hda_fixup alc269_fixups[] = { |
| @@ -5289,6 +5379,24 @@ static const struct hda_fixup alc269_fixups[] = { | |||
| 5289 | .chained = true, | 5379 | .chained = true, |
| 5290 | .chain_id = ALC269_FIXUP_THINKPAD_ACPI, | 5380 | .chain_id = ALC269_FIXUP_THINKPAD_ACPI, |
| 5291 | }, | 5381 | }, |
| 5382 | [ALC255_FIXUP_ACER_MIC_NO_PRESENCE] = { | ||
| 5383 | .type = HDA_FIXUP_PINS, | ||
| 5384 | .v.pins = (const struct hda_pintbl[]) { | ||
| 5385 | { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ | ||
| 5386 | { } | ||
| 5387 | }, | ||
| 5388 | .chained = true, | ||
| 5389 | .chain_id = ALC255_FIXUP_HEADSET_MODE | ||
| 5390 | }, | ||
| 5391 | [ALC255_FIXUP_ASUS_MIC_NO_PRESENCE] = { | ||
| 5392 | .type = HDA_FIXUP_PINS, | ||
| 5393 | .v.pins = (const struct hda_pintbl[]) { | ||
| 5394 | { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ | ||
| 5395 | { } | ||
| 5396 | }, | ||
| 5397 | .chained = true, | ||
| 5398 | .chain_id = ALC255_FIXUP_HEADSET_MODE | ||
| 5399 | }, | ||
| 5292 | [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = { | 5400 | [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = { |
| 5293 | .type = HDA_FIXUP_PINS, | 5401 | .type = HDA_FIXUP_PINS, |
| 5294 | .v.pins = (const struct hda_pintbl[]) { | 5402 | .v.pins = (const struct hda_pintbl[]) { |
| @@ -5579,6 +5687,54 @@ static const struct hda_fixup alc269_fixups[] = { | |||
| 5579 | .chained = true, | 5687 | .chained = true, |
| 5580 | .chain_id = ALC269_FIXUP_HEADSET_MODE | 5688 | .chain_id = ALC269_FIXUP_HEADSET_MODE |
| 5581 | }, | 5689 | }, |
| 5690 | [ALC256_FIXUP_ASUS_HEADSET_MODE] = { | ||
| 5691 | .type = HDA_FIXUP_FUNC, | ||
| 5692 | .v.func = alc_fixup_headset_mode, | ||
| 5693 | }, | ||
| 5694 | [ALC256_FIXUP_ASUS_MIC] = { | ||
| 5695 | .type = HDA_FIXUP_PINS, | ||
| 5696 | .v.pins = (const struct hda_pintbl[]) { | ||
| 5697 | { 0x13, 0x90a60160 }, /* use as internal mic */ | ||
| 5698 | { 0x19, 0x04a11120 }, /* use as headset mic, without its own jack detect */ | ||
| 5699 | { } | ||
| 5700 | }, | ||
| 5701 | .chained = true, | ||
| 5702 | .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE | ||
| 5703 | }, | ||
| 5704 | [ALC256_FIXUP_ASUS_AIO_GPIO2] = { | ||
| 5705 | .type = HDA_FIXUP_VERBS, | ||
| 5706 | .v.verbs = (const struct hda_verb[]) { | ||
| 5707 | /* Set up GPIO2 for the speaker amp */ | ||
| 5708 | { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 }, | ||
| 5709 | { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 }, | ||
| 5710 | { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 }, | ||
| 5711 | {} | ||
| 5712 | }, | ||
| 5713 | }, | ||
| 5714 | [ALC233_FIXUP_ASUS_MIC_NO_PRESENCE] = { | ||
| 5715 | .type = HDA_FIXUP_PINS, | ||
| 5716 | .v.pins = (const struct hda_pintbl[]) { | ||
| 5717 | { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ | ||
| 5718 | { } | ||
| 5719 | }, | ||
| 5720 | .chained = true, | ||
| 5721 | .chain_id = ALC269_FIXUP_HEADSET_MIC | ||
| 5722 | }, | ||
| 5723 | [ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE] = { | ||
| 5724 | .type = HDA_FIXUP_VERBS, | ||
| 5725 | .v.verbs = (const struct hda_verb[]) { | ||
| 5726 | /* Enables internal speaker */ | ||
| 5727 | {0x20, AC_VERB_SET_COEF_INDEX, 0x40}, | ||
| 5728 | {0x20, AC_VERB_SET_PROC_COEF, 0x8800}, | ||
| 5729 | {} | ||
| 5730 | }, | ||
| 5731 | .chained = true, | ||
| 5732 | .chain_id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE | ||
| 5733 | }, | ||
| 5734 | [ALC233_FIXUP_LENOVO_MULTI_CODECS] = { | ||
| 5735 | .type = HDA_FIXUP_FUNC, | ||
| 5736 | .v.func = alc233_alc662_fixup_lenovo_dual_codecs, | ||
| 5737 | }, | ||
| 5582 | }; | 5738 | }; |
| 5583 | 5739 | ||
| 5584 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { | 5740 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { |
| @@ -5692,15 +5848,27 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
| 5692 | SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC), | 5848 | SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC), |
| 5693 | SND_PCI_QUIRK(0x103c, 0x82bf, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), | 5849 | SND_PCI_QUIRK(0x103c, 0x82bf, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), |
| 5694 | SND_PCI_QUIRK(0x103c, 0x82c0, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), | 5850 | SND_PCI_QUIRK(0x103c, 0x82c0, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), |
| 5851 | SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), | ||
| 5695 | SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), | 5852 | SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), |
| 5696 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 5853 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
| 5854 | SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), | ||
| 5697 | SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 5855 | SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
| 5856 | SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC), | ||
| 5857 | SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC), | ||
| 5858 | SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), | ||
| 5698 | SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), | 5859 | SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), |
| 5699 | SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), | 5860 | SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), |
| 5700 | SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), | 5861 | SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), |
| 5701 | SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), | 5862 | SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), |
| 5702 | SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), | 5863 | SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), |
| 5703 | SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 5864 | SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
| 5865 | SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), | ||
| 5866 | SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), | ||
| 5867 | SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), | ||
| 5868 | SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), | ||
| 5869 | SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), | ||
| 5870 | SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), | ||
| 5871 | SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), | ||
| 5704 | SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), | 5872 | SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), |
| 5705 | SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), | 5873 | SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), |
| 5706 | SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), | 5874 | SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), |
| @@ -5721,6 +5889,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
| 5721 | SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), | 5889 | SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), |
| 5722 | SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), | 5890 | SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), |
| 5723 | SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), | 5891 | SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), |
| 5892 | SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS), | ||
| 5724 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), | 5893 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), |
| 5725 | SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), | 5894 | SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), |
| 5726 | SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), | 5895 | SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), |
| @@ -5875,6 +6044,18 @@ static const struct hda_model_fixup alc269_fixup_models[] = { | |||
| 5875 | {0x21, 0x03211020} | 6044 | {0x21, 0x03211020} |
| 5876 | 6045 | ||
| 5877 | static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { | 6046 | static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { |
| 6047 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1025, "Acer", ALC255_FIXUP_ACER_MIC_NO_PRESENCE, | ||
| 6048 | {0x12, 0x90a601c0}, | ||
| 6049 | {0x14, 0x90171120}, | ||
| 6050 | {0x21, 0x02211030}), | ||
| 6051 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, | ||
| 6052 | {0x14, 0x90170110}, | ||
| 6053 | {0x1b, 0x90a70130}, | ||
| 6054 | {0x21, 0x03211020}), | ||
| 6055 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, | ||
| 6056 | {0x1a, 0x90a70130}, | ||
| 6057 | {0x1b, 0x90170110}, | ||
| 6058 | {0x21, 0x03211020}), | ||
| 5878 | SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, | 6059 | SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, |
| 5879 | ALC225_STANDARD_PINS, | 6060 | ALC225_STANDARD_PINS, |
| 5880 | {0x12, 0xb7a60130}, | 6061 | {0x12, 0xb7a60130}, |
| @@ -5995,6 +6176,14 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { | |||
| 5995 | {0x21, 0x02211020}), | 6176 | {0x21, 0x02211020}), |
| 5996 | SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 6177 | SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
| 5997 | ALC256_STANDARD_PINS), | 6178 | ALC256_STANDARD_PINS), |
| 6179 | SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC, | ||
| 6180 | {0x14, 0x90170110}, | ||
| 6181 | {0x1b, 0x90a70130}, | ||
| 6182 | {0x21, 0x04211020}), | ||
| 6183 | SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC, | ||
| 6184 | {0x14, 0x90170110}, | ||
| 6185 | {0x1b, 0x90a70130}, | ||
| 6186 | {0x21, 0x03211020}), | ||
| 5998 | SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4, | 6187 | SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4, |
| 5999 | {0x12, 0x90a60130}, | 6188 | {0x12, 0x90a60130}, |
| 6000 | {0x14, 0x90170110}, | 6189 | {0x14, 0x90170110}, |
| @@ -6714,6 +6903,7 @@ enum { | |||
| 6714 | ALC668_FIXUP_DELL_DISABLE_AAMIX, | 6903 | ALC668_FIXUP_DELL_DISABLE_AAMIX, |
| 6715 | ALC668_FIXUP_DELL_XPS13, | 6904 | ALC668_FIXUP_DELL_XPS13, |
| 6716 | ALC662_FIXUP_ASUS_Nx50, | 6905 | ALC662_FIXUP_ASUS_Nx50, |
| 6906 | ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, | ||
| 6717 | ALC668_FIXUP_ASUS_Nx51, | 6907 | ALC668_FIXUP_ASUS_Nx51, |
| 6718 | ALC891_FIXUP_HEADSET_MODE, | 6908 | ALC891_FIXUP_HEADSET_MODE, |
| 6719 | ALC891_FIXUP_DELL_MIC_NO_PRESENCE, | 6909 | ALC891_FIXUP_DELL_MIC_NO_PRESENCE, |
| @@ -6721,6 +6911,7 @@ enum { | |||
| 6721 | ALC892_FIXUP_ASROCK_MOBO, | 6911 | ALC892_FIXUP_ASROCK_MOBO, |
| 6722 | ALC662_FIXUP_USI_FUNC, | 6912 | ALC662_FIXUP_USI_FUNC, |
| 6723 | ALC662_FIXUP_USI_HEADSET_MODE, | 6913 | ALC662_FIXUP_USI_HEADSET_MODE, |
| 6914 | ALC662_FIXUP_LENOVO_MULTI_CODECS, | ||
| 6724 | }; | 6915 | }; |
| 6725 | 6916 | ||
| 6726 | static const struct hda_fixup alc662_fixups[] = { | 6917 | static const struct hda_fixup alc662_fixups[] = { |
| @@ -6967,14 +7158,21 @@ static const struct hda_fixup alc662_fixups[] = { | |||
| 6967 | .chained = true, | 7158 | .chained = true, |
| 6968 | .chain_id = ALC662_FIXUP_BASS_1A | 7159 | .chain_id = ALC662_FIXUP_BASS_1A |
| 6969 | }, | 7160 | }, |
| 7161 | [ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = { | ||
| 7162 | .type = HDA_FIXUP_FUNC, | ||
| 7163 | .v.func = alc_fixup_headset_mode_alc668, | ||
| 7164 | .chain_id = ALC662_FIXUP_BASS_CHMAP | ||
| 7165 | }, | ||
| 6970 | [ALC668_FIXUP_ASUS_Nx51] = { | 7166 | [ALC668_FIXUP_ASUS_Nx51] = { |
| 6971 | .type = HDA_FIXUP_PINS, | 7167 | .type = HDA_FIXUP_PINS, |
| 6972 | .v.pins = (const struct hda_pintbl[]) { | 7168 | .v.pins = (const struct hda_pintbl[]) { |
| 6973 | {0x1a, 0x90170151}, /* bass speaker */ | 7169 | { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ |
| 7170 | { 0x1a, 0x90170151 }, /* bass speaker */ | ||
| 7171 | { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ | ||
| 6974 | {} | 7172 | {} |
| 6975 | }, | 7173 | }, |
| 6976 | .chained = true, | 7174 | .chained = true, |
| 6977 | .chain_id = ALC662_FIXUP_BASS_CHMAP, | 7175 | .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, |
| 6978 | }, | 7176 | }, |
| 6979 | [ALC891_FIXUP_HEADSET_MODE] = { | 7177 | [ALC891_FIXUP_HEADSET_MODE] = { |
| 6980 | .type = HDA_FIXUP_FUNC, | 7178 | .type = HDA_FIXUP_FUNC, |
| @@ -7019,6 +7217,10 @@ static const struct hda_fixup alc662_fixups[] = { | |||
| 7019 | .chained = true, | 7217 | .chained = true, |
| 7020 | .chain_id = ALC662_FIXUP_USI_FUNC | 7218 | .chain_id = ALC662_FIXUP_USI_FUNC |
| 7021 | }, | 7219 | }, |
| 7220 | [ALC662_FIXUP_LENOVO_MULTI_CODECS] = { | ||
| 7221 | .type = HDA_FIXUP_FUNC, | ||
| 7222 | .v.func = alc233_alc662_fixup_lenovo_dual_codecs, | ||
| 7223 | }, | ||
| 7022 | }; | 7224 | }; |
| 7023 | 7225 | ||
| 7024 | static const struct snd_pci_quirk alc662_fixup_tbl[] = { | 7226 | static const struct snd_pci_quirk alc662_fixup_tbl[] = { |
| @@ -7056,6 +7258,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { | |||
| 7056 | SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), | 7258 | SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), |
| 7057 | SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), | 7259 | SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), |
| 7058 | SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE), | 7260 | SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE), |
| 7261 | SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS), | ||
| 7059 | SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), | 7262 | SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), |
| 7060 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), | 7263 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), |
| 7061 | SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO), | 7264 | SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO), |
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 3bfdc78cbc5f..da5f37b7fdd0 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c | |||
| @@ -432,7 +432,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco | |||
| 432 | return 0; | 432 | return 0; |
| 433 | } | 433 | } |
| 434 | 434 | ||
| 435 | static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status = | 435 | static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status = |
| 436 | { | 436 | { |
| 437 | .access = (SNDRV_CTL_ELEM_ACCESS_READ), | 437 | .access = (SNDRV_CTL_ELEM_ACCESS_READ), |
| 438 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 438 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 5cb587cf360e..ec07136fc288 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c | |||
| @@ -719,7 +719,7 @@ static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, st | |||
| 719 | return ndata != data; | 719 | return ndata != data; |
| 720 | } | 720 | } |
| 721 | 721 | ||
| 722 | static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense = { | 722 | static const struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense = { |
| 723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 724 | .name = "Input Sensitivity Switch", | 724 | .name = "Input Sensitivity Switch", |
| 725 | .info = snd_ice1712_ewx_io_sense_info, | 725 | .info = snd_ice1712_ewx_io_sense_info, |
| @@ -728,7 +728,7 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense = { | |||
| 728 | .count = 8, | 728 | .count = 8, |
| 729 | }; | 729 | }; |
| 730 | 730 | ||
| 731 | static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense = { | 731 | static const struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense = { |
| 732 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 732 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 733 | .name = "Output Sensitivity Switch", | 733 | .name = "Output Sensitivity Switch", |
| 734 | .info = snd_ice1712_ewx_io_sense_info, | 734 | .info = snd_ice1712_ewx_io_sense_info, |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index b4aa4c1370a8..1d8612cabb9e 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
| @@ -279,7 +279,7 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru | |||
| 279 | return val != nval; | 279 | return val != nval; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 = { | 282 | static const struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 = { |
| 283 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 283 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 284 | .name = "Digital Mixer To AC97", | 284 | .name = "Digital Mixer To AC97", |
| 285 | .info = snd_ice1712_digmix_route_ac97_info, | 285 | .info = snd_ice1712_digmix_route_ac97_info, |
| @@ -1410,7 +1410,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch = { | |||
| 1410 | .private_value = 10, | 1410 | .private_value = 10, |
| 1411 | }; | 1411 | }; |
| 1412 | 1412 | ||
| 1413 | static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch = { | 1413 | static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch = { |
| 1414 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1414 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1415 | .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, SWITCH), | 1415 | .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, SWITCH), |
| 1416 | .info = snd_ice1712_pro_mixer_switch_info, | 1416 | .info = snd_ice1712_pro_mixer_switch_info, |
| @@ -1432,7 +1432,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume = { | |||
| 1432 | .tlv = { .p = db_scale_playback } | 1432 | .tlv = { .p = db_scale_playback } |
| 1433 | }; | 1433 | }; |
| 1434 | 1434 | ||
| 1435 | static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume = { | 1435 | static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume = { |
| 1436 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1436 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1437 | .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, VOLUME), | 1437 | .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, VOLUME), |
| 1438 | .info = snd_ice1712_pro_mixer_volume_info, | 1438 | .info = snd_ice1712_pro_mixer_volume_info, |
| @@ -1630,7 +1630,7 @@ static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol, | |||
| 1630 | return 0; | 1630 | return 0; |
| 1631 | } | 1631 | } |
| 1632 | 1632 | ||
| 1633 | static struct snd_kcontrol_new snd_ice1712_eeprom = { | 1633 | static const struct snd_kcontrol_new snd_ice1712_eeprom = { |
| 1634 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 1634 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
| 1635 | .name = "ICE1712 EEPROM", | 1635 | .name = "ICE1712 EEPROM", |
| 1636 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1636 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| @@ -1666,7 +1666,7 @@ static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
| 1666 | return 0; | 1666 | return 0; |
| 1667 | } | 1667 | } |
| 1668 | 1668 | ||
| 1669 | static struct snd_kcontrol_new snd_ice1712_spdif_default = | 1669 | static const struct snd_kcontrol_new snd_ice1712_spdif_default = |
| 1670 | { | 1670 | { |
| 1671 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1671 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1672 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | 1672 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), |
| @@ -1717,7 +1717,7 @@ static int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol, | |||
| 1717 | return 0; | 1717 | return 0; |
| 1718 | } | 1718 | } |
| 1719 | 1719 | ||
| 1720 | static struct snd_kcontrol_new snd_ice1712_spdif_maskc = | 1720 | static const struct snd_kcontrol_new snd_ice1712_spdif_maskc = |
| 1721 | { | 1721 | { |
| 1722 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1722 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1723 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1723 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1726,7 +1726,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskc = | |||
| 1726 | .get = snd_ice1712_spdif_maskc_get, | 1726 | .get = snd_ice1712_spdif_maskc_get, |
| 1727 | }; | 1727 | }; |
| 1728 | 1728 | ||
| 1729 | static struct snd_kcontrol_new snd_ice1712_spdif_maskp = | 1729 | static const struct snd_kcontrol_new snd_ice1712_spdif_maskp = |
| 1730 | { | 1730 | { |
| 1731 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1731 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1732 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1732 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1753,7 +1753,7 @@ static int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol, | |||
| 1753 | return 0; | 1753 | return 0; |
| 1754 | } | 1754 | } |
| 1755 | 1755 | ||
| 1756 | static struct snd_kcontrol_new snd_ice1712_spdif_stream = | 1756 | static const struct snd_kcontrol_new snd_ice1712_spdif_stream = |
| 1757 | { | 1757 | { |
| 1758 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 1758 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 1759 | SNDRV_CTL_ELEM_ACCESS_INACTIVE), | 1759 | SNDRV_CTL_ELEM_ACCESS_INACTIVE), |
| @@ -1878,7 +1878,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, | |||
| 1878 | return change; | 1878 | return change; |
| 1879 | } | 1879 | } |
| 1880 | 1880 | ||
| 1881 | static struct snd_kcontrol_new snd_ice1712_pro_internal_clock = { | 1881 | static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock = { |
| 1882 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1882 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1883 | .name = "Multi Track Internal Clock", | 1883 | .name = "Multi Track Internal Clock", |
| 1884 | .info = snd_ice1712_pro_internal_clock_info, | 1884 | .info = snd_ice1712_pro_internal_clock_info, |
| @@ -1943,7 +1943,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont | |||
| 1943 | return change; | 1943 | return change; |
| 1944 | } | 1944 | } |
| 1945 | 1945 | ||
| 1946 | static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default = { | 1946 | static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default = { |
| 1947 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1947 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1948 | .name = "Multi Track Internal Clock Default", | 1948 | .name = "Multi Track Internal Clock Default", |
| 1949 | .info = snd_ice1712_pro_internal_clock_default_info, | 1949 | .info = snd_ice1712_pro_internal_clock_default_info, |
| @@ -1974,7 +1974,7 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol, | |||
| 1974 | return change; | 1974 | return change; |
| 1975 | } | 1975 | } |
| 1976 | 1976 | ||
| 1977 | static struct snd_kcontrol_new snd_ice1712_pro_rate_locking = { | 1977 | static const struct snd_kcontrol_new snd_ice1712_pro_rate_locking = { |
| 1978 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1978 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1979 | .name = "Multi Track Rate Locking", | 1979 | .name = "Multi Track Rate Locking", |
| 1980 | .info = snd_ice1712_pro_rate_locking_info, | 1980 | .info = snd_ice1712_pro_rate_locking_info, |
| @@ -2005,7 +2005,7 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol, | |||
| 2005 | return change; | 2005 | return change; |
| 2006 | } | 2006 | } |
| 2007 | 2007 | ||
| 2008 | static struct snd_kcontrol_new snd_ice1712_pro_rate_reset = { | 2008 | static const struct snd_kcontrol_new snd_ice1712_pro_rate_reset = { |
| 2009 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2009 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2010 | .name = "Multi Track Rate Reset", | 2010 | .name = "Multi Track Rate Reset", |
| 2011 | .info = snd_ice1712_pro_rate_reset_info, | 2011 | .info = snd_ice1712_pro_rate_reset_info, |
| @@ -2173,7 +2173,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route = { | |||
| 2173 | .put = snd_ice1712_pro_route_analog_put, | 2173 | .put = snd_ice1712_pro_route_analog_put, |
| 2174 | }; | 2174 | }; |
| 2175 | 2175 | ||
| 2176 | static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route = { | 2176 | static const struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route = { |
| 2177 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2177 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2178 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", | 2178 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", |
| 2179 | .info = snd_ice1712_pro_route_info, | 2179 | .info = snd_ice1712_pro_route_info, |
| @@ -2215,7 +2215,7 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol, | |||
| 2215 | return change; | 2215 | return change; |
| 2216 | } | 2216 | } |
| 2217 | 2217 | ||
| 2218 | static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate = { | 2218 | static const struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate = { |
| 2219 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2219 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2220 | .name = "Multi Track Volume Rate", | 2220 | .name = "Multi Track Volume Rate", |
| 2221 | .info = snd_ice1712_pro_volume_rate_info, | 2221 | .info = snd_ice1712_pro_volume_rate_info, |
| @@ -2248,7 +2248,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol, | |||
| 2248 | return 0; | 2248 | return 0; |
| 2249 | } | 2249 | } |
| 2250 | 2250 | ||
| 2251 | static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak = { | 2251 | static const struct snd_kcontrol_new snd_ice1712_mixer_pro_peak = { |
| 2252 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 2252 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 2253 | .name = "Multi Track Peak", | 2253 | .name = "Multi Track Peak", |
| 2254 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 2254 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 842744e7a139..9cd6e55c0642 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
| @@ -1598,7 +1598,7 @@ static int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol, | |||
| 1598 | return 0; | 1598 | return 0; |
| 1599 | } | 1599 | } |
| 1600 | 1600 | ||
| 1601 | static struct snd_kcontrol_new snd_vt1724_eeprom = { | 1601 | static const struct snd_kcontrol_new snd_vt1724_eeprom = { |
| 1602 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 1602 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
| 1603 | .name = "ICE1724 EEPROM", | 1603 | .name = "ICE1724 EEPROM", |
| 1604 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1604 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| @@ -1711,7 +1711,7 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
| 1711 | return val != old; | 1711 | return val != old; |
| 1712 | } | 1712 | } |
| 1713 | 1713 | ||
| 1714 | static struct snd_kcontrol_new snd_vt1724_spdif_default = | 1714 | static const struct snd_kcontrol_new snd_vt1724_spdif_default = |
| 1715 | { | 1715 | { |
| 1716 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1716 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1717 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | 1717 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), |
| @@ -1743,7 +1743,7 @@ static int snd_vt1724_spdif_maskp_get(struct snd_kcontrol *kcontrol, | |||
| 1743 | return 0; | 1743 | return 0; |
| 1744 | } | 1744 | } |
| 1745 | 1745 | ||
| 1746 | static struct snd_kcontrol_new snd_vt1724_spdif_maskc = | 1746 | static const struct snd_kcontrol_new snd_vt1724_spdif_maskc = |
| 1747 | { | 1747 | { |
| 1748 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1748 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1749 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1749 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1752,7 +1752,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskc = | |||
| 1752 | .get = snd_vt1724_spdif_maskc_get, | 1752 | .get = snd_vt1724_spdif_maskc_get, |
| 1753 | }; | 1753 | }; |
| 1754 | 1754 | ||
| 1755 | static struct snd_kcontrol_new snd_vt1724_spdif_maskp = | 1755 | static const struct snd_kcontrol_new snd_vt1724_spdif_maskp = |
| 1756 | { | 1756 | { |
| 1757 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1757 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1758 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1758 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1789,7 +1789,7 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol, | |||
| 1789 | return old != val; | 1789 | return old != val; |
| 1790 | } | 1790 | } |
| 1791 | 1791 | ||
| 1792 | static struct snd_kcontrol_new snd_vt1724_spdif_switch = | 1792 | static const struct snd_kcontrol_new snd_vt1724_spdif_switch = |
| 1793 | { | 1793 | { |
| 1794 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1794 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1795 | /* FIXME: the following conflict with IEC958 Playback Route */ | 1795 | /* FIXME: the following conflict with IEC958 Playback Route */ |
| @@ -1964,7 +1964,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol, | |||
| 1964 | return old_rate != new_rate; | 1964 | return old_rate != new_rate; |
| 1965 | } | 1965 | } |
| 1966 | 1966 | ||
| 1967 | static struct snd_kcontrol_new snd_vt1724_pro_internal_clock = { | 1967 | static const struct snd_kcontrol_new snd_vt1724_pro_internal_clock = { |
| 1968 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1968 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1969 | .name = "Multi Track Internal Clock", | 1969 | .name = "Multi Track Internal Clock", |
| 1970 | .info = snd_vt1724_pro_internal_clock_info, | 1970 | .info = snd_vt1724_pro_internal_clock_info, |
| @@ -1995,7 +1995,7 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol, | |||
| 1995 | return change; | 1995 | return change; |
| 1996 | } | 1996 | } |
| 1997 | 1997 | ||
| 1998 | static struct snd_kcontrol_new snd_vt1724_pro_rate_locking = { | 1998 | static const struct snd_kcontrol_new snd_vt1724_pro_rate_locking = { |
| 1999 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1999 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2000 | .name = "Multi Track Rate Locking", | 2000 | .name = "Multi Track Rate Locking", |
| 2001 | .info = snd_vt1724_pro_rate_locking_info, | 2001 | .info = snd_vt1724_pro_rate_locking_info, |
| @@ -2026,7 +2026,7 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol, | |||
| 2026 | return change; | 2026 | return change; |
| 2027 | } | 2027 | } |
| 2028 | 2028 | ||
| 2029 | static struct snd_kcontrol_new snd_vt1724_pro_rate_reset = { | 2029 | static const struct snd_kcontrol_new snd_vt1724_pro_rate_reset = { |
| 2030 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2030 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2031 | .name = "Multi Track Rate Reset", | 2031 | .name = "Multi Track Rate Reset", |
| 2032 | .info = snd_vt1724_pro_rate_reset_info, | 2032 | .info = snd_vt1724_pro_rate_reset_info, |
| @@ -2151,7 +2151,7 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route = | |||
| 2151 | .put = snd_vt1724_pro_route_analog_put, | 2151 | .put = snd_vt1724_pro_route_analog_put, |
| 2152 | }; | 2152 | }; |
| 2153 | 2153 | ||
| 2154 | static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route = { | 2154 | static const struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route = { |
| 2155 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2155 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2156 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", | 2156 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", |
| 2157 | .info = snd_vt1724_pro_route_info, | 2157 | .info = snd_vt1724_pro_route_info, |
| @@ -2187,7 +2187,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol, | |||
| 2187 | return 0; | 2187 | return 0; |
| 2188 | } | 2188 | } |
| 2189 | 2189 | ||
| 2190 | static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak = { | 2190 | static const struct snd_kcontrol_new snd_vt1724_mixer_pro_peak = { |
| 2191 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 2191 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 2192 | .name = "Multi Track Peak", | 2192 | .name = "Multi Track Peak", |
| 2193 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 2193 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c index e7fe15dd5a90..cb25acf7bc49 100644 --- a/sound/pci/lola/lola_mixer.c +++ b/sound/pci/lola/lola_mixer.c | |||
| @@ -645,7 +645,7 @@ static int lola_input_src_put(struct snd_kcontrol *kcontrol, | |||
| 645 | return lola_set_src_config(chip, mask, true); | 645 | return lola_set_src_config(chip, mask, true); |
| 646 | } | 646 | } |
| 647 | 647 | ||
| 648 | static struct snd_kcontrol_new lola_input_src_mixer = { | 648 | static const struct snd_kcontrol_new lola_input_src_mixer = { |
| 649 | .name = "Digital SRC Capture Switch", | 649 | .name = "Digital SRC Capture Switch", |
| 650 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 650 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 651 | .info = lola_input_src_info, | 651 | .info = lola_input_src_info, |
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index c0f0c349c3ec..f9c3e86d55d5 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c | |||
| @@ -899,7 +899,7 @@ static int lx_control_playback_put(struct snd_kcontrol *kcontrol, | |||
| 899 | return changed; | 899 | return changed; |
| 900 | } | 900 | } |
| 901 | 901 | ||
| 902 | static struct snd_kcontrol_new lx_control_playback_switch = { | 902 | static const struct snd_kcontrol_new lx_control_playback_switch = { |
| 903 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 903 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 904 | .name = "PCM Playback Switch", | 904 | .name = "PCM Playback Switch", |
| 905 | .index = 0, | 905 | .index = 0, |
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 51e53497f0ad..4a4616aac787 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c | |||
| @@ -448,7 +448,7 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
| 448 | return changed; | 448 | return changed; |
| 449 | } | 449 | } |
| 450 | 450 | ||
| 451 | static struct snd_kcontrol_new mixart_control_output_switch = { | 451 | static const struct snd_kcontrol_new mixart_control_output_switch = { |
| 452 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 452 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 453 | .name = "Master Playback Switch", | 453 | .name = "Master Playback Switch", |
| 454 | .info = mixart_sw_info, /* shared */ | 454 | .info = mixart_sw_info, /* shared */ |
| @@ -1024,7 +1024,7 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
| 1024 | return changed; | 1024 | return changed; |
| 1025 | } | 1025 | } |
| 1026 | 1026 | ||
| 1027 | static struct snd_kcontrol_new mixart_control_monitor_vol = { | 1027 | static const struct snd_kcontrol_new mixart_control_monitor_vol = { |
| 1028 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1028 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1029 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 1029 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 1030 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | 1030 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
| @@ -1091,7 +1091,7 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
| 1091 | return (changed != 0); | 1091 | return (changed != 0); |
| 1092 | } | 1092 | } |
| 1093 | 1093 | ||
| 1094 | static struct snd_kcontrol_new mixart_control_monitor_sw = { | 1094 | static const struct snd_kcontrol_new mixart_control_monitor_sw = { |
| 1095 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1095 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1096 | .name = "Monitoring Switch", | 1096 | .name = "Monitoring Switch", |
| 1097 | .info = mixart_sw_info, /* shared */ | 1097 | .info = mixart_sw_info, /* shared */ |
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 74afb6b75976..e36ed8af55ad 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
| @@ -767,6 +767,8 @@ static int get_oxygen_model(struct oxygen *chip, | |||
| 767 | [MODEL_FANTASIA] = "TempoTec HiFier Fantasia", | 767 | [MODEL_FANTASIA] = "TempoTec HiFier Fantasia", |
| 768 | [MODEL_SERENADE] = "TempoTec HiFier Serenade", | 768 | [MODEL_SERENADE] = "TempoTec HiFier Serenade", |
| 769 | [MODEL_HG2PCI] = "CMI8787-HG2PCI", | 769 | [MODEL_HG2PCI] = "CMI8787-HG2PCI", |
| 770 | [MODEL_XONAR_DG] = "Xonar DG", | ||
| 771 | [MODEL_XONAR_DGX] = "Xonar DGX", | ||
| 770 | }; | 772 | }; |
| 771 | 773 | ||
| 772 | chip->model = model_generic; | 774 | chip->model = model_generic; |
| @@ -829,12 +831,8 @@ static int get_oxygen_model(struct oxygen *chip, | |||
| 829 | chip->model.dac_channels_mixer = 2; | 831 | chip->model.dac_channels_mixer = 2; |
| 830 | break; | 832 | break; |
| 831 | case MODEL_XONAR_DG: | 833 | case MODEL_XONAR_DG: |
| 832 | chip->model = model_xonar_dg; | ||
| 833 | chip->model.shortname = "Xonar DG"; | ||
| 834 | break; | ||
| 835 | case MODEL_XONAR_DGX: | 834 | case MODEL_XONAR_DGX: |
| 836 | chip->model = model_xonar_dg; | 835 | chip->model = model_xonar_dg; |
| 837 | chip->model.shortname = "Xonar DGX"; | ||
| 838 | break; | 836 | break; |
| 839 | } | 837 | } |
| 840 | if (id->driver_data == MODEL_MERIDIAN || | 838 | if (id->driver_data == MODEL_MERIDIAN || |
diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c index 6a56e5306a65..8b4d0282efb8 100644 --- a/sound/pci/pcxhr/pcxhr_mix22.c +++ b/sound/pci/pcxhr/pcxhr_mix22.c | |||
| @@ -744,7 +744,7 @@ static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol, | |||
| 744 | return changed; | 744 | return changed; |
| 745 | } | 745 | } |
| 746 | 746 | ||
| 747 | static struct snd_kcontrol_new hr222_control_mic_level = { | 747 | static const struct snd_kcontrol_new hr222_control_mic_level = { |
| 748 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 748 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 749 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 749 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 750 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | 750 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
| @@ -794,7 +794,7 @@ static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol, | |||
| 794 | return changed; | 794 | return changed; |
| 795 | } | 795 | } |
| 796 | 796 | ||
| 797 | static struct snd_kcontrol_new hr222_control_mic_boost = { | 797 | static const struct snd_kcontrol_new hr222_control_mic_boost = { |
| 798 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 798 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 799 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 799 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 800 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | 800 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
| @@ -836,7 +836,7 @@ static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol, | |||
| 836 | return changed; | 836 | return changed; |
| 837 | } | 837 | } |
| 838 | 838 | ||
| 839 | static struct snd_kcontrol_new hr222_phantom_power_switch = { | 839 | static const struct snd_kcontrol_new hr222_phantom_power_switch = { |
| 840 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 840 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 841 | .name = "Phantom Power Switch", | 841 | .name = "Phantom Power Switch", |
| 842 | .info = hr222_phantom_power_info, | 842 | .info = hr222_phantom_power_info, |
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index 63136c4f3f3d..36875df30dbf 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c | |||
| @@ -235,7 +235,7 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, | |||
| 235 | return changed; | 235 | return changed; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | static struct snd_kcontrol_new pcxhr_control_output_switch = { | 238 | static const struct snd_kcontrol_new pcxhr_control_output_switch = { |
| 239 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 239 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 240 | .name = "Master Playback Switch", | 240 | .name = "Master Playback Switch", |
| 241 | .info = pcxhr_sw_info, /* shared */ | 241 | .info = pcxhr_sw_info, /* shared */ |
| @@ -460,7 +460,7 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, | |||
| 460 | return changed; | 460 | return changed; |
| 461 | } | 461 | } |
| 462 | 462 | ||
| 463 | static struct snd_kcontrol_new pcxhr_control_pcm_switch = { | 463 | static const struct snd_kcontrol_new pcxhr_control_pcm_switch = { |
| 464 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 464 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 465 | .name = "PCM Playback Switch", | 465 | .name = "PCM Playback Switch", |
| 466 | .count = PCXHR_PLAYBACK_STREAMS, | 466 | .count = PCXHR_PLAYBACK_STREAMS, |
| @@ -509,7 +509,7 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, | |||
| 509 | return changed; | 509 | return changed; |
| 510 | } | 510 | } |
| 511 | 511 | ||
| 512 | static struct snd_kcontrol_new pcxhr_control_monitor_vol = { | 512 | static const struct snd_kcontrol_new pcxhr_control_monitor_vol = { |
| 513 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 513 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 514 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 514 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 515 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | 515 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
| @@ -562,7 +562,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, | |||
| 562 | return (changed != 0); | 562 | return (changed != 0); |
| 563 | } | 563 | } |
| 564 | 564 | ||
| 565 | static struct snd_kcontrol_new pcxhr_control_monitor_sw = { | 565 | static const struct snd_kcontrol_new pcxhr_control_monitor_sw = { |
| 566 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 566 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 567 | .name = "Monitoring Playback Switch", | 567 | .name = "Monitoring Playback Switch", |
| 568 | .info = pcxhr_sw_info, /* shared */ | 568 | .info = pcxhr_sw_info, /* shared */ |
| @@ -697,7 +697,7 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, | |||
| 697 | return ret; | 697 | return ret; |
| 698 | } | 698 | } |
| 699 | 699 | ||
| 700 | static struct snd_kcontrol_new pcxhr_control_audio_src = { | 700 | static const struct snd_kcontrol_new pcxhr_control_audio_src = { |
| 701 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 701 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 702 | .name = "Capture Source", | 702 | .name = "Capture Source", |
| 703 | .info = pcxhr_audio_src_info, | 703 | .info = pcxhr_audio_src_info, |
| @@ -798,7 +798,7 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, | |||
| 798 | return ret; | 798 | return ret; |
| 799 | } | 799 | } |
| 800 | 800 | ||
| 801 | static struct snd_kcontrol_new pcxhr_control_clock_type = { | 801 | static const struct snd_kcontrol_new pcxhr_control_clock_type = { |
| 802 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 802 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 803 | .name = "Clock Mode", | 803 | .name = "Clock Mode", |
| 804 | .info = pcxhr_clock_type_info, | 804 | .info = pcxhr_clock_type_info, |
| @@ -842,7 +842,7 @@ static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol, | |||
| 842 | return 0; | 842 | return 0; |
| 843 | } | 843 | } |
| 844 | 844 | ||
| 845 | static struct snd_kcontrol_new pcxhr_control_clock_rate = { | 845 | static const struct snd_kcontrol_new pcxhr_control_clock_rate = { |
| 846 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 846 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 847 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 847 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
| 848 | .name = "Clock Rates", | 848 | .name = "Clock Rates", |
| @@ -1017,14 +1017,14 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, | |||
| 1017 | return changed; | 1017 | return changed; |
| 1018 | } | 1018 | } |
| 1019 | 1019 | ||
| 1020 | static struct snd_kcontrol_new pcxhr_control_playback_iec958_mask = { | 1020 | static const struct snd_kcontrol_new pcxhr_control_playback_iec958_mask = { |
| 1021 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1021 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1022 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1022 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1023 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), | 1023 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), |
| 1024 | .info = pcxhr_iec958_info, | 1024 | .info = pcxhr_iec958_info, |
| 1025 | .get = pcxhr_iec958_mask_get | 1025 | .get = pcxhr_iec958_mask_get |
| 1026 | }; | 1026 | }; |
| 1027 | static struct snd_kcontrol_new pcxhr_control_playback_iec958 = { | 1027 | static const struct snd_kcontrol_new pcxhr_control_playback_iec958 = { |
| 1028 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1028 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1029 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | 1029 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), |
| 1030 | .info = pcxhr_iec958_info, | 1030 | .info = pcxhr_iec958_info, |
| @@ -1033,14 +1033,14 @@ static struct snd_kcontrol_new pcxhr_control_playback_iec958 = { | |||
| 1033 | .private_value = 0 /* playback */ | 1033 | .private_value = 0 /* playback */ |
| 1034 | }; | 1034 | }; |
| 1035 | 1035 | ||
| 1036 | static struct snd_kcontrol_new pcxhr_control_capture_iec958_mask = { | 1036 | static const struct snd_kcontrol_new pcxhr_control_capture_iec958_mask = { |
| 1037 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1037 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1038 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1038 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1039 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), | 1039 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), |
| 1040 | .info = pcxhr_iec958_info, | 1040 | .info = pcxhr_iec958_info, |
| 1041 | .get = pcxhr_iec958_mask_get | 1041 | .get = pcxhr_iec958_mask_get |
| 1042 | }; | 1042 | }; |
| 1043 | static struct snd_kcontrol_new pcxhr_control_capture_iec958 = { | 1043 | static const struct snd_kcontrol_new pcxhr_control_capture_iec958 = { |
| 1044 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1044 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1045 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1045 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1046 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), | 1046 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 92ad2d7a6bf8..64d3b8eba4bb 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
| @@ -2356,7 +2356,7 @@ static int snd_trident_spdif_control_put(struct snd_kcontrol *kcontrol, | |||
| 2356 | return change; | 2356 | return change; |
| 2357 | } | 2357 | } |
| 2358 | 2358 | ||
| 2359 | static struct snd_kcontrol_new snd_trident_spdif_control = | 2359 | static const struct snd_kcontrol_new snd_trident_spdif_control = |
| 2360 | { | 2360 | { |
| 2361 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2361 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2362 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), | 2362 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), |
| @@ -2419,7 +2419,7 @@ static int snd_trident_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
| 2419 | return change; | 2419 | return change; |
| 2420 | } | 2420 | } |
| 2421 | 2421 | ||
| 2422 | static struct snd_kcontrol_new snd_trident_spdif_default = | 2422 | static const struct snd_kcontrol_new snd_trident_spdif_default = |
| 2423 | { | 2423 | { |
| 2424 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 2424 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 2425 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | 2425 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), |
| @@ -2452,7 +2452,7 @@ static int snd_trident_spdif_mask_get(struct snd_kcontrol *kcontrol, | |||
| 2452 | return 0; | 2452 | return 0; |
| 2453 | } | 2453 | } |
| 2454 | 2454 | ||
| 2455 | static struct snd_kcontrol_new snd_trident_spdif_mask = | 2455 | static const struct snd_kcontrol_new snd_trident_spdif_mask = |
| 2456 | { | 2456 | { |
| 2457 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 2457 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 2458 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 2458 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -2514,7 +2514,7 @@ static int snd_trident_spdif_stream_put(struct snd_kcontrol *kcontrol, | |||
| 2514 | return change; | 2514 | return change; |
| 2515 | } | 2515 | } |
| 2516 | 2516 | ||
| 2517 | static struct snd_kcontrol_new snd_trident_spdif_stream = | 2517 | static const struct snd_kcontrol_new snd_trident_spdif_stream = |
| 2518 | { | 2518 | { |
| 2519 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | 2519 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
| 2520 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 2520 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -2564,7 +2564,7 @@ static int snd_trident_ac97_control_put(struct snd_kcontrol *kcontrol, | |||
| 2564 | return change; | 2564 | return change; |
| 2565 | } | 2565 | } |
| 2566 | 2566 | ||
| 2567 | static struct snd_kcontrol_new snd_trident_ac97_rear_control = | 2567 | static const struct snd_kcontrol_new snd_trident_ac97_rear_control = |
| 2568 | { | 2568 | { |
| 2569 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2569 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2570 | .name = "Rear Path", | 2570 | .name = "Rear Path", |
| @@ -2622,7 +2622,7 @@ static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, | |||
| 2622 | return change; | 2622 | return change; |
| 2623 | } | 2623 | } |
| 2624 | 2624 | ||
| 2625 | static struct snd_kcontrol_new snd_trident_vol_music_control = | 2625 | static const struct snd_kcontrol_new snd_trident_vol_music_control = |
| 2626 | { | 2626 | { |
| 2627 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2627 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2628 | .name = "Music Playback Volume", | 2628 | .name = "Music Playback Volume", |
| @@ -2633,7 +2633,7 @@ static struct snd_kcontrol_new snd_trident_vol_music_control = | |||
| 2633 | .tlv = { .p = db_scale_gvol }, | 2633 | .tlv = { .p = db_scale_gvol }, |
| 2634 | }; | 2634 | }; |
| 2635 | 2635 | ||
| 2636 | static struct snd_kcontrol_new snd_trident_vol_wave_control = | 2636 | static const struct snd_kcontrol_new snd_trident_vol_wave_control = |
| 2637 | { | 2637 | { |
| 2638 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2638 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2639 | .name = "Wave Playback Volume", | 2639 | .name = "Wave Playback Volume", |
| @@ -2700,7 +2700,7 @@ static int snd_trident_pcm_vol_control_put(struct snd_kcontrol *kcontrol, | |||
| 2700 | return change; | 2700 | return change; |
| 2701 | } | 2701 | } |
| 2702 | 2702 | ||
| 2703 | static struct snd_kcontrol_new snd_trident_pcm_vol_control = | 2703 | static const struct snd_kcontrol_new snd_trident_pcm_vol_control = |
| 2704 | { | 2704 | { |
| 2705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2706 | .name = "PCM Front Playback Volume", | 2706 | .name = "PCM Front Playback Volume", |
| @@ -2764,7 +2764,7 @@ static int snd_trident_pcm_pan_control_put(struct snd_kcontrol *kcontrol, | |||
| 2764 | return change; | 2764 | return change; |
| 2765 | } | 2765 | } |
| 2766 | 2766 | ||
| 2767 | static struct snd_kcontrol_new snd_trident_pcm_pan_control = | 2767 | static const struct snd_kcontrol_new snd_trident_pcm_pan_control = |
| 2768 | { | 2768 | { |
| 2769 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2769 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2770 | .name = "PCM Pan Playback Control", | 2770 | .name = "PCM Pan Playback Control", |
| @@ -2821,7 +2821,7 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol, | |||
| 2821 | 2821 | ||
| 2822 | static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); | 2822 | static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); |
| 2823 | 2823 | ||
| 2824 | static struct snd_kcontrol_new snd_trident_pcm_rvol_control = | 2824 | static const struct snd_kcontrol_new snd_trident_pcm_rvol_control = |
| 2825 | { | 2825 | { |
| 2826 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2826 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2827 | .name = "PCM Reverb Playback Volume", | 2827 | .name = "PCM Reverb Playback Volume", |
| @@ -2877,7 +2877,7 @@ static int snd_trident_pcm_cvol_control_put(struct snd_kcontrol *kcontrol, | |||
| 2877 | return change; | 2877 | return change; |
| 2878 | } | 2878 | } |
| 2879 | 2879 | ||
| 2880 | static struct snd_kcontrol_new snd_trident_pcm_cvol_control = | 2880 | static const struct snd_kcontrol_new snd_trident_pcm_cvol_control = |
| 2881 | { | 2881 | { |
| 2882 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2882 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2883 | .name = "PCM Chorus Playback Volume", | 2883 | .name = "PCM Chorus Playback Volume", |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 2d8c14e3f8d2..d078e86414c2 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
| @@ -1683,7 +1683,7 @@ static int snd_via8233_dxs3_spdif_put(struct snd_kcontrol *kcontrol, | |||
| 1683 | return 0; | 1683 | return 0; |
| 1684 | } | 1684 | } |
| 1685 | 1685 | ||
| 1686 | static struct snd_kcontrol_new snd_via8233_dxs3_spdif_control = { | 1686 | static const struct snd_kcontrol_new snd_via8233_dxs3_spdif_control = { |
| 1687 | .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), | 1687 | .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), |
| 1688 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1688 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1689 | .info = snd_via8233_dxs3_spdif_info, | 1689 | .info = snd_via8233_dxs3_spdif_info, |
| @@ -1772,7 +1772,7 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol, | |||
| 1772 | 1772 | ||
| 1773 | static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -4650, 150, 1); | 1773 | static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -4650, 150, 1); |
| 1774 | 1774 | ||
| 1775 | static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control = { | 1775 | static const struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control = { |
| 1776 | .name = "PCM Playback Volume", | 1776 | .name = "PCM Playback Volume", |
| 1777 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1777 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1778 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 1778 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| @@ -1783,7 +1783,7 @@ static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control = { | |||
| 1783 | .tlv = { .p = db_scale_dxs } | 1783 | .tlv = { .p = db_scale_dxs } |
| 1784 | }; | 1784 | }; |
| 1785 | 1785 | ||
| 1786 | static struct snd_kcontrol_new snd_via8233_dxs_volume_control = { | 1786 | static const struct snd_kcontrol_new snd_via8233_dxs_volume_control = { |
| 1787 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1787 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1788 | .device = 0, | 1788 | .device = 0, |
| 1789 | /* .subdevice set later */ | 1789 | /* .subdevice set later */ |
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 8e457ea27f89..7df1663ea510 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c | |||
| @@ -945,7 +945,7 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
| 945 | return 0; | 945 | return 0; |
| 946 | } | 946 | } |
| 947 | 947 | ||
| 948 | static struct snd_kcontrol_new vx_control_input_level = { | 948 | static const struct snd_kcontrol_new vx_control_input_level = { |
| 949 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 949 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 950 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 950 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 951 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | 951 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
| @@ -956,7 +956,7 @@ static struct snd_kcontrol_new vx_control_input_level = { | |||
| 956 | .tlv = { .p = db_scale_mic }, | 956 | .tlv = { .p = db_scale_mic }, |
| 957 | }; | 957 | }; |
| 958 | 958 | ||
| 959 | static struct snd_kcontrol_new vx_control_mic_level = { | 959 | static const struct snd_kcontrol_new vx_control_mic_level = { |
| 960 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 960 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 961 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 961 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 962 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | 962 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index ffee284898b3..fe4ba463b57c 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
| @@ -1316,7 +1316,7 @@ static int snd_ymfpci_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
| 1316 | return change; | 1316 | return change; |
| 1317 | } | 1317 | } |
| 1318 | 1318 | ||
| 1319 | static struct snd_kcontrol_new snd_ymfpci_spdif_default = | 1319 | static const struct snd_kcontrol_new snd_ymfpci_spdif_default = |
| 1320 | { | 1320 | { |
| 1321 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1321 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1322 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | 1322 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), |
| @@ -1344,7 +1344,7 @@ static int snd_ymfpci_spdif_mask_get(struct snd_kcontrol *kcontrol, | |||
| 1344 | return 0; | 1344 | return 0; |
| 1345 | } | 1345 | } |
| 1346 | 1346 | ||
| 1347 | static struct snd_kcontrol_new snd_ymfpci_spdif_mask = | 1347 | static const struct snd_kcontrol_new snd_ymfpci_spdif_mask = |
| 1348 | { | 1348 | { |
| 1349 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 1349 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 1350 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1350 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1391,7 +1391,7 @@ static int snd_ymfpci_spdif_stream_put(struct snd_kcontrol *kcontrol, | |||
| 1391 | return change; | 1391 | return change; |
| 1392 | } | 1392 | } |
| 1393 | 1393 | ||
| 1394 | static struct snd_kcontrol_new snd_ymfpci_spdif_stream = | 1394 | static const struct snd_kcontrol_new snd_ymfpci_spdif_stream = |
| 1395 | { | 1395 | { |
| 1396 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | 1396 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
| 1397 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1397 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -1439,7 +1439,7 @@ static int snd_ymfpci_drec_source_put(struct snd_kcontrol *kcontrol, struct snd_ | |||
| 1439 | return reg != old_reg; | 1439 | return reg != old_reg; |
| 1440 | } | 1440 | } |
| 1441 | 1441 | ||
| 1442 | static struct snd_kcontrol_new snd_ymfpci_drec_source = { | 1442 | static const struct snd_kcontrol_new snd_ymfpci_drec_source = { |
| 1443 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | 1443 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
| 1444 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1444 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1445 | .name = "Direct Recording Source", | 1445 | .name = "Direct Recording Source", |
| @@ -1609,7 +1609,7 @@ static int snd_ymfpci_put_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
| 1609 | return change; | 1609 | return change; |
| 1610 | } | 1610 | } |
| 1611 | 1611 | ||
| 1612 | static struct snd_kcontrol_new snd_ymfpci_dup4ch = { | 1612 | static const struct snd_kcontrol_new snd_ymfpci_dup4ch = { |
| 1613 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1613 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1614 | .name = "4ch Duplication", | 1614 | .name = "4ch Duplication", |
| 1615 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | 1615 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
| @@ -1712,7 +1712,7 @@ static int snd_ymfpci_gpio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
| 1712 | return 0; | 1712 | return 0; |
| 1713 | } | 1713 | } |
| 1714 | 1714 | ||
| 1715 | static struct snd_kcontrol_new snd_ymfpci_rear_shared = { | 1715 | static const struct snd_kcontrol_new snd_ymfpci_rear_shared = { |
| 1716 | .name = "Shared Rear/Line-In Switch", | 1716 | .name = "Shared Rear/Line-In Switch", |
| 1717 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1717 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1718 | .info = snd_ymfpci_gpio_sw_info, | 1718 | .info = snd_ymfpci_gpio_sw_info, |
| @@ -1776,7 +1776,7 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
| 1776 | return 0; | 1776 | return 0; |
| 1777 | } | 1777 | } |
| 1778 | 1778 | ||
| 1779 | static struct snd_kcontrol_new snd_ymfpci_pcm_volume = { | 1779 | static const struct snd_kcontrol_new snd_ymfpci_pcm_volume = { |
| 1780 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 1780 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 1781 | .name = "PCM Playback Volume", | 1781 | .name = "PCM Playback Volume", |
| 1782 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 1782 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index bbef77d2b917..8e2878012d53 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h | |||
| @@ -27,27 +27,6 @@ | |||
| 27 | 27 | ||
| 28 | #define SKL_SUSPEND_DELAY 2000 | 28 | #define SKL_SUSPEND_DELAY 2000 |
| 29 | 29 | ||
| 30 | /* Vendor Specific Registers */ | ||
| 31 | #define AZX_REG_VS_EM1 0x1000 | ||
| 32 | #define AZX_REG_VS_INRC 0x1004 | ||
| 33 | #define AZX_REG_VS_OUTRC 0x1008 | ||
| 34 | #define AZX_REG_VS_FIFOTRK 0x100C | ||
| 35 | #define AZX_REG_VS_FIFOTRK2 0x1010 | ||
| 36 | #define AZX_REG_VS_EM2 0x1030 | ||
| 37 | #define AZX_REG_VS_EM3L 0x1038 | ||
| 38 | #define AZX_REG_VS_EM3U 0x103C | ||
| 39 | #define AZX_REG_VS_EM4L 0x1040 | ||
| 40 | #define AZX_REG_VS_EM4U 0x1044 | ||
| 41 | #define AZX_REG_VS_LTRC 0x1048 | ||
| 42 | #define AZX_REG_VS_D0I3C 0x104A | ||
| 43 | #define AZX_REG_VS_PCE 0x104B | ||
| 44 | #define AZX_REG_VS_L2MAGC 0x1050 | ||
| 45 | #define AZX_REG_VS_L2LAHPT 0x1054 | ||
| 46 | #define AZX_REG_VS_SDXDPIB_XBASE 0x1084 | ||
| 47 | #define AZX_REG_VS_SDXDPIB_XINTERVAL 0x20 | ||
| 48 | #define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 | ||
| 49 | #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 | ||
| 50 | |||
| 51 | #define AZX_PCIREG_PGCTL 0x44 | 30 | #define AZX_PCIREG_PGCTL 0x44 |
| 52 | #define AZX_PGCTL_LSRMD_MASK (1 << 4) | 31 | #define AZX_PGCTL_LSRMD_MASK (1 << 4) |
| 53 | #define AZX_PCIREG_CGCTL 0x48 | 32 | #define AZX_PCIREG_CGCTL 0x48 |
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index ac75816ada7c..850fab4a8f3b 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c | |||
| @@ -225,9 +225,9 @@ snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, | |||
| 225 | else if (format == SNDRV_OSS_SOUNDFONT_PATCH) { | 225 | else if (format == SNDRV_OSS_SOUNDFONT_PATCH) { |
| 226 | struct soundfont_patch_info patch; | 226 | struct soundfont_patch_info patch; |
| 227 | if (count < (int)sizeof(patch)) | 227 | if (count < (int)sizeof(patch)) |
| 228 | rc = -EINVAL; | 228 | return -EINVAL; |
| 229 | if (copy_from_user(&patch, buf, sizeof(patch))) | 229 | if (copy_from_user(&patch, buf, sizeof(patch))) |
| 230 | rc = -EFAULT; | 230 | return -EFAULT; |
| 231 | if (patch.type >= SNDRV_SFNT_LOAD_INFO && | 231 | if (patch.type >= SNDRV_SFNT_LOAD_INFO && |
| 232 | patch.type <= SNDRV_SFNT_PROBE_DATA) | 232 | patch.type <= SNDRV_SFNT_PROBE_DATA) |
| 233 | rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port)); | 233 | rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port)); |
diff --git a/sound/usb/card.c b/sound/usb/card.c index f36cb068dad3..6640277a725b 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
| @@ -332,6 +332,7 @@ static int snd_usb_audio_dev_free(struct snd_device *device) | |||
| 332 | static int snd_usb_audio_create(struct usb_interface *intf, | 332 | static int snd_usb_audio_create(struct usb_interface *intf, |
| 333 | struct usb_device *dev, int idx, | 333 | struct usb_device *dev, int idx, |
| 334 | const struct snd_usb_audio_quirk *quirk, | 334 | const struct snd_usb_audio_quirk *quirk, |
| 335 | unsigned int usb_id, | ||
| 335 | struct snd_usb_audio **rchip) | 336 | struct snd_usb_audio **rchip) |
| 336 | { | 337 | { |
| 337 | struct snd_card *card; | 338 | struct snd_card *card; |
| @@ -381,8 +382,7 @@ static int snd_usb_audio_create(struct usb_interface *intf, | |||
| 381 | atomic_set(&chip->usage_count, 0); | 382 | atomic_set(&chip->usage_count, 0); |
| 382 | atomic_set(&chip->shutdown, 0); | 383 | atomic_set(&chip->shutdown, 0); |
| 383 | 384 | ||
| 384 | chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), | 385 | chip->usb_id = usb_id; |
| 385 | le16_to_cpu(dev->descriptor.idProduct)); | ||
| 386 | INIT_LIST_HEAD(&chip->pcm_list); | 386 | INIT_LIST_HEAD(&chip->pcm_list); |
| 387 | INIT_LIST_HEAD(&chip->ep_list); | 387 | INIT_LIST_HEAD(&chip->ep_list); |
| 388 | INIT_LIST_HEAD(&chip->midi_list); | 388 | INIT_LIST_HEAD(&chip->midi_list); |
| @@ -569,7 +569,7 @@ static int usb_audio_probe(struct usb_interface *intf, | |||
| 569 | (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && | 569 | (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && |
| 570 | (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { | 570 | (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { |
| 571 | err = snd_usb_audio_create(intf, dev, i, quirk, | 571 | err = snd_usb_audio_create(intf, dev, i, quirk, |
| 572 | &chip); | 572 | id, &chip); |
| 573 | if (err < 0) | 573 | if (err < 0) |
| 574 | goto __error; | 574 | goto __error; |
| 575 | chip->pm_intf = intf; | 575 | chip->pm_intf = intf; |
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index fab53f58d447..b3854f8c0c67 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c | |||
| @@ -430,7 +430,7 @@ static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, | |||
| 430 | } | 430 | } |
| 431 | 431 | ||
| 432 | /* control definition */ | 432 | /* control definition */ |
| 433 | static struct snd_kcontrol_new line6_controls[] = { | 433 | static const struct snd_kcontrol_new line6_controls[] = { |
| 434 | { | 434 | { |
| 435 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 435 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 436 | .name = "PCM Playback Volume", | 436 | .name = "PCM Playback Volume", |
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index 17aa616e61f5..358224cc5638 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c | |||
| @@ -380,7 +380,7 @@ static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol, | |||
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | /* control definition */ | 382 | /* control definition */ |
| 383 | static struct snd_kcontrol_new pod_control_monitor = { | 383 | static const struct snd_kcontrol_new pod_control_monitor = { |
| 384 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 384 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 385 | .name = "Monitor Playback Volume", | 385 | .name = "Monitor Playback Volume", |
| 386 | .index = 0, | 386 | .index = 0, |
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 8e22f430d700..ba7975c0d03d 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c | |||
| @@ -250,7 +250,7 @@ static void toneport_start_pcm(unsigned long arg) | |||
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | /* control definition */ | 252 | /* control definition */ |
| 253 | static struct snd_kcontrol_new toneport_control_monitor = { | 253 | static const struct snd_kcontrol_new toneport_control_monitor = { |
| 254 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 254 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 255 | .name = "Monitor Playback Volume", | 255 | .name = "Monitor Playback Volume", |
| 256 | .index = 0, | 256 | .index = 0, |
| @@ -261,7 +261,7 @@ static struct snd_kcontrol_new toneport_control_monitor = { | |||
| 261 | }; | 261 | }; |
| 262 | 262 | ||
| 263 | /* source selector definition */ | 263 | /* source selector definition */ |
| 264 | static struct snd_kcontrol_new toneport_control_source = { | 264 | static const struct snd_kcontrol_new toneport_control_source = { |
| 265 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 265 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 266 | .name = "PCM Capture Source", | 266 | .name = "PCM Capture Source", |
| 267 | .index = 0, | 267 | .index = 0, |
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 6e763bc8d7db..a35f41467237 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c | |||
| @@ -1922,7 +1922,7 @@ static int roland_load_put(struct snd_kcontrol *kcontrol, | |||
| 1922 | return changed; | 1922 | return changed; |
| 1923 | } | 1923 | } |
| 1924 | 1924 | ||
| 1925 | static struct snd_kcontrol_new roland_load_ctl = { | 1925 | static const struct snd_kcontrol_new roland_load_ctl = { |
| 1926 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1926 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1927 | .name = "MIDI Input Mode", | 1927 | .name = "MIDI Input Mode", |
| 1928 | .info = roland_load_info, | 1928 | .info = roland_load_info, |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 4703caea56b2..082736c539bc 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
| @@ -1172,7 +1172,7 @@ static struct snd_kcontrol_new usb_feature_unit_ctl = { | |||
| 1172 | }; | 1172 | }; |
| 1173 | 1173 | ||
| 1174 | /* the read-only variant */ | 1174 | /* the read-only variant */ |
| 1175 | static struct snd_kcontrol_new usb_feature_unit_ctl_ro = { | 1175 | static const struct snd_kcontrol_new usb_feature_unit_ctl_ro = { |
| 1176 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1176 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1177 | .name = "", /* will be filled later manually */ | 1177 | .name = "", /* will be filled later manually */ |
| 1178 | .info = mixer_ctl_feature_info, | 1178 | .info = mixer_ctl_feature_info, |
| @@ -1745,7 +1745,7 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol, | |||
| 1745 | } | 1745 | } |
| 1746 | 1746 | ||
| 1747 | /* alsa control interface for processing/extension unit */ | 1747 | /* alsa control interface for processing/extension unit */ |
| 1748 | static struct snd_kcontrol_new mixer_procunit_ctl = { | 1748 | static const struct snd_kcontrol_new mixer_procunit_ctl = { |
| 1749 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1749 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1750 | .name = "", /* will be filled later */ | 1750 | .name = "", /* will be filled later */ |
| 1751 | .info = mixer_ctl_feature_info, | 1751 | .info = mixer_ctl_feature_info, |
| @@ -2033,7 +2033,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, | |||
| 2033 | } | 2033 | } |
| 2034 | 2034 | ||
| 2035 | /* alsa control interface for selector unit */ | 2035 | /* alsa control interface for selector unit */ |
| 2036 | static struct snd_kcontrol_new mixer_selectunit_ctl = { | 2036 | static const struct snd_kcontrol_new mixer_selectunit_ctl = { |
| 2037 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2037 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2038 | .name = "", /* will be filled later */ | 2038 | .name = "", /* will be filled later */ |
| 2039 | .info = mixer_ctl_selector_info, | 2039 | .info = mixer_ctl_selector_info, |
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c index 7438e7c4a842..c33e2378089d 100644 --- a/sound/usb/mixer_scarlett.c +++ b/sound/usb/mixer_scarlett.c | |||
| @@ -477,7 +477,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, | |||
| 477 | return 0; | 477 | return 0; |
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | static struct snd_kcontrol_new usb_scarlett_ctl_switch = { | 480 | static const struct snd_kcontrol_new usb_scarlett_ctl_switch = { |
| 481 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 481 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 482 | .name = "", | 482 | .name = "", |
| 483 | .info = scarlett_ctl_switch_info, | 483 | .info = scarlett_ctl_switch_info, |
| @@ -487,7 +487,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl_switch = { | |||
| 487 | 487 | ||
| 488 | static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0); | 488 | static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0); |
| 489 | 489 | ||
| 490 | static struct snd_kcontrol_new usb_scarlett_ctl = { | 490 | static const struct snd_kcontrol_new usb_scarlett_ctl = { |
| 491 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 491 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 492 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 492 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 493 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 493 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, |
| @@ -499,7 +499,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl = { | |||
| 499 | .tlv = { .p = db_scale_scarlett_gain } | 499 | .tlv = { .p = db_scale_scarlett_gain } |
| 500 | }; | 500 | }; |
| 501 | 501 | ||
| 502 | static struct snd_kcontrol_new usb_scarlett_ctl_master = { | 502 | static const struct snd_kcontrol_new usb_scarlett_ctl_master = { |
| 503 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 503 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 504 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 504 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 505 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 505 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, |
| @@ -511,7 +511,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl_master = { | |||
| 511 | .tlv = { .p = db_scale_scarlett_gain } | 511 | .tlv = { .p = db_scale_scarlett_gain } |
| 512 | }; | 512 | }; |
| 513 | 513 | ||
| 514 | static struct snd_kcontrol_new usb_scarlett_ctl_enum = { | 514 | static const struct snd_kcontrol_new usb_scarlett_ctl_enum = { |
| 515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 516 | .name = "", | 516 | .name = "", |
| 517 | .info = scarlett_ctl_enum_info, | 517 | .info = scarlett_ctl_enum_info, |
| @@ -519,7 +519,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl_enum = { | |||
| 519 | .put = scarlett_ctl_enum_put, | 519 | .put = scarlett_ctl_enum_put, |
| 520 | }; | 520 | }; |
| 521 | 521 | ||
| 522 | static struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = { | 522 | static const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = { |
| 523 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 523 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 524 | .name = "", | 524 | .name = "", |
| 525 | .info = scarlett_ctl_enum_dynamic_info, | 525 | .info = scarlett_ctl_enum_dynamic_info, |
| @@ -527,7 +527,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = { | |||
| 527 | .put = scarlett_ctl_enum_put, | 527 | .put = scarlett_ctl_enum_put, |
| 528 | }; | 528 | }; |
| 529 | 529 | ||
| 530 | static struct snd_kcontrol_new usb_scarlett_ctl_sync = { | 530 | static const struct snd_kcontrol_new usb_scarlett_ctl_sync = { |
| 531 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 531 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 532 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 532 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
| 533 | .name = "", | 533 | .name = "", |
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index cf45bf1f7ee0..e118bdca983d 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c | |||
| @@ -472,7 +472,7 @@ static int usb_stream_hwdep_new(struct snd_card *card) | |||
| 472 | hw->ops.mmap = usb_stream_hwdep_mmap; | 472 | hw->ops.mmap = usb_stream_hwdep_mmap; |
| 473 | hw->ops.poll = usb_stream_hwdep_poll; | 473 | hw->ops.poll = usb_stream_hwdep_poll; |
| 474 | 474 | ||
| 475 | sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", | 475 | sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", |
| 476 | dev->bus->busnum, dev->devnum); | 476 | dev->bus->busnum, dev->devnum); |
| 477 | return 0; | 477 | return 0; |
| 478 | } | 478 | } |
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 605e1047c01d..f4b3cda412fc 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c | |||
| @@ -258,7 +258,7 @@ int usX2Y_hwdep_new(struct snd_card *card, struct usb_device* device) | |||
| 258 | hw->ops.mmap = snd_us428ctls_mmap; | 258 | hw->ops.mmap = snd_us428ctls_mmap; |
| 259 | hw->ops.poll = snd_us428ctls_poll; | 259 | hw->ops.poll = snd_us428ctls_poll; |
| 260 | hw->exclusive = 1; | 260 | hw->exclusive = 1; |
| 261 | sprintf(hw->name, "/proc/bus/usb/%03d/%03d", device->bus->busnum, device->devnum); | 261 | sprintf(hw->name, "/dev/bus/usb/%03d/%03d", device->bus->busnum, device->devnum); |
| 262 | return 0; | 262 | return 0; |
| 263 | } | 263 | } |
| 264 | 264 | ||
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index f95164b91152..d51c7fd7835b 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c | |||
| @@ -723,7 +723,7 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card) | |||
| 723 | hw->ops.release = snd_usX2Y_hwdep_pcm_release; | 723 | hw->ops.release = snd_usX2Y_hwdep_pcm_release; |
| 724 | hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap; | 724 | hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap; |
| 725 | hw->exclusive = 1; | 725 | hw->exclusive = 1; |
| 726 | sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum); | 726 | sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum); |
| 727 | 727 | ||
| 728 | err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm); | 728 | err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm); |
| 729 | if (err < 0) { | 729 | if (err < 0) { |
