oleavr-rgl-a500-mini-linux-.../drivers/hid/hid-pt71600-remote.c
Ole André Vadla Ravnås 169c65d57e Initial commit
2022-05-07 01:01:45 +02:00

1447 lines
44 KiB
C

/*
* HID driver for the Android TV remote
* providing keys and microphone audio functionality
*
* Copyright (C) 2014 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/hardirq.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <linux/proc_fs.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include "hid-ids.h"
MODULE_LICENSE("GPL v2");
/* Driver names (maximum sizes may depend on kernel version) */
#define PT71600_REMOTE_HID_DRIVER_NAME "PT71600 Motion and Audio remote"
#define PT71600_REMOTE_AUDIO_DEVICE_ID "PT71600Audio" /* max=16 */
/* Used by Audio HAL (/proc/asound/card<n>/id)
to identify the virtual sound card. */
#define PT71600_REMOTE_AUDIO_DRIVER_NAME "PT71600 Audio" /* max=16 */
#define PT71600_REMOTE_AUDIO_DEVICE_NAME_SHORT "PT71600Audio" /* max=32 */
#define PT71600_REMOTE_AUDIO_DEVICE_NAME_LONG "PT71600 Remote %i audio" /* max=80 */
#define PT71600_REMOTE_PCM_DEVICE_ID "PT71600 PCM AUDIO" /* max=64 */
#define PT71600_REMOTE_PCM_DEVICE_NAME "PT71600 PCM" /* max=80 */
#define PT71600_DRIVER_VERSION "2.0.0-Half-IMA"
#define snd_pt71600_log(...) pr_err("snd_pt71600: " __VA_ARGS__)
#define ADPCM_AUDIO_REPORT_ID_2 (2)
/* defaults */
#define MAX_PCM_DEVICES 1
#define MAX_PCM_SUBSTREAMS 4
#define MAX_MIDI_DEVICES 0
/* Define these all in one place so they stay in sync. */
#define USE_RATE_MIN 16000
#define USE_RATE_MAX 16000
#define USE_RATES_ARRAY {USE_RATE_MIN}
#define USE_RATES_MASK (SNDRV_PCM_RATE_16000) /* only this enum matters for ALSA PCM INFO */
#ifndef DECODER_BITS_PER_SAMPLE
#define DECODER_BITS_PER_SAMPLE 4
#endif
#define DECODER_BUFFER_LATENCY_MS 200
#define DECODER_MAX_ADJUST_FRAMES USE_RATE_MAX
#define MAX_FRAMES_PER_BUFFER (16384) /* doubling the buffer */
#define USE_CHANNELS_MIN 1
#define USE_CHANNELS_MAX 1
#define USE_PERIODS_MIN 1
#define USE_PERIODS_MAX 4
#define MAX_PCM_BUFFER_SIZE (MAX_FRAMES_PER_BUFFER * sizeof(int16_t))
#define MIN_PERIOD_SIZE 2
#define MAX_PERIOD_SIZE (MAX_FRAMES_PER_BUFFER * sizeof(int16_t))
#define USE_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
#define PACKET_TYPE_ADPCM 0
struct fifo_packet {
uint8_t type;
uint8_t num_bytes;
uint8_t start;
uint8_t reset;
uint32_t pos;
/* Expect no more than 20 bytes. But align struct size to power of 2. */
uint8_t raw_data[24];
};
#define MAX_SAMPLES_PER_PACKET 128
#define MIN_SAMPLES_PER_PACKET_P2 32
#define MAX_PACKETS_PER_BUFFER \
(MAX_FRAMES_PER_BUFFER / MIN_SAMPLES_PER_PACKET_P2)
#define MAX_BUFFER_SIZE \
(MAX_PACKETS_PER_BUFFER * sizeof(struct fifo_packet))
#define SND_ATVR_RUNNING_TIMEOUT_MSEC (500)
#define TIMER_STATE_UNINIT 255
#define TIMER_STATE_BEFORE_DECODE 0
#define TIMER_STATE_DURING_DECODE 1
#define TIMER_STATE_AFTER_DECODE 2
static int packet_counter;
static int num_remotes;
static bool card_created;
static int dev;
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static bool enable[SNDRV_CARDS] = {true, false};
/* Linux does not like NULL initialization. */
static char *model[SNDRV_CARDS]; /* = {[0 ... (SNDRV_CARDS - 1)] = NULL}; */
static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
const int8_t IndexTable[16] = {-1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8};
const int16_t StepSizeTable[89] = {
7, 8, 9, 10, 11, 12, 13, 14,
16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66,
73, 80, 88, 97, 107, 118, 130, 143,
157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658,
724, 796, 876, 963, 1060, 1166, 1282, 1411,
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
#define HEAVY_ATTENU
#ifdef HEAVY_ATTENU
#define FILT_LEN 56
const int16_t filt_coef[] = {
-34, -155, -312, -290, 27, 354, 275, -88, -134, 248, 375, -72, -326, 174,
578, 6, -620, 2, 920, 256, -1096, -435, 1593, 1023, -2307, -2223, 5107, 13507,
};
#else
#define FILT_LEN 40
const int16_t filt_coef[] = {
174, 478, 477, -17, -393, -21, 465, 83, -600, -182,
780, 346, -1037, -614, 1436, 1119, -2221, -2393, 4929, 13573,
};
#endif
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for PT71600 Remote soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for PT71600 Remote soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable this PT71600 Remote soundcard.");
module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Soundcard model.");
module_param_array(pcm_devs, int, NULL, 0444);
MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for PT71600 Remote driver.");
module_param_array(pcm_substreams, int, NULL, 0444);
MODULE_PARM_DESC(pcm_substreams,
"PCM substreams # (1-128) for PT71600 Remote driver?");
/* Debug feature to trace audio packets being received */
#define DEBUG_AUDIO_RECEPTION 1
/* Debug feature to trace HID reports we see */
#define DEBUG_HID_RAW_INPUT (0)
/* Driver data (virtual sound card private data) */
struct snd_pt71600 *s_pt71600_snd;
/*
* Static substream is needed so Bluetooth can pass encoded audio
* to a running stream.
* This also serves to enable or disable the decoding of audio in the callback.
*/
static struct snd_pcm_substream *s_substream_for_btle;
static DEFINE_SPINLOCK(s_substream_lock);
struct simple_atomic_fifo {
/* Read and write cursors are modified by different threads. */
uint read_cursor;
uint write_cursor;
/* Size must be a power of two. */
uint size;
/* internal mask is 2*size - 1
* This allows us to tell the difference between full and empty. */
uint internal_mask;
uint external_mask;
};
struct snd_pt71600 {
struct snd_card *card;
struct snd_pcm *pcm;
struct snd_pcm_hardware pcm_hw;
uint32_t sample_rate;
uint previous_jiffies; /* Used to detect underflows. */
uint timeout_jiffies;
struct timer_list decoding_timer;
uint timer_state;
bool timer_enabled;
uint timer_callback_count;
uint32_t decoder_buffer_size;
uint32_t num_bytes;
uint32_t buffer_start_pos;
uint32_t stream_enable_pos;
uint32_t stream_disable_pos;
uint32_t stream_reset_pos;
uint32_t decoder_pos;
int32_t decoder_frames_adjust;
int16_t peak_level;
struct simple_atomic_fifo fifo_controller;
struct fifo_packet *fifo_packet_buffer;
/* IMA Decoder */
int16_t prevsample;
uint16_t previndex;
int16_t idx;
int16_t filt_state[FILT_LEN];
/*
* Write_index is the circular buffer position.
* It is advanced by the BTLE thread after decoding.
* It is read by ALSA in snd_pt71600_pcm_pointer().
* It is not declared volatile because that is not
* allowed in the Linux kernel.
*/
uint32_t write_index;
uint32_t frames_per_buffer;
/* count frames generated so far in this period */
uint32_t frames_in_period;
int16_t *pcm_buffer;
};
/***************************************************************************/
/************* Atomic FIFO *************************************************/
/***************************************************************************/
/*
* This FIFO is atomic if used by no more than 2 threads.
* One thread modifies the read cursor and the other
* thread modifies the write_cursor.
* Size and mask are not modified while being used.
*
* The read and write cursors range internally from 0 to (2*size)-1.
* This allows us to tell the difference between full and empty.
* When we get the cursors for external use we mask with size-1.
*
* Memory barriers required on SMP platforms.
*/
static int atomic_fifo_init(struct simple_atomic_fifo *fifo_ptr, uint size)
{
/* Make sure size is a power of 2. */
if ((size & (size-1)) != 0) {
pr_err("%s:%d - ERROR FIFO size = %d, not power of 2!\n",
__func__, __LINE__, size);
return -EINVAL;
}
fifo_ptr->read_cursor = 0;
fifo_ptr->write_cursor = 0;
fifo_ptr->size = size;
fifo_ptr->internal_mask = (size * 2) - 1;
fifo_ptr->external_mask = size - 1;
smp_wmb();
return 0;
}
static uint atomic_fifo_available_to_read(struct simple_atomic_fifo *fifo_ptr)
{
smp_rmb();
return (fifo_ptr->write_cursor - fifo_ptr->read_cursor)
& fifo_ptr->internal_mask;
}
static uint atomic_fifo_available_to_write(struct simple_atomic_fifo *fifo_ptr)
{
smp_rmb();
return fifo_ptr->size - atomic_fifo_available_to_read(fifo_ptr);
}
static void atomic_fifo_advance_read(
struct simple_atomic_fifo *fifo_ptr,
uint frames)
{
smp_rmb();
BUG_ON(frames > atomic_fifo_available_to_read(fifo_ptr));
fifo_ptr->read_cursor = (fifo_ptr->read_cursor + frames)
& fifo_ptr->internal_mask;
smp_wmb();
}
static void atomic_fifo_advance_write(
struct simple_atomic_fifo *fifo_ptr,
uint frames)
{
smp_rmb();
BUG_ON(frames > atomic_fifo_available_to_write(fifo_ptr));
fifo_ptr->write_cursor = (fifo_ptr->write_cursor + frames)
& fifo_ptr->internal_mask;
smp_wmb();
}
static uint atomic_fifo_get_read_index(struct simple_atomic_fifo *fifo_ptr)
{
smp_rmb();
return fifo_ptr->read_cursor & fifo_ptr->external_mask;
}
static uint atomic_fifo_get_write_index(struct simple_atomic_fifo *fifo_ptr)
{
smp_rmb();
return fifo_ptr->write_cursor & fifo_ptr->external_mask;
}
/****************************************************************************/
static void snd_pt71600_handle_frame_advance(
struct snd_pcm_substream *substream, uint num_frames)
{
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
pt71600_snd->frames_in_period += num_frames;
/* Tell ALSA if we have advanced by one or more periods. */
if (pt71600_snd->frames_in_period >= substream->runtime->period_size) {
snd_pcm_period_elapsed(substream);
pt71600_snd->frames_in_period %= substream->runtime->period_size;
}
}
static uint32_t snd_pt71600_bump_write_index(
struct snd_pcm_substream *substream,
uint32_t num_samples)
{
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
uint32_t pos = pt71600_snd->write_index;
/* Advance write position. */
pos += num_samples;
/* Wrap around at end of the circular buffer. */
pos %= pt71600_snd->frames_per_buffer;
pt71600_snd->write_index = pos;
snd_pt71600_handle_frame_advance(substream, num_samples);
return pos;
}
/*
* Decode an IMA/DVI ADPCM packet and write the PCM data into a circular buffer.
* ADPCM is 4:1 16kHz@256kbps -> 16kHz@64kbps.
* ADPCM is 4:1 8kHz@128kbps -> 8kHz@32kbps.
*/
static const int ima_index_table[16] = {
-1, -1, -1, -1,
2, 4, 6, 8,
-1, -1, -1, -1,
2, 4, 6, 8};
static const int16_t ima_step_table[89] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
static short *U2_FILT(short in, short *outp, struct snd_pt71600 *pt71600_snd)
{
long out = 0;
short *ph, *pe;
int i;
pt71600_snd->filt_state[pt71600_snd->idx] = pt71600_snd->filt_state[pt71600_snd->idx+FILT_LEN/2] = in;
ph = pt71600_snd->filt_state+pt71600_snd->idx;
pe = ph+FILT_LEN/2-1;
for (i = 0; i < FILT_LEN/2; i += 2) {
out += *ph*filt_coef[i];
out += *pe*filt_coef[i+1];
ph++; pe--;
}
out >>= 12;
if (out > 32767)
out = 32767;
else if (out < -32768)
out = -32768;
*outp++ = (short)out;
out = 0;
ph = pt71600_snd->filt_state+pt71600_snd->idx;
pe = ph+FILT_LEN/2-1;
for (i = 0; i < FILT_LEN/2; i += 2) {
out += *pe*filt_coef[i];
out += *ph*filt_coef[i+1];
ph++; pe--;
}
out >>= 12;
if (out > 32767)
out = 32767;
else if (out < -32768)
out = -32768;
*outp++ = (short)out;
pt71600_snd->idx -= 1;
if (pt71600_snd->idx < 0)
pt71600_snd->idx = FILT_LEN/2-1;
return outp;
}
static int ima_32_decoder(int code, struct snd_pt71600 *pt71600_snd)
{
int predsample, index, step, diffq;
int i;
predsample = pt71600_snd->prevsample;
index = pt71600_snd->previndex;
step = StepSizeTable[index];
code &= 0x0F;
index = index + IndexTable[code];
if (index < 0)
index = 0;
else if (index > 88)
index = 88;
pt71600_snd->previndex = (uint16_t)index;
diffq = 0;
i = 3;
do {
if (code & 4) {
diffq += step;
}
code <<= 1;
step >>= 1;
i--;
} while (i > 0);
diffq += step;
if (code & 64)
predsample -= diffq;
else
predsample += diffq;
if (predsample > 32767)
predsample = 32767;
else if (predsample < -32768)
predsample = -32768;
pt71600_snd->prevsample = (int16_t)predsample;
if (predsample > pt71600_snd->peak_level)
pt71600_snd->peak_level = predsample;
return predsample;
}
int ima_adpcm_decode_proc_halfrate(int code, struct snd_pt71600 *pt71600_snd,
struct snd_pcm_substream *substream)
{
int i;
int d2;
short synth[4];
short *syp = synth;
memset(synth, 0, sizeof(synth));
d2 = ima_32_decoder(code, pt71600_snd); /* low nibble */
syp = U2_FILT(d2, syp, pt71600_snd);
d2 = ima_32_decoder(code >> 4, pt71600_snd); /* high nibble */
syp = U2_FILT(d2, syp, pt71600_snd);
for (i = 0; i < 4; i++) {
if (substream != NULL) {
pt71600_snd->pcm_buffer[pt71600_snd->write_index] = synth[i];
snd_pt71600_bump_write_index(substream, 1);
}
}
return 4;
}
#if (DECODER_BITS_PER_SAMPLE == 4)
static int snd_pt71600_decode_adpcm_packet(
struct snd_pcm_substream *substream,
const uint8_t *adpcm_input,
size_t num_bytes
)
{
uint i;
struct snd_pt71600 *pt71600_snd = substream != NULL ? snd_pcm_substream_chip(substream) : s_pt71600_snd;
for (i = 0; i < num_bytes; i++) {
uint8_t raw = adpcm_input[i];
ima_adpcm_decode_proc_halfrate(raw, pt71600_snd, substream);
}
return num_bytes * 4;
}
#endif /* (DECODER_BITS_PER_SAMPLE == 4) */
#if (DECODER_BITS_PER_SAMPLE == 3)
static int snd_pt71600_decode_adpcm_packet(
struct snd_pcm_substream *substream,
const uint8_t *adpcm_input,
size_t num_bytes
)
{
uint i, j, size;
uint frames = 0;
uint32_t packed;
uint8_t nibble;
struct snd_pt71600 *pt71600_snd = substream != NULL ? snd_pcm_substream_chip(substream) : s_pt71600_snd;
i = 0;
while (i < num_bytes) {
/* Pack 8 samples (at most) in 3 bytes (MSB) */
packed = 0;
size = 0;
for (j = 0; j < 3 && i < num_bytes; ++j, ++i) {
packed |= adpcm_input[i] << (24 - size);
size += 8;
}
size /= 3; /* number of packed samples */
/* Create and decode 4-bit nibbles */
for (j = 0; j < size; ++j) {
nibble = ((packed >> 28) & 0x0E) | 0x01;
packed <<= 3;
decode_adpcm_nibble(nibble, pt71600_snd, substream);
++frames;
}
}
return frames;
}
#endif /* (DECODER_BITS_PER_SAMPLE == 3) */
/**
* This is called by the event filter when it gets an audio packet
* from the AndroidTV remote. It writes the packet into a FIFO
* which is then read and decoded by the timer task.
* @param input pointer to data to be decoded
* @param num_bytes how many bytes in raw_input
* @return number of samples decoded or negative error.
*/
static void audio_dec(const uint8_t *raw_input, int type, size_t num_bytes)
{
bool dropped_packet = false;
struct snd_pcm_substream *substream;
spin_lock(&s_substream_lock);
substream = s_substream_for_btle;
if (substream != NULL) {
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
/* Write data to a FIFO for decoding by the timer task. */
uint writable = atomic_fifo_available_to_write(
&pt71600_snd->fifo_controller);
if (writable > 0) {
uint fifo_index = atomic_fifo_get_write_index(
&pt71600_snd->fifo_controller);
struct fifo_packet *packet =
&pt71600_snd->fifo_packet_buffer[fifo_index];
packet->type = type;
packet->num_bytes = (uint8_t)num_bytes;
packet->pos = pt71600_snd->num_bytes;
packet->start = packet->pos == pt71600_snd->stream_enable_pos;
packet->reset = packet->pos == pt71600_snd->stream_reset_pos;
memcpy(packet->raw_data, raw_input, num_bytes);
pt71600_snd->num_bytes += num_bytes;
atomic_fifo_advance_write(
&pt71600_snd->fifo_controller, 1);
} else {
dropped_packet = true;
s_substream_for_btle = NULL; /* Stop decoding. */
}
} else {
/* Decode received packet to keep decoder in sync with the RCU */
if (s_pt71600_snd != NULL) {
/* Reset decoder values */
if (s_pt71600_snd->stream_reset_pos == s_pt71600_snd->num_bytes) {
s_pt71600_snd->prevsample = 0;
s_pt71600_snd->previndex = 0;
s_pt71600_snd->idx = FILT_LEN/2-1;;
memset(s_pt71600_snd->filt_state, 0, sizeof(s_pt71600_snd->filt_state));
}
/* If we are waiting for the substream to close, and there are data in the FIFO, put
the packet in the FIFO. It will be decoded when snd_pt71600_pcm_close is called. */
if (atomic_fifo_available_to_read(&s_pt71600_snd->fifo_controller) > 0
&& atomic_fifo_available_to_write(&s_pt71600_snd->fifo_controller) > 0) {
uint fifo_index = atomic_fifo_get_write_index(&s_pt71600_snd->fifo_controller);
struct fifo_packet *packet = &s_pt71600_snd->fifo_packet_buffer[fifo_index];
packet->type = type;
packet->num_bytes = (uint8_t)num_bytes;
packet->pos = s_pt71600_snd->num_bytes;
memcpy(packet->raw_data, raw_input, num_bytes);
atomic_fifo_advance_write(&s_pt71600_snd->fifo_controller, 1);
} else {
snd_pt71600_decode_adpcm_packet(NULL, raw_input, num_bytes);
}
s_pt71600_snd->num_bytes += num_bytes;
}
}
packet_counter++;
spin_unlock(&s_substream_lock);
if (dropped_packet)
snd_pt71600_log("WARNING, raw audio packet dropped, FIFO full\n");
}
/*
* Note that smp_rmb() is called by snd_pt71600_timer_callback()
* before calling this function.
*
* Reads:
* jiffies
* pt71600_snd->previous_jiffies
* Writes:
* pt71600_snd->previous_jiffies
* Returns:
* num_frames needed to catch up to the current time
*/
static uint snd_pt71600_calc_frame_advance(struct snd_pt71600 *pt71600_snd)
{
/* Determine how much time passed. */
uint now_jiffies = jiffies;
uint elapsed_jiffies = now_jiffies - pt71600_snd->previous_jiffies;
/* Convert jiffies to frames. */
uint frames_by_time = jiffies_to_msecs(elapsed_jiffies)
* pt71600_snd->sample_rate / 1000;
pt71600_snd->previous_jiffies = now_jiffies;
/* Don't write more than one buffer full. */
if (frames_by_time > (pt71600_snd->frames_per_buffer - 4))
frames_by_time = pt71600_snd->frames_per_buffer - 4;
return frames_by_time;
}
/* Write zeros into the PCM buffer. */
static uint32_t snd_pt71600_write_silence(struct snd_pt71600 *pt71600_snd,
uint32_t pos,
int frames_to_advance)
{
/* Does it wrap? */
if ((pos + frames_to_advance) > pt71600_snd->frames_per_buffer) {
/* Write to end of buffer. */
int16_t *destination = &pt71600_snd->pcm_buffer[pos];
size_t num_frames = pt71600_snd->frames_per_buffer - pos;
size_t num_bytes = num_frames * sizeof(int16_t);
memset(destination, 0, num_bytes);
/* Write from start of buffer to new pos. */
destination = &pt71600_snd->pcm_buffer[0];
num_frames = frames_to_advance - num_frames;
num_bytes = num_frames * sizeof(int16_t);
memset(destination, 0, num_bytes);
} else {
/* Write within the buffer. */
int16_t *destination = &pt71600_snd->pcm_buffer[pos];
size_t num_bytes = frames_to_advance * sizeof(int16_t);
memset(destination, 0, num_bytes);
}
/* Advance and wrap write_index */
pos += frames_to_advance;
pos %= pt71600_snd->frames_per_buffer;
return pos;
}
/*
* Called by timer task to decode raw audio data from the FIFO into the PCM
* buffer. Returns the number of packets decoded.
*/
static uint snd_pt71600_decode_from_fifo(struct snd_pcm_substream *substream, uint *max_frames)
{
uint i, frames;
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
uint readable = atomic_fifo_available_to_read(
&pt71600_snd->fifo_controller);
frames = 0;
for (i = 0; i < readable; i++) {
uint fifo_index = atomic_fifo_get_read_index(
&pt71600_snd->fifo_controller);
struct fifo_packet *packet =
&pt71600_snd->fifo_packet_buffer[fifo_index];
if (packet->start)
break;
/* Check buffer size */
if (frames + packet->num_bytes * 8 / DECODER_BITS_PER_SAMPLE > pt71600_snd->frames_per_buffer - 4) {
*max_frames = frames;
break;
}
frames += snd_pt71600_decode_adpcm_packet(substream,
packet->raw_data,
packet->num_bytes);
pt71600_snd->decoder_pos = packet->pos + packet->num_bytes;
atomic_fifo_advance_read(&pt71600_snd->fifo_controller, 1);
/* Check max frames but don't let decoder fall behind the stream */
if (frames >= *max_frames /* && (int) (pt71600_snd->num_bytes - pt71600_snd->decoder_pos) <= pt71600_snd->decoder_buffer_size */)
break;
}
return frames;
}
static int snd_pt71600_schedule_timer(struct snd_pcm_substream *substream)
{
int ret;
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
uint msec_to_sleep = (substream->runtime->period_size * 1000)
/ pt71600_snd->sample_rate;
uint jiffies_to_sleep = msecs_to_jiffies(msec_to_sleep);
if (jiffies_to_sleep < 2)
jiffies_to_sleep = 2;
ret = mod_timer(&pt71600_snd->decoding_timer, jiffies + jiffies_to_sleep);
if (ret < 0)
pr_err("%s:%d - ERROR in mod_timer, ret = %d\n",
__func__, __LINE__, ret);
return ret;
}
static void snd_pt71600_timer_callback(unsigned long data)
{
uint readable;
uint frames_decoded;
uint frames_to_advance;
uint frames_to_silence;
uint fifo_index;
struct fifo_packet *packet;
bool need_silence = false;
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
/* timer_enabled will be false when stopping a stream. */
smp_rmb();
if (!pt71600_snd->timer_enabled)
return;
pt71600_snd->timer_callback_count++;
frames_to_advance = frames_to_silence = snd_pt71600_calc_frame_advance(pt71600_snd);
switch (pt71600_snd->timer_state) {
case TIMER_STATE_BEFORE_DECODE:
readable = atomic_fifo_available_to_read(
&pt71600_snd->fifo_controller);
if (readable > 0) {
pt71600_snd->timer_state = TIMER_STATE_DURING_DECODE;
/* Fall through into next state. */
} else {
need_silence = true;
break;
}
case TIMER_STATE_DURING_DECODE:
/* Check for start packet */
if (atomic_fifo_available_to_read(&pt71600_snd->fifo_controller) > 0) {
fifo_index = atomic_fifo_get_read_index(&pt71600_snd->fifo_controller);
packet = &pt71600_snd->fifo_packet_buffer[fifo_index];
if (packet->start) {
packet->start = 0;
snd_pt71600_log("Start packet: %u\n", packet->pos);
pt71600_snd->buffer_start_pos = packet->pos;
pt71600_snd->decoder_frames_adjust = 0;
/* Reset decoder values */
if (packet->reset) {
pt71600_snd->prevsample = 0;
pt71600_snd->previndex = 0;
pt71600_snd->idx = FILT_LEN/2-1;;
memset(pt71600_snd->filt_state, 0, sizeof(pt71600_snd->filt_state));
}
}
}
/* Check buffer */
if (s_substream_for_btle != NULL
&& pt71600_snd->buffer_start_pos == pt71600_snd->stream_enable_pos
&& (int) (pt71600_snd->buffer_start_pos - pt71600_snd->stream_disable_pos) >= 0
&& pt71600_snd->num_bytes - pt71600_snd->buffer_start_pos < pt71600_snd->decoder_buffer_size) {
pr_info("BUFFER: %d of %d", pt71600_snd->num_bytes - pt71600_snd->buffer_start_pos, pt71600_snd->decoder_buffer_size);
need_silence = true;
break;
} else {
pr_info("TIMER: %d %d", pt71600_snd->num_bytes, atomic_fifo_available_to_read(&pt71600_snd->fifo_controller));
}
/* Check if we have already decoded the needed packets */
if (pt71600_snd->decoder_frames_adjust < 0 && -pt71600_snd->decoder_frames_adjust >= frames_to_advance) {
pt71600_snd->decoder_frames_adjust += frames_to_advance;
break;
}
/* Adjust frames and check buffer size */
frames_to_advance += pt71600_snd->decoder_frames_adjust;
if (frames_to_advance > pt71600_snd->frames_per_buffer - 4) {
pt71600_snd->decoder_frames_adjust = frames_to_advance - (pt71600_snd->frames_per_buffer - 4);
frames_to_advance = pt71600_snd->frames_per_buffer - 4;
} else {
pt71600_snd->decoder_frames_adjust = 0;
}
/* Decode packets and update adjust frames */
frames_decoded = snd_pt71600_decode_from_fifo(substream, &frames_to_advance);
pt71600_snd->decoder_frames_adjust += frames_to_advance - frames_decoded;
if (pt71600_snd->decoder_frames_adjust > DECODER_MAX_ADJUST_FRAMES)
pt71600_snd->decoder_frames_adjust = DECODER_MAX_ADJUST_FRAMES;
snd_pt71600_log("DECODE: %u of %u, %u %d\n", frames_decoded, frames_to_advance, pt71600_snd->decoder_pos, pt71600_snd->decoder_frames_adjust);
if (frames_decoded > 0) {
if ((int) (pt71600_snd->decoder_pos - pt71600_snd->stream_disable_pos) > 0 && frames_to_advance > frames_decoded)
pr_err("Missing %u frames, decoded %u\n", frames_to_advance - frames_decoded, frames_decoded);
break;
} else {
if ((int) (pt71600_snd->decoder_pos - pt71600_snd->stream_disable_pos) > 0)
pr_err("Buffer empty, generating silence\n");
pt71600_snd->decoder_frames_adjust = 0;
/* no packets read
snd_pt71600_log("No packets read, generating silence"); */
need_silence = true;
}
if (s_substream_for_btle == NULL) {
pt71600_snd->timer_state = TIMER_STATE_AFTER_DECODE;
frames_to_silence = frames_decoded > frames_to_silence ? 0 : frames_to_silence - frames_decoded;
/* Decoder died. Overflowed?
* Fall through into next state. */
} else if ((jiffies - pt71600_snd->previous_jiffies) >
pt71600_snd->timeout_jiffies) {
snd_pt71600_log("audio UNDERFLOW detected\n");
/* Not fatal. Reset timeout. */
pt71600_snd->previous_jiffies = jiffies;
/* ....and generate silence */
/* need_silence = true; */
break;
} else
break;
case TIMER_STATE_AFTER_DECODE:
need_silence = true;
break;
}
/* Write silence before and after decoding. */
if (need_silence) {
pt71600_snd->write_index = snd_pt71600_write_silence(
pt71600_snd,
pt71600_snd->write_index,
frames_to_silence);
/* This can cause snd_pt71600_pcm_trigger() to be called, which
* may try to stop the timer. */
snd_pt71600_handle_frame_advance(substream, frames_to_silence);
}
smp_rmb();
if (pt71600_snd->timer_enabled)
snd_pt71600_schedule_timer(substream);
}
static void snd_pt71600_timer_start(struct snd_pcm_substream *substream)
{
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
pt71600_snd->timer_enabled = true;
pt71600_snd->previous_jiffies = jiffies;
pt71600_snd->timeout_jiffies =
msecs_to_jiffies(SND_ATVR_RUNNING_TIMEOUT_MSEC);
pt71600_snd->timer_callback_count = 0;
smp_wmb();
setup_timer(&pt71600_snd->decoding_timer,
snd_pt71600_timer_callback,
(unsigned long)substream);
snd_pt71600_schedule_timer(substream);
}
static void snd_pt71600_timer_stop(struct snd_pcm_substream *substream, bool sync)
{
int ret;
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
/* Tell timer function not to reschedule itself if it runs. */
pt71600_snd->timer_enabled = false;
smp_wmb();
if (!in_interrupt()) {
/* del_timer_sync will hang if called in the timer callback. */
if (sync)
ret = del_timer_sync(&pt71600_snd->decoding_timer);
else
ret = del_timer(&pt71600_snd->decoding_timer);
if (ret < 0)
pr_err("%s:%d - ERROR del_timer_sync failed, %d\n",
__func__, __LINE__, ret);
}
/*
* Else if we are in an interrupt then we are being called from the
* middle of the snd_pt71600_timer_callback(). The timer will not get
* rescheduled because pt71600_snd->timer_enabled will be false
* at the end of snd_pt71600_timer_callback().
* We do not need to "delete" the timer.
* The del_timer functions just cancel pending timers.
* There are no resources that need to be cleaned up.
*/
}
/* ===================================================================== */
/*
* PCM interface
*/
static int snd_pt71600_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
snd_pt71600_log("%s snd_pt71600_pcm_trigger called", __func__);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
pr_err("%s starting audio\n", __func__);
/* Check if timer is still running */
if (pt71600_snd->timer_state != TIMER_STATE_UNINIT && try_to_del_timer_sync(&pt71600_snd->decoding_timer) < 0)
return -EBUSY;
packet_counter = 0;
pt71600_snd->peak_level = -32768;
pt71600_snd->previous_jiffies = jiffies;
pt71600_snd->timer_state = TIMER_STATE_BEFORE_DECODE;
/* ADPCM decoder state */
pt71600_snd->stream_enable_pos = pt71600_snd->num_bytes;
pt71600_snd->decoder_frames_adjust = 0;
snd_pt71600_timer_start(substream);
/* Enables callback from BTLE driver. */
s_substream_for_btle = substream;
smp_wmb(); /* so other thread will see s_substream_for_btle */
return 0;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
pr_err("Audio stop or suspend.....");
snd_pt71600_log("%s stopping audio, peak = %d, # packets = %d\n",
__func__, pt71600_snd->peak_level, packet_counter);
s_substream_for_btle = NULL;
smp_wmb(); /* so other thread will see s_substream_for_btle */
/* snd_pt71600_timer_stop(substream, false); */
return 0;
}
return -EINVAL;
}
static int snd_pt71600_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pt71600_log("%s, rate = %d, period_size = %d, buffer_size = %d\n",
__func__, (int) runtime->rate,
(int) runtime->period_size,
(int) runtime->buffer_size);
if (runtime->buffer_size > MAX_FRAMES_PER_BUFFER)
return -EINVAL;
pt71600_snd->sample_rate = runtime->rate;
pt71600_snd->frames_per_buffer = runtime->buffer_size;
pt71600_snd->decoder_buffer_size = runtime->rate * DECODER_BUFFER_LATENCY_MS * DECODER_BITS_PER_SAMPLE / 1000 / 8;
return 0; /* TODO - review */
}
static struct snd_pcm_hardware pt71600_pcm_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = USE_FORMATS,
.rates = USE_RATES_MASK,
.rate_min = USE_RATE_MIN,
.rate_max = USE_RATE_MAX,
.channels_min = USE_CHANNELS_MIN,
.channels_max = USE_CHANNELS_MAX,
.buffer_bytes_max = MAX_PCM_BUFFER_SIZE,
.period_bytes_min = MIN_PERIOD_SIZE,
.period_bytes_max = MAX_PERIOD_SIZE,
.periods_min = USE_PERIODS_MIN,
.periods_max = USE_PERIODS_MAX,
.fifo_size = 0,
};
static int snd_pt71600_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
int ret = 0;
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
pt71600_snd->write_index = 0;
smp_wmb();
return ret;
}
static int snd_pt71600_pcm_hw_free(struct snd_pcm_substream *substream)
{
return 0;
}
static int snd_pt71600_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
int ret = atomic_fifo_init(&pt71600_snd->fifo_controller,
MAX_PACKETS_PER_BUFFER);
if (ret)
return ret;
runtime->hw = pt71600_snd->pcm_hw;
if (substream->pcm->device & 1) {
runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
}
if (substream->pcm->device & 2)
runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID);
/*
* Allocate the maximum buffer now and then just use part of it when
* the substream starts. We don't need DMA because it will just
* get written to by the BTLE code.
*/
/* We only use this buffer in the kernel and we do not do
* DMA so vmalloc should be OK. */
pt71600_snd->pcm_buffer = vmalloc(MAX_PCM_BUFFER_SIZE);
if (pt71600_snd->pcm_buffer == NULL) {
pr_err("%s:%d - ERROR PCM buffer allocation failed\n",
__func__, __LINE__);
return -ENOMEM;
}
/* We only use this buffer in the kernel and we do not do
* DMA so vmalloc should be OK.
*/
pt71600_snd->fifo_packet_buffer = vmalloc(MAX_BUFFER_SIZE);
if (pt71600_snd->fifo_packet_buffer == NULL) {
pr_err("%s:%d - ERROR buffer allocation failed\n",
__func__, __LINE__);
vfree(pt71600_snd->pcm_buffer);
pt71600_snd->pcm_buffer = NULL;
return -ENOMEM;
}
/* Set minimum buffer size, to avoid overflow of the pcm buffer.
This affects the period_size, and, as a result, the timer period.
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, USE_RATE_MAX * 200 / 1000, MAX_FRAMES_PER_BUFFER); */
return 0;
}
static int snd_pt71600_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
/* Make sure the timer is not running */
if (pt71600_snd->timer_state != TIMER_STATE_UNINIT)
snd_pt71600_timer_stop(substream, true);
if (pt71600_snd->timer_callback_count > 0)
snd_pt71600_log("processed %d packets in %d timer callbacks\n",
packet_counter, pt71600_snd->timer_callback_count);
if (pt71600_snd->pcm_buffer) {
vfree(pt71600_snd->pcm_buffer);
pt71600_snd->pcm_buffer = NULL;
}
/*
* Use spinlock so we don't free the FIFO when the
* driver is writing to it.
* The s_substream_for_btle should already be NULL by now.
*/
spin_lock(&s_substream_lock);
if (pt71600_snd->fifo_packet_buffer) {
/* Decode all remaining data */
uint i, readable = atomic_fifo_available_to_read(&pt71600_snd->fifo_controller);
if (readable)
snd_pt71600_log("%s: Decoding %d remaining FIFO packets\n", __func__, readable);
for (i = 0; i < readable; i++) {
uint fifo_index = atomic_fifo_get_read_index(&pt71600_snd->fifo_controller);
struct fifo_packet *packet = &pt71600_snd->fifo_packet_buffer[fifo_index];
snd_pt71600_decode_adpcm_packet(NULL, packet->raw_data, packet->num_bytes);
pt71600_snd->decoder_pos = packet->pos + packet->num_bytes;
atomic_fifo_advance_read(&pt71600_snd->fifo_controller, 1);
}
vfree(pt71600_snd->fifo_packet_buffer);
pt71600_snd->fifo_packet_buffer = NULL;
}
spin_unlock(&s_substream_lock);
return 0;
}
static snd_pcm_uframes_t snd_pt71600_pcm_pointer(
struct snd_pcm_substream *substream)
{
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
/* write_index is written by another driver thread */
smp_rmb();
return pt71600_snd->write_index;
}
static int snd_pt71600_pcm_copy(struct snd_pcm_substream *substream,
int channel, snd_pcm_uframes_t pos,
void __user *dst, snd_pcm_uframes_t count)
{
struct snd_pt71600 *pt71600_snd = snd_pcm_substream_chip(substream);
short *output = (short *)dst;
/* TODO Needs to be modified if we support more than 1 channel. */
/*
* Copy from PCM buffer to user memory.
* Are we reading past the end of the buffer?
*/
if ((pos + count) > pt71600_snd->frames_per_buffer) {
const int16_t *source = &pt71600_snd->pcm_buffer[pos];
int16_t *destination = output;
size_t num_frames = pt71600_snd->frames_per_buffer - pos;
size_t num_bytes = num_frames * sizeof(int16_t);
memcpy(destination, source, num_bytes);
source = &pt71600_snd->pcm_buffer[0];
destination += num_frames;
num_frames = count - num_frames;
num_bytes = num_frames * sizeof(int16_t);
memcpy(destination, source, num_bytes);
} else {
const int16_t *source = &pt71600_snd->pcm_buffer[pos];
int16_t *destination = output;
size_t num_bytes = count * sizeof(int16_t);
memcpy(destination, source, num_bytes);
}
return 0;
}
static int snd_pt71600_pcm_silence(struct snd_pcm_substream *substream,
int channel, snd_pcm_uframes_t pos,
snd_pcm_uframes_t count)
{
return 0; /* Do nothing. Only used by output? */
}
static struct snd_pcm_ops snd_pt71600_pcm_ops_no_buf = {
.open = snd_pt71600_pcm_open,
.close = snd_pt71600_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_pt71600_pcm_hw_params,
.hw_free = snd_pt71600_pcm_hw_free,
.prepare = snd_pt71600_pcm_prepare,
.trigger = snd_pt71600_pcm_trigger,
.pointer = snd_pt71600_pcm_pointer,
.copy = snd_pt71600_pcm_copy,
.silence = snd_pt71600_pcm_silence,
};
static int snd_card_pt71600_pcm(struct snd_pt71600 *pt71600_snd,
int device,
int substreams)
{
struct snd_pcm *pcm;
struct snd_pcm_ops *ops;
int err;
err = snd_pcm_new(pt71600_snd->card, PT71600_REMOTE_PCM_DEVICE_ID, device,
0, /* no playback substreams */
1, /* 1 capture substream */
&pcm);
if (err < 0)
return err;
pt71600_snd->pcm = pcm;
ops = &snd_pt71600_pcm_ops_no_buf;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ops);
pcm->private_data = pt71600_snd;
pcm->info_flags = 0;
strncpy(pcm->name, PT71600_REMOTE_PCM_DEVICE_NAME, sizeof(pcm->name));
return 0;
}
static int pt71600_snd_initialize(struct hid_device *hdev)
{
struct snd_card *card;
struct snd_pt71600 *pt71600_snd;
int err;
int i;
pr_err("Initializing PT71600 HID driver");
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev]) {
dev++;
return -ENOENT;
}
err = snd_card_create(index[dev], PT71600_REMOTE_AUDIO_DEVICE_ID, THIS_MODULE,
sizeof(struct snd_pt71600), &card);
if (err < 0) {
pr_err("%s: snd_card_create() returned err %d\n",
__func__, err);
return err;
}
hid_set_drvdata(hdev, card);
pt71600_snd = card->private_data;
pt71600_snd->card = card;
pt71600_snd->timer_state = TIMER_STATE_UNINIT;
pt71600_snd->num_bytes = 0;
pt71600_snd->buffer_start_pos = 0;
pt71600_snd->stream_enable_pos = 0;
pt71600_snd->stream_disable_pos = 0;
pt71600_snd->stream_reset_pos = 0;
pt71600_snd->decoder_pos = 0;
for (i = 0; i < MAX_PCM_DEVICES && i < pcm_devs[dev]; i++) {
if (pcm_substreams[dev] < 1)
pcm_substreams[dev] = 1;
if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
err = snd_card_pt71600_pcm(pt71600_snd, i, pcm_substreams[dev]);
if (err < 0) {
pr_err("%s: snd_card_pt71600_pcm() returned err %d\n",
__func__, err);
goto __nodev;
}
}
pt71600_snd->pcm_hw = pt71600_pcm_hardware;
strncpy(card->driver, PT71600_REMOTE_AUDIO_DRIVER_NAME, sizeof(card->driver));
strncpy(card->shortname, PT71600_REMOTE_AUDIO_DEVICE_NAME_SHORT, sizeof(card->shortname));
snprintf(card->longname, sizeof(card->longname), PT71600_REMOTE_AUDIO_DEVICE_NAME_LONG, dev + 1);
snd_card_set_dev(card, &hdev->dev);
err = snd_card_register(card);
if (!err) {
/* Store snd_pt71600 struct */
s_pt71600_snd = pt71600_snd;
return 0;
}
__nodev:
snd_card_free(card);
return err;
}
static int pt71600_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
#if (DEBUG_HID_RAW_INPUT == 1)
int i;
pr_info("%s: report->id = 0x%x, size = %d\n",
__func__, report->id, size);
/* if (size < 20) { */
for (i = 1; i < size; i++) {
pr_info("data[%d] = 0x%02x\n", i, data[i]);
}
/* } */
#endif
if ((data[1] == 0x0C && data[2] == 0x02) || (data[1] == 0xCC && data[2] == 0xCC)) {
struct snd_pcm_substream *substream = s_substream_for_btle;
if (substream != NULL || s_pt71600_snd != NULL) {
struct snd_pt71600 *pt71600_snd = substream != NULL ? snd_pcm_substream_chip(substream) : s_pt71600_snd;
snd_pt71600_log("Stream Enable 0x%x, 0x%x\n", data[1], data[2]);
/* Mark stream enable/disable position */
if (data[1] == 0x0C && data[2] == 0x02) {
pt71600_snd->stream_enable_pos = pt71600_snd->num_bytes;
pt71600_snd->stream_reset_pos = pt71600_snd->num_bytes;
if (substream == NULL) {
snd_pt71600_log("Stream enabled with no substream. Reset decoder.\n");
/* Wait for timer callback to finish if running. */
while (pt71600_snd->timer_state != TIMER_STATE_UNINIT
&& try_to_del_timer_sync(&pt71600_snd->decoding_timer) < 0)
;
/* Flush the FIFO */
spin_lock(&s_substream_lock);
atomic_fifo_init(&pt71600_snd->fifo_controller, MAX_PACKETS_PER_BUFFER);
spin_unlock(&s_substream_lock);
}
} else {/* 0xCC 0xCC */
pt71600_snd->stream_disable_pos = pt71600_snd->num_bytes;
}
}
return 0;
}
if (report->id == ADPCM_AUDIO_REPORT_ID_2) {
audio_dec(&data[1], PACKET_TYPE_ADPCM, size - 1);
/* we've handled the event */
return 1;
}
/* let the event through for regular input processing */
return 0;
}
static int pt71600_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
bool supported = false;
/* since vendor/product id filter doesn't work yet, because
* Bluedroid is unable to get the vendor/product id, we
* have to filter on name
*/
pr_info("%s: hdev->name = %s, vendor_id = %d, product_id = %d, num %d\n",
__func__, hdev->name, hdev->vendor, hdev->product, num_remotes);
if (hdev->vendor == 0x2B54 && hdev->product == 0x1600)
supported = true;
if (!supported) {
ret = -ENODEV;
pr_err("Error! Device is not compatible with PT71600 HID: %s", hdev->name);
goto err_match;
}
pr_info("%s: Found supported remote %s\n", __func__, hdev->name);
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "hid parse failed\n");
goto err_parse;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto err_start;
}
if (!card_created) {
ret = pt71600_snd_initialize(hdev);
if (ret)
goto err_stop;
card_created = true;
}
pr_info("%s: num_remotes %d->%d\n", __func__, num_remotes, num_remotes + 1);
num_remotes++;
return 0;
err_stop:
hid_hw_stop(hdev);
err_start:
err_parse:
err_match:
return ret;
}
static void pt71600_remove(struct hid_device *hdev)
{
pr_info("%s: hdev->name = %s removed, num %d->%d\n",
__func__, hdev->name, num_remotes, num_remotes - 1);
num_remotes--;
hid_hw_stop(hdev);
}
static const struct hid_device_id pt71600_devices[] = {
{HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_PT71600, USB_DEVICE_ID_PT71600)},
{ }
};
MODULE_DEVICE_TABLE(hid, pt71600_devices);
static struct hid_driver pt71600_driver = {
.name = PT71600_REMOTE_HID_DRIVER_NAME,
.id_table = pt71600_devices,
.raw_event = pt71600_raw_event,
.probe = pt71600_probe,
.remove = pt71600_remove,
};
static int proc_num_remotes_read(struct seq_file *sfp, void *data)
{
if (sfp)
/* seq_printf(sfp, "%d\n", num_remotes); */
seq_write(sfp, &num_remotes, sizeof(num_remotes));
return 0;
}
static int proc_num_remotes_open(struct inode *inode, struct file *file)
{
/* return single_open(file, proc_num_remotes_read, PDE_DATA(inode)); */
return single_open(file, proc_num_remotes_read, inode->i_private);
}
static const struct file_operations pt71600_proc_fops = {
.owner = THIS_MODULE,
.open = proc_num_remotes_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int pt71600_init(void)
{
int ret;
struct proc_dir_entry *r;
pr_err("PT71600 Driver - version %s! \n", PT71600_DRIVER_VERSION);
r = proc_create_data("pt71600-num-remotes", 0, NULL, &pt71600_proc_fops, NULL);
if (r == NULL)
pr_err("%s: can't register Proc Entry\n", __func__);
ret = hid_register_driver(&pt71600_driver);
if (ret)
pr_err("%s: can't register AndroidTV Remote driver\n", __func__);
return ret;
}
static void pt71600_exit(void)
{
hid_unregister_driver(&pt71600_driver);
/* switch_set_state(&h2w_switch, BIT_NO_HEADSET);
switch_dev_unregister(&h2w_switch); */
remove_proc_entry("pt71600-num-remotes", NULL);
}
module_init(pt71600_init);
module_exit(pt71600_exit);
MODULE_LICENSE("GPL");