summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/pcm_lib.c13
-rw-r--r--sound/core/pcm_native.c39
-rw-r--r--sound/pci/aw2/aw2-alsa.c11
-rw-r--r--sound/pci/emu10k1/emufx.c36
-rw-r--r--sound/usb/caiaq/input.c2
-rw-r--r--sound/usb/midi.c110
-rw-r--r--sound/usb/midi.h2
-rw-r--r--sound/usb/quirks-table.h11
-rw-r--r--sound/usb/quirks.c1
-rw-r--r--sound/usb/usbaudio.h1
10 files changed, 171 insertions, 55 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index a2ff86189d2a..e9d98be190c5 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -345,7 +345,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
new_hw_ptr = hw_base + pos;
}
__delta:
- delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary;
+ delta = new_hw_ptr - old_hw_ptr;
+ if (delta < 0)
+ delta += runtime->boundary;
if (xrun_debug(substream, in_interrupt ?
XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
char name[16];
@@ -439,8 +441,13 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
snd_pcm_playback_silence(substream, new_hw_ptr);
if (in_interrupt) {
- runtime->hw_ptr_interrupt = new_hw_ptr -
- (new_hw_ptr % runtime->period_size);
+ delta = new_hw_ptr - runtime->hw_ptr_interrupt;
+ if (delta < 0)
+ delta += runtime->boundary;
+ delta -= (snd_pcm_uframes_t)delta % runtime->period_size;
+ runtime->hw_ptr_interrupt += delta;
+ if (runtime->hw_ptr_interrupt >= runtime->boundary)
+ runtime->hw_ptr_interrupt -= runtime->boundary;
}
runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 644c2bb17b86..303ac04ff6e4 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -27,7 +27,6 @@
#include <linux/pm_qos_params.h>
#include <linux/uio.h>
#include <linux/dma-mapping.h>
-#include <linux/math64.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
@@ -370,38 +369,6 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
return usecs;
}
-static int calc_boundary(struct snd_pcm_runtime *runtime)
-{
- u_int64_t boundary;
-
- boundary = (u_int64_t)runtime->buffer_size *
- (u_int64_t)runtime->period_size;
-#if BITS_PER_LONG < 64
- /* try to find lowest common multiple for buffer and period */
- if (boundary > LONG_MAX - runtime->buffer_size) {
- u_int32_t remainder = -1;
- u_int32_t divident = runtime->buffer_size;
- u_int32_t divisor = runtime->period_size;
- while (remainder) {
- remainder = divident % divisor;
- if (remainder) {
- divident = divisor;
- divisor = remainder;
- }
- }
- boundary = div_u64(boundary, divisor);
- if (boundary > LONG_MAX - runtime->buffer_size)
- return -ERANGE;
- }
-#endif
- if (boundary == 0)
- return -ERANGE;
- runtime->boundary = boundary;
- while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
- runtime->boundary *= 2;
- return 0;
-}
-
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -477,9 +444,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
runtime->stop_threshold = runtime->buffer_size;
runtime->silence_threshold = 0;
runtime->silence_size = 0;
- err = calc_boundary(runtime);
- if (err < 0)
- goto _error;
+ runtime->boundary = runtime->buffer_size;
+ while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
+ runtime->boundary *= 2;
snd_pcm_timer_resolution_change(substream);
runtime->status->state = SNDRV_PCM_STATE_SETUP;
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 67921f93a41e..c15002242d98 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -26,7 +26,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
@@ -44,9 +44,6 @@ MODULE_LICENSE("GPL");
/*********************************
* DEFINES
********************************/
-#define PCI_VENDOR_ID_SAA7146 0x1131
-#define PCI_DEVICE_ID_SAA7146 0x7146
-
#define CTL_ROUTE_ANALOG 0
#define CTL_ROUTE_DIGITAL 1
@@ -165,7 +162,7 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = {
- {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0,
+ {PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0, 0,
0, 0, 0},
{0}
};
@@ -419,7 +416,7 @@ static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- snd_printdd(KERN_DEBUG "aw2: Playback_open \n");
+ snd_printdd(KERN_DEBUG "aw2: Playback_open\n");
runtime->hw = snd_aw2_playback_hw;
return 0;
}
@@ -435,7 +432,7 @@ static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- snd_printdd(KERN_DEBUG "aw2: Capture_open \n");
+ snd_printdd(KERN_DEBUG "aw2: Capture_open\n");
runtime->hw = snd_aw2_capture_hw;
return 0;
}
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 4b302d86f5f2..7a9401462c1c 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -35,6 +35,7 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/tlv.h>
@@ -50,6 +51,10 @@
#define EMU10K1_CENTER_LFE_FROM_FRONT
#endif
+static bool high_res_gpr_volume;
+module_param(high_res_gpr_volume, bool, 0444);
+MODULE_PARM_DESC(high_res_gpr_volume, "GPR mixer controls use 31-bit range.");
+
/*
* Tables
*/
@@ -296,6 +301,7 @@ static const u32 db_table[101] = {
/* EMU10k1/EMU10k2 DSP control db gain */
static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
+static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
static const u32 onoff_table[2] = {
0x00000000, 0x00000001
@@ -1072,10 +1078,17 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
strcpy(ctl->id.name, name);
ctl->vcount = ctl->count = 1;
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
- ctl->min = 0;
- ctl->max = 100;
- ctl->tlv = snd_emu10k1_db_scale1;
- ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+ if (high_res_gpr_volume) {
+ ctl->min = 0;
+ ctl->max = 0x7fffffff;
+ ctl->tlv = snd_emu10k1_db_linear;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
+ } else {
+ ctl->min = 0;
+ ctl->max = 100;
+ ctl->tlv = snd_emu10k1_db_scale1;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+ }
}
static void __devinit
@@ -1087,10 +1100,17 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
ctl->vcount = ctl->count = 2;
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
- ctl->min = 0;
- ctl->max = 100;
- ctl->tlv = snd_emu10k1_db_scale1;
- ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+ if (high_res_gpr_volume) {
+ ctl->min = 0;
+ ctl->max = 0x7fffffff;
+ ctl->tlv = snd_emu10k1_db_linear;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
+ } else {
+ ctl->min = 0;
+ ctl->max = 100;
+ ctl->tlv = snd_emu10k1_db_scale1;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+ }
}
static void __devinit
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index 8bbfbfd4c658..dcb620796d9e 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -171,7 +171,7 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]);
input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]);
- input_report_abs(input_dev, ABS_HAT2X, (buf[15] << 8) | buf[15]);
+ input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]);
input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]);
input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]);
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 2c1558c327bb..9c23d89066e4 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -645,6 +645,105 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = {
};
/*
+ * AKAI MPD16 protocol:
+ *
+ * For control port (endpoint 1):
+ * ==============================
+ * One or more chunks consisting of first byte of (0x10 | msg_len) and then a
+ * SysEx message (msg_len=9 bytes long).
+ *
+ * For data port (endpoint 2):
+ * ===========================
+ * One or more chunks consisting of first byte of (0x20 | msg_len) and then a
+ * MIDI message (msg_len bytes long)
+ *
+ * Messages sent: Active Sense, Note On, Poly Pressure, Control Change.
+ */
+static void snd_usbmidi_akai_input(struct snd_usb_midi_in_endpoint *ep,
+ uint8_t *buffer, int buffer_length)
+{
+ unsigned int pos = 0;
+ unsigned int len = (unsigned int)buffer_length;
+ while (pos < len) {
+ unsigned int port = (buffer[pos] >> 4) - 1;
+ unsigned int msg_len = buffer[pos] & 0x0f;
+ pos++;
+ if (pos + msg_len <= len && port < 2)
+ snd_usbmidi_input_data(ep, 0, &buffer[pos], msg_len);
+ pos += msg_len;
+ }
+}
+
+#define MAX_AKAI_SYSEX_LEN 9
+
+static void snd_usbmidi_akai_output(struct snd_usb_midi_out_endpoint *ep,
+ struct urb *urb)
+{
+ uint8_t *msg;
+ int pos, end, count, buf_end;
+ uint8_t tmp[MAX_AKAI_SYSEX_LEN];
+ struct snd_rawmidi_substream *substream = ep->ports[0].substream;
+
+ if (!ep->ports[0].active)
+ return;
+
+ msg = urb->transfer_buffer + urb->transfer_buffer_length;
+ buf_end = ep->max_transfer - MAX_AKAI_SYSEX_LEN - 1;
+
+ /* only try adding more data when there's space for at least 1 SysEx */
+ while (urb->transfer_buffer_length < buf_end) {
+ count = snd_rawmidi_transmit_peek(substream,
+ tmp, MAX_AKAI_SYSEX_LEN);
+ if (!count) {
+ ep->ports[0].active = 0;
+ return;
+ }
+ /* try to skip non-SysEx data */
+ for (pos = 0; pos < count && tmp[pos] != 0xF0; pos++)
+ ;
+
+ if (pos > 0) {
+ snd_rawmidi_transmit_ack(substream, pos);
+ continue;
+ }
+
+ /* look for the start or end marker */
+ for (end = 1; end < count && tmp[end] < 0xF0; end++)
+ ;
+
+ /* next SysEx started before the end of current one */
+ if (end < count && tmp[end] == 0xF0) {
+ /* it's incomplete - drop it */
+ snd_rawmidi_transmit_ack(substream, end);
+ continue;
+ }
+ /* SysEx complete */
+ if (end < count && tmp[end] == 0xF7) {
+ /* queue it, ack it, and get the next one */
+ count = end + 1;
+ msg[0] = 0x10 | count;
+ memcpy(&msg[1], tmp, count);
+ snd_rawmidi_transmit_ack(substream, count);
+ urb->transfer_buffer_length += count + 1;
+ msg += count + 1;
+ continue;
+ }
+ /* less than 9 bytes and no end byte - wait for more */
+ if (count < MAX_AKAI_SYSEX_LEN) {
+ ep->ports[0].active = 0;
+ return;
+ }
+ /* 9 bytes and no end marker in sight - malformed, skip it */
+ snd_rawmidi_transmit_ack(substream, count);
+ }
+}
+
+static struct usb_protocol_ops snd_usbmidi_akai_ops = {
+ .input = snd_usbmidi_akai_input,
+ .output = snd_usbmidi_akai_output,
+};
+
+/*
* Novation USB MIDI protocol: number of data bytes is in the first byte
* (when receiving) (+1!) or in the second byte (when sending); data begins
* at the third byte.
@@ -1434,6 +1533,11 @@ static struct port_info {
EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"),
EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"),
EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"),
+ /* Akai MPD16 */
+ CONTROL_PORT(0x09e8, 0x0062, 0, "%s Control"),
+ PORT_INFO(0x09e8, 0x0062, 1, "%s MIDI", 0,
+ SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
+ SNDRV_SEQ_PORT_TYPE_HARDWARE),
/* Access Music Virus TI */
EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"),
PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0,
@@ -2035,6 +2139,12 @@ int snd_usbmidi_create(struct snd_card *card,
umidi->usb_protocol_ops = &snd_usbmidi_cme_ops;
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
+ case QUIRK_MIDI_AKAI:
+ umidi->usb_protocol_ops = &snd_usbmidi_akai_ops;
+ err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+ /* endpoint 1 is input-only */
+ endpoints[1].out_cables = 0;
+ break;
default:
snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
err = -ENXIO;
diff --git a/sound/usb/midi.h b/sound/usb/midi.h
index 2089ec987c66..2fca80b744c0 100644
--- a/sound/usb/midi.h
+++ b/sound/usb/midi.h
@@ -37,6 +37,8 @@ struct snd_usb_midi_endpoint_info {
/* for QUIRK_MIDI_CME, data is NULL */
+/* for QUIRK_MIDI_AKAI, data is NULL */
+
int snd_usbmidi_create(struct snd_card *card,
struct usb_interface *iface,
struct list_head *midi_list,
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 91ddef31bcbd..f8797f61a24b 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -1973,6 +1973,17 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
+/* AKAI devices */
+{
+ USB_DEVICE(0x09e8, 0x0062),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "AKAI",
+ .product_name = "MPD16",
+ .ifnum = 0,
+ .type = QUIRK_MIDI_AKAI,
+ }
+},
+
/* TerraTec devices */
{
USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012),
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 136e5b4cf6de..b45e54c09ba2 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -289,6 +289,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
[QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
[QUIRK_MIDI_CME] = create_any_midi_quirk,
+ [QUIRK_MIDI_AKAI] = create_any_midi_quirk,
[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index d679e72a3e5c..06ebf24d3a4d 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -74,6 +74,7 @@ enum quirk_type {
QUIRK_MIDI_FASTLANE,
QUIRK_MIDI_EMAGIC,
QUIRK_MIDI_CME,
+ QUIRK_MIDI_AKAI,
QUIRK_MIDI_US122L,
QUIRK_AUDIO_STANDARD_INTERFACE,
QUIRK_AUDIO_FIXED_ENDPOINT,