/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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/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");