summaryrefslogtreecommitdiff
path: root/drivers/misc/qcom/qdsp6v2/audio_utils_aio.h
blob: 9c53f58b746f39575e19edc0ad24cfeec54944fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/* Copyright (C) 2008 Google, Inc.
 * Copyright (C) 2008 HTC Corporation
 * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved.
 *
 * 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/fs.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/wakelock.h>
#include <linux/msm_audio.h>
#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/msm_ion.h>
#include <asm/ioctls.h>
#include <asm/atomic.h>
#include "q6audio_common.h"

#define TUNNEL_MODE     0x0000
#define NON_TUNNEL_MODE 0x0001

#define ADRV_STATUS_AIO_INTF 0x00000001 /* AIO interface */
#define ADRV_STATUS_FSYNC 0x00000008
#define ADRV_STATUS_PAUSE 0x00000010
#define AUDIO_DEC_EOS_SET  0x00000001
#define AUDIO_DEC_EOF_SET  0x00000010
#define AUDIO_EVENT_NUM		10

#define __CONTAINS(r, v, l) ({                                  \
	typeof(r) __r = r;                                      \
	typeof(v) __v = v;                                      \
	typeof(v) __e = __v + l;                                \
	int res = ((__v >= __r->vaddr) &&                       \
		(__e <= __r->vaddr + __r->len));                \
	res;                                                    \
})

#define CONTAINS(r1, r2) ({                                     \
	typeof(r2) __r2 = r2;                                   \
	__CONTAINS(r1, __r2->vaddr, __r2->len);                 \
})

#define IN_RANGE(r, v) ({                                       \
	typeof(r) __r = r;                                      \
	typeof(v) __vv = v;                                     \
	int res = ((__vv >= __r->vaddr) &&                      \
		(__vv < (__r->vaddr + __r->len)));              \
	res;                                                    \
})

#define OVERLAPS(r1, r2) ({                                     \
	typeof(r1) __r1 = r1;                                   \
	typeof(r2) __r2 = r2;                                   \
	typeof(__r2->vaddr) __v = __r2->vaddr;                  \
	typeof(__v) __e = __v + __r2->len - 1;                  \
	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e)); \
	res;                                                    \
})

struct timestamp {
	u32 lowpart;
	u32 highpart;
} __packed;

struct meta_out_dsp {
	u32 offset_to_frame;
	u32 frame_size;
	u32 encoded_pcm_samples;
	u32 msw_ts;
	u32 lsw_ts;
	u32 nflags;
} __packed;

struct dec_meta_in {
	unsigned char reserved[18];
	unsigned short offset;
	struct timestamp ntimestamp;
	unsigned int nflags;
} __packed;

struct dec_meta_out {
	unsigned int reserved[7];
	unsigned int num_of_frames;
	struct meta_out_dsp meta_out_dsp[];
} __packed;

/* General meta field to store meta info
locally */
union  meta_data {
	struct dec_meta_out meta_out;
	struct dec_meta_in meta_in;
} __packed;

/* per device wakeup source manager */
struct ws_mgr {
	struct mutex       ws_lock;
	uint32_t           ref_cnt;
};

#define PCM_BUF_COUNT           (2)
/* Buffer with meta */
#define PCM_BUFSZ_MIN           ((4*1024) + sizeof(struct dec_meta_out))

/* FRAME_NUM must be a power of two */
#define FRAME_NUM               (2)
#define FRAME_SIZE	((4*1536) + sizeof(struct dec_meta_in))

struct audio_aio_ion_region {
	struct list_head list;
	struct ion_handle *handle;
	int fd;
	void *vaddr;
	phys_addr_t paddr;
	void *kvaddr;
	unsigned long len;
	unsigned ref_cnt;
};

struct audio_aio_event {
	struct list_head list;
	int event_type;
	union msm_audio_event_payload payload;
};

struct audio_aio_buffer_node {
	struct list_head list;
	struct msm_audio_aio_buf buf;
	unsigned long paddr;
	uint32_t token;
	void            *kvaddr;
	union meta_data meta_info;
};

struct q6audio_aio;
struct audio_aio_drv_operations {
	void (*out_flush) (struct q6audio_aio *);
	void (*in_flush) (struct q6audio_aio *);
};

struct q6audio_aio {
	atomic_t in_bytes;
	atomic_t in_samples;

	struct msm_audio_stream_config str_cfg;
	struct msm_audio_buf_cfg        buf_cfg;
	struct msm_audio_config pcm_cfg;
	void *codec_cfg;

	struct audio_client *ac;

	struct mutex lock;
	struct mutex read_lock;
	struct mutex write_lock;
	struct mutex get_event_lock;
	wait_queue_head_t cmd_wait;
	wait_queue_head_t write_wait;
	wait_queue_head_t event_wait;
	spinlock_t dsp_lock;
	spinlock_t event_queue_lock;

	struct miscdevice *miscdevice;
	uint32_t wakelock_voted;
	struct ws_mgr *audio_ws_mgr;

#ifdef CONFIG_DEBUG_FS
	struct dentry *dentry;
#endif
	struct list_head out_queue;     /* queue to retain output buffers */
	struct list_head in_queue;      /* queue to retain input buffers */
	struct list_head free_event_queue;
	struct list_head event_queue;
	struct list_head ion_region_queue;     /* protected by lock */
	struct ion_client *client;
	struct audio_aio_drv_operations drv_ops;
	union msm_audio_event_payload eos_write_payload;
	uint32_t device_events;
	uint16_t volume;
	uint32_t drv_status;
	int event_abort;
	int eos_rsp;
	int eos_flag;
	int opened;
	int enabled;
	int stopped;
	int feedback;
	int rflush;             /* Read  flush */
	int wflush;             /* Write flush */
	bool reset_event;
	long (*codec_ioctl)(struct file *, unsigned int, unsigned long);
	long (*codec_compat_ioctl)(struct file *, unsigned int, unsigned long);
};

void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
				uint32_t *payload);

void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
			uint32_t *payload);

int insert_eos_buf(struct q6audio_aio *audio,
		struct audio_aio_buffer_node *buf_node);

void extract_meta_out_info(struct q6audio_aio *audio,
		struct audio_aio_buffer_node *buf_node, int dir);

int audio_aio_open(struct q6audio_aio *audio, struct file *file);
int audio_aio_enable(struct q6audio_aio  *audio);
void audio_aio_post_event(struct q6audio_aio *audio, int type,
		union msm_audio_event_payload payload);
int audio_aio_release(struct inode *inode, struct file *file);
int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync);
void audio_aio_async_out_flush(struct q6audio_aio *audio);
void audio_aio_async_in_flush(struct q6audio_aio *audio);
void audio_aio_ioport_reset(struct q6audio_aio *audio);
int enable_volume_ramp(struct q6audio_aio *audio);
#ifdef CONFIG_DEBUG_FS
int audio_aio_debug_open(struct inode *inode, struct file *file);
ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
			size_t count, loff_t *ppos);
#endif