blob: 0549656acb43c96f67e0ceb0f3584c08f3ed066b [file] [log] [blame]
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -08001/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/errno.h>
17#include <linux/delay.h>
18#include <linux/debugfs.h>
19#include <linux/usb/audio.h>
20#include <linux/uaccess.h>
21#include <sound/pcm.h>
22#include <sound/core.h>
23#include <sound/asound.h>
24#include <linux/usb.h>
25#include <linux/qmi_encdec.h>
26#include <soc/qcom/msm_qmi_interface.h>
Hemant Kumard2a54502016-03-22 16:35:16 -070027#include <linux/iommu.h>
28#include <linux/platform_device.h>
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -080029
30#include "usbaudio.h"
31#include "card.h"
32#include "helper.h"
33#include "pcm.h"
34#include "usb_audio_qmi_v01.h"
35
36#define SND_PCM_CARD_NUM_MASK 0xffff0000
37#define SND_PCM_DEV_NUM_MASK 0xff00
38#define SND_PCM_STREAM_DIRECTION 0xff
39
Hemant Kumard2a54502016-03-22 16:35:16 -070040#define PREPEND_SID_TO_IOVA(iova, sid) (u64)(((u64)(iova)) | \
41 (((u64)sid) << 32))
42
43/* event ring iova base address */
44#define IOVA_BASE 0x1000
45
46#define IOVA_DCBA_BASE 0x2000
47#define IOVA_XFER_RING_BASE (IOVA_DCBA_BASE + PAGE_SIZE * (SNDRV_CARDS + 1))
48#define IOVA_XFER_BUF_BASE (IOVA_XFER_RING_BASE + PAGE_SIZE * SNDRV_CARDS * 32)
49#define IOVA_XFER_RING_MAX (IOVA_XFER_BUF_BASE - PAGE_SIZE)
50#define IOVA_XFER_BUF_MAX (0xfffff000 - PAGE_SIZE)
51
Hemant Kumarbeb99fd2016-10-10 16:49:34 -070052#define MAX_XFER_BUFF_LEN (24 * PAGE_SIZE)
Hemant Kumard2a54502016-03-22 16:35:16 -070053
54struct iova_info {
55 struct list_head list;
56 unsigned long start_iova;
57 size_t size;
58 bool in_use;
59};
60
61struct intf_info {
62 unsigned long data_xfer_ring_va;
63 size_t data_xfer_ring_size;
64 unsigned long sync_xfer_ring_va;
65 size_t sync_xfer_ring_size;
66 unsigned long xfer_buf_va;
67 size_t xfer_buf_size;
68 phys_addr_t xfer_buf_pa;
69 u8 *xfer_buf;
Hemant Kumar89fa7b92016-10-27 19:56:31 -070070 u8 pcm_card_num;
71 u8 pcm_dev_num;
72 u8 direction;
Hemant Kumard2a54502016-03-22 16:35:16 -070073 bool in_use;
74};
75
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -080076struct uaudio_dev {
Hemant Kumard2a54502016-03-22 16:35:16 -070077 struct usb_device *udev;
78 unsigned int card_num;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -080079 atomic_t in_use;
80 struct kref kref;
Hemant Kumard2a54502016-03-22 16:35:16 -070081 unsigned long dcba_iova;
82 size_t dcba_size;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -080083 wait_queue_head_t disconnect_wq;
Hemant Kumard2a54502016-03-22 16:35:16 -070084
85 /* interface specific */
86 int num_intf;
87 struct intf_info *info;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -080088};
89
90static struct uaudio_dev uadev[SNDRV_CARDS];
91
Hemant Kumard2a54502016-03-22 16:35:16 -070092struct uaudio_qmi_dev {
93 struct device *dev;
94 u32 sid;
95 u32 intr_num;
96 struct iommu_domain *domain;
97
98 /* list to keep track of available iova */
99 struct list_head dcba_list;
100 size_t dcba_iova_size;
101 unsigned long curr_dcba_iova;
102 struct list_head xfer_ring_list;
103 size_t xfer_ring_iova_size;
104 unsigned long curr_xfer_ring_iova;
105 struct list_head xfer_buf_list;
106 size_t xfer_buf_iova_size;
107 unsigned long curr_xfer_buf_iova;
108 /* bit fields representing pcm card enabled */
109 unsigned long card_slot;
110 /* cache event ring phys addr */
111 u64 er_phys_addr;
112};
113
114static struct uaudio_qmi_dev *uaudio_qdev;
115
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800116struct uaudio_qmi_svc {
117 struct qmi_handle *uaudio_svc_hdl;
118 void *curr_conn;
119 struct work_struct recv_msg_work;
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700120 struct work_struct qmi_disconnect_work;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800121 struct workqueue_struct *uaudio_wq;
122 ktime_t t_request_recvd;
123 ktime_t t_resp_sent;
124};
125
126static struct uaudio_qmi_svc *uaudio_svc;
127
128static struct msg_desc uaudio_stream_req_desc = {
129 .max_msg_len = QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN,
130 .msg_id = QMI_UAUDIO_STREAM_REQ_V01,
131 .ei_array = qmi_uaudio_stream_req_msg_v01_ei,
132};
133
134static struct msg_desc uaudio_stream_resp_desc = {
135 .max_msg_len = QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN,
136 .msg_id = QMI_UAUDIO_STREAM_RESP_V01,
137 .ei_array = qmi_uaudio_stream_resp_msg_v01_ei,
138};
139
Vamsi Krishna Samavedam1e634532016-09-13 14:09:37 -0700140static struct msg_desc uaudio_stream_ind_desc = {
141 .max_msg_len = QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN,
142 .msg_id = QMI_UADUIO_STREAM_IND_V01,
143 .ei_array = qmi_uaudio_stream_ind_msg_v01_ei,
144};
145
Hemant Kumard2a54502016-03-22 16:35:16 -0700146enum mem_type {
147 MEM_EVENT_RING,
148 MEM_DCBA,
149 MEM_XFER_RING,
150 MEM_XFER_BUF,
151};
152
Hemant Kumara4f61012016-10-13 15:41:55 -0700153enum usb_qmi_audio_format {
154 USB_QMI_PCM_FORMAT_S8 = 0,
155 USB_QMI_PCM_FORMAT_U8,
156 USB_QMI_PCM_FORMAT_S16_LE,
157 USB_QMI_PCM_FORMAT_S16_BE,
158 USB_QMI_PCM_FORMAT_U16_LE,
159 USB_QMI_PCM_FORMAT_U16_BE,
160 USB_QMI_PCM_FORMAT_S24_LE,
161 USB_QMI_PCM_FORMAT_S24_BE,
162 USB_QMI_PCM_FORMAT_U24_LE,
163 USB_QMI_PCM_FORMAT_U24_BE,
164 USB_QMI_PCM_FORMAT_S24_3LE,
165 USB_QMI_PCM_FORMAT_S24_3BE,
166 USB_QMI_PCM_FORMAT_U24_3LE,
167 USB_QMI_PCM_FORMAT_U24_3BE,
168 USB_QMI_PCM_FORMAT_S32_LE,
169 USB_QMI_PCM_FORMAT_S32_BE,
170 USB_QMI_PCM_FORMAT_U32_LE,
171 USB_QMI_PCM_FORMAT_U32_BE,
172};
173
Hemant Kumard2a54502016-03-22 16:35:16 -0700174static unsigned long uaudio_get_iova(unsigned long *curr_iova,
175 size_t *curr_iova_size, struct list_head *head, size_t size)
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800176{
Hemant Kumard2a54502016-03-22 16:35:16 -0700177 struct iova_info *info, *new_info = NULL;
178 struct list_head *curr_head;
179 unsigned long va = 0;
180 size_t tmp_size = size;
181 bool found = false;
182
183 if (size % PAGE_SIZE) {
184 pr_err("%s: size %zu is not page size multiple\n", __func__,
185 size);
186 goto done;
187 }
188
189 if (size > *curr_iova_size) {
190 pr_err("%s: size %zu > curr size %zu\n", __func__, size,
191 *curr_iova_size);
192 goto done;
193 }
194 if (*curr_iova_size == 0) {
195 pr_err("%s: iova mapping is full\n", __func__);
196 goto done;
197 }
198
199 list_for_each_entry(info, head, list) {
200 /* exact size iova_info */
201 if (!info->in_use && info->size == size) {
202 info->in_use = true;
203 va = info->start_iova;
204 *curr_iova_size -= size;
205 found = true;
206 pr_debug("%s: exact size :%zu found\n", __func__, size);
207 goto done;
208 } else if (!info->in_use && tmp_size >= info->size) {
209 if (!new_info)
210 new_info = info;
211 pr_debug("%s: partial size: %zu found\n", __func__,
212 info->size);
213 tmp_size -= info->size;
214 if (tmp_size)
215 continue;
216
217 va = new_info->start_iova;
218 for (curr_head = &new_info->list; curr_head !=
219 &info->list; curr_head = curr_head->next) {
220 new_info = list_entry(curr_head, struct
221 iova_info, list);
222 new_info->in_use = true;
223 }
224 info->in_use = true;
225 *curr_iova_size -= size;
226 found = true;
227 goto done;
228 } else {
229 /* iova region in use */
230 new_info = NULL;
231 tmp_size = size;
232 }
233 }
234
235 info = kzalloc(sizeof(struct iova_info), GFP_KERNEL);
236 if (!info) {
237 va = 0;
238 goto done;
239 }
240
241 va = info->start_iova = *curr_iova;
242 info->size = size;
243 info->in_use = true;
244 *curr_iova += size;
245 *curr_iova_size -= size;
246 found = true;
247 list_add_tail(&info->list, head);
248
249done:
250 if (!found)
251 pr_err("%s: unable to find %zu size iova\n", __func__, size);
252 else
253 pr_debug("%s: va:%lu curr_iova:%lu curr_iova_size:%zu\n",
254 __func__, va, *curr_iova, *curr_iova_size);
255
256 return va;
257}
258
259static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
260 size_t size)
261{
262 unsigned long va = 0;
263 bool map = true;
264 int ret;
265
266 switch (mtype) {
267 case MEM_EVENT_RING:
268 va = IOVA_BASE;
269 /* er already mapped */
270 if (uaudio_qdev->er_phys_addr == pa)
271 map = false;
272 break;
273 case MEM_DCBA:
274 va = uaudio_get_iova(&uaudio_qdev->curr_dcba_iova,
275 &uaudio_qdev->dcba_iova_size, &uaudio_qdev->dcba_list, size);
276 break;
277 case MEM_XFER_RING:
278 va = uaudio_get_iova(&uaudio_qdev->curr_xfer_ring_iova,
279 &uaudio_qdev->xfer_ring_iova_size, &uaudio_qdev->xfer_ring_list,
280 size);
281 break;
282 case MEM_XFER_BUF:
283 va = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova,
284 &uaudio_qdev->xfer_buf_iova_size, &uaudio_qdev->xfer_buf_list,
285 size);
286 break;
287 default:
288 pr_err("%s: unknown mem type %d\n", __func__, mtype);
289 }
290
291 if (!va)
292 map = false;
293
294 if (!map)
295 goto done;
296
297 pr_debug("%s: map pa %pa to iova %lu for memtype %d\n", __func__, &pa,
298 va, mtype);
299 ret = iommu_map(uaudio_qdev->domain, va, pa, size,
300 IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
301 if (ret)
302 pr_err("%s:failed to map pa:%pa iova:%lu memtype:%d ret:%d\n",
303 __func__, &pa, va, mtype, ret);
304done:
305 return va;
306}
307
308static void uaudio_put_iova(unsigned long va, size_t size, struct list_head
309 *head, size_t *curr_iova_size)
310{
311 struct iova_info *info;
312 size_t tmp_size = size;
313 bool found = false;
314
315 list_for_each_entry(info, head, list) {
316 if (info->start_iova == va) {
317 if (!info->in_use) {
318 pr_err("%s: va %lu is not in use\n", __func__,
319 va);
320 return;
321 }
322 found = true;
323 info->in_use = false;
324 if (info->size == size)
325 goto done;
326 }
327
328 if (found && tmp_size >= info->size) {
329 info->in_use = false;
330 tmp_size -= info->size;
331 if (!tmp_size)
332 goto done;
333 }
334 }
335
336 if (!found) {
337 pr_err("%s: unable to find the va %lu\n", __func__, va);
338 return;
339 }
340done:
341 *curr_iova_size += size;
342 pr_debug("%s: curr_iova_size %zu\n", __func__, *curr_iova_size);
343}
344
345static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
346 size_t size)
347{
348 size_t umap_size;
349 bool unmap = true;
350
351 if (!va || !size)
352 return;
353
354 switch (mtype) {
355 case MEM_EVENT_RING:
356 if (uaudio_qdev->er_phys_addr)
357 uaudio_qdev->er_phys_addr = 0;
358 else
359 unmap = false;
360 break;
361 case MEM_DCBA:
362 uaudio_put_iova(va, size, &uaudio_qdev->dcba_list,
363 &uaudio_qdev->dcba_iova_size);
364 break;
365 case MEM_XFER_RING:
366 uaudio_put_iova(va, size, &uaudio_qdev->xfer_ring_list,
367 &uaudio_qdev->xfer_ring_iova_size);
368 break;
369 case MEM_XFER_BUF:
370 uaudio_put_iova(va, size, &uaudio_qdev->xfer_buf_list,
371 &uaudio_qdev->xfer_buf_iova_size);
372 break;
373 default:
374 pr_err("%s: unknown mem type %d\n", __func__, mtype);
375 unmap = false;
376 }
377
378 if (!unmap)
379 return;
380
381 pr_debug("%s: unmap iova %lu for memtype %d\n", __func__, va, mtype);
382
383 umap_size = iommu_unmap(uaudio_qdev->domain, va, size);
384 if (umap_size != size)
385 pr_err("%s: unmapped size %zu for iova %lu\n", __func__,
386 umap_size, va);
387}
388
389static int prepare_qmi_response(struct snd_usb_substream *subs,
390 struct qmi_uaudio_stream_resp_msg_v01 *resp, u32 xfer_buf_len,
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700391 int card_num, int pcm_dev_num)
Hemant Kumard2a54502016-03-22 16:35:16 -0700392{
393 int ret = -ENODEV;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800394 struct usb_interface *iface;
395 struct usb_host_interface *alts;
396 struct usb_interface_descriptor *altsd;
397 struct usb_host_endpoint *ep;
398 struct uac_format_type_i_continuous_descriptor *fmt;
399 struct uac_format_type_i_discrete_descriptor *fmt_v1;
400 struct uac_format_type_i_ext_descriptor *fmt_v2;
401 struct uac1_as_header_descriptor *as;
402 struct uac1_ac_header_descriptor *ac;
403 int protocol;
Hemant Kumard2a54502016-03-22 16:35:16 -0700404 u8 *xfer_buf;
405 u32 len, mult, remainder;
406 unsigned long va, tr_data_va = 0, tr_sync_va = 0, dcba_va = 0,
407 xfer_buf_va = 0;
408 phys_addr_t xhci_pa, xfer_buf_pa;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800409
410 iface = usb_ifnum_to_if(subs->dev, subs->interface);
411 if (!iface) {
412 pr_err("%s: interface # %d does not exist\n", __func__,
413 subs->interface);
414 goto err;
415 }
416
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700417 if (uadev[card_num].info &&
418 uadev[card_num].info[subs->interface].in_use) {
419 pr_err("%s interface# %d already in use card# %d\n", __func__,
420 subs->interface, card_num);
421 ret = -EBUSY;
422 goto err;
423 }
424
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800425 alts = &iface->altsetting[subs->altset_idx];
426 altsd = get_iface_desc(alts);
427 protocol = altsd->bInterfaceProtocol;
428
429 /* get format type */
430 fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
431 UAC_FORMAT_TYPE);
432 if (!fmt) {
433 pr_err("%s: %u:%d : no UAC_FORMAT_TYPE desc\n", __func__,
434 subs->interface, subs->altset_idx);
435 goto err;
436 }
437
438 if (protocol == UAC_VERSION_1) {
439 as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
440 UAC_AS_GENERAL);
441 if (!as) {
442 pr_err("%s: %u:%d : no UAC_AS_GENERAL desc\n", __func__,
443 subs->interface, subs->altset_idx);
444 goto err;
445 }
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700446 resp->data_path_delay = as->bDelay;
447 resp->data_path_delay_valid = 1;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800448 fmt_v1 = (struct uac_format_type_i_discrete_descriptor *)fmt;
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700449 resp->usb_audio_subslot_size = fmt_v1->bSubframeSize;
450 resp->usb_audio_subslot_size_valid = 1;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800451 } else if (protocol == UAC_VERSION_2) {
452 fmt_v2 = (struct uac_format_type_i_ext_descriptor *)fmt;
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700453 resp->usb_audio_subslot_size = fmt_v2->bSubslotSize;
454 resp->usb_audio_subslot_size_valid = 1;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800455 } else {
456 pr_err("%s: unknown protocol version %x\n", __func__, protocol);
457 goto err;
458 }
459
460 ac = snd_usb_find_csint_desc(alts->extra,
461 alts->extralen,
462 NULL, UAC_HEADER);
463 if (!ac) {
464 pr_err("%s: %u:%d : no UAC_HEADER desc\n", __func__,
465 subs->interface, subs->altset_idx);
466 goto err;
467 }
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700468 resp->usb_audio_spec_revision = ac->bcdADC;
469 resp->usb_audio_spec_revision_valid = 1;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800470
471 resp->slot_id = subs->dev->slot_id;
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700472 resp->slot_id_valid = 1;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800473
474 memcpy(&resp->std_as_opr_intf_desc, &alts->desc, sizeof(alts->desc));
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700475 resp->std_as_opr_intf_desc_valid = 1;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800476
477 ep = usb_pipe_endpoint(subs->dev, subs->data_endpoint->pipe);
478 if (!ep) {
479 pr_err("%s: data ep # %d context is null\n", __func__,
480 subs->data_endpoint->ep_num);
481 goto err;
482 }
483 memcpy(&resp->std_as_data_ep_desc, &ep->desc, sizeof(ep->desc));
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700484 resp->std_as_data_ep_desc_valid = 1;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800485
Hemant Kumard2a54502016-03-22 16:35:16 -0700486 xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep);
487 if (!xhci_pa) {
488 pr_err("%s:failed to get data ep ring dma address\n", __func__);
489 goto err;
490 }
491
492 resp->xhci_mem_info.tr_data.pa = xhci_pa;
493
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800494 if (subs->sync_endpoint) {
495 ep = usb_pipe_endpoint(subs->dev, subs->sync_endpoint->pipe);
496 if (!ep) {
Hemant Kumar44cefc52016-12-06 18:34:40 -0800497 pr_debug("%s: implicit fb on data ep\n", __func__);
498 goto skip_sync_ep;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800499 }
500 memcpy(&resp->std_as_sync_ep_desc, &ep->desc, sizeof(ep->desc));
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700501 resp->std_as_sync_ep_desc_valid = 1;
502
Hemant Kumard2a54502016-03-22 16:35:16 -0700503 xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep);
504 if (!xhci_pa) {
505 pr_err("%s:failed to get sync ep ring dma address\n",
506 __func__);
507 goto err;
508 }
509 resp->xhci_mem_info.tr_sync.pa = xhci_pa;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800510 }
511
Hemant Kumar44cefc52016-12-06 18:34:40 -0800512skip_sync_ep:
Hemant Kumard2a54502016-03-22 16:35:16 -0700513 resp->interrupter_num = uaudio_qdev->intr_num;
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700514 resp->interrupter_num_valid = 1;
Hemant Kumard2a54502016-03-22 16:35:16 -0700515
516 /* map xhci data structures PA memory to iova */
517
518 /* event ring */
519 ret = usb_sec_event_ring_setup(subs->dev, resp->interrupter_num);
520 if (ret) {
521 pr_err("%s: failed to setup sec event ring ret %d\n", __func__,
522 ret);
523 goto err;
524 }
525 xhci_pa = usb_get_sec_event_ring_dma_addr(subs->dev,
526 resp->interrupter_num);
527 if (!xhci_pa) {
528 pr_err("%s: failed to get sec event ring dma address\n",
529 __func__);
530 goto err;
531 }
532
533 va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE);
534 if (!va)
535 goto err;
536
537 resp->xhci_mem_info.evt_ring.va = PREPEND_SID_TO_IOVA(va,
538 uaudio_qdev->sid);
539 resp->xhci_mem_info.evt_ring.pa = xhci_pa;
540 resp->xhci_mem_info.evt_ring.size = PAGE_SIZE;
541 uaudio_qdev->er_phys_addr = xhci_pa;
542
543 /* dcba */
544 xhci_pa = usb_get_dcba_dma_addr(subs->dev);
545 if (!xhci_pa) {
546 pr_err("%s:failed to get dcba dma address\n", __func__);
547 goto unmap_er;
548 }
549
550 if (!uadev[card_num].dcba_iova) { /* mappped per usb device */
551 va = uaudio_iommu_map(MEM_DCBA, xhci_pa, PAGE_SIZE);
552 if (!va)
553 goto unmap_er;
554
555 uadev[card_num].dcba_iova = va;
556 uadev[card_num].dcba_size = PAGE_SIZE;
557 }
558
559 dcba_va = uadev[card_num].dcba_iova;
560 resp->xhci_mem_info.dcba.va = PREPEND_SID_TO_IOVA(dcba_va,
561 uaudio_qdev->sid);
562 resp->xhci_mem_info.dcba.pa = xhci_pa;
563 resp->xhci_mem_info.dcba.size = PAGE_SIZE;
564
565 /* data transfer ring */
566 xhci_pa = resp->xhci_mem_info.tr_data.pa;
567 va = uaudio_iommu_map(MEM_XFER_RING, xhci_pa, PAGE_SIZE);
568 if (!va)
569 goto unmap_dcba;
570
571 tr_data_va = va;
572 resp->xhci_mem_info.tr_data.va = PREPEND_SID_TO_IOVA(va,
573 uaudio_qdev->sid);
574 resp->xhci_mem_info.tr_data.size = PAGE_SIZE;
575
576 /* sync transfer ring */
577 if (!resp->xhci_mem_info.tr_sync.pa)
578 goto skip_sync;
579
580 xhci_pa = resp->xhci_mem_info.tr_sync.pa;
581 va = uaudio_iommu_map(MEM_XFER_RING, xhci_pa, PAGE_SIZE);
582 if (!va)
583 goto unmap_data;
584
585 tr_sync_va = va;
586 resp->xhci_mem_info.tr_sync.va = PREPEND_SID_TO_IOVA(va,
587 uaudio_qdev->sid);
588 resp->xhci_mem_info.tr_sync.size = PAGE_SIZE;
589
590skip_sync:
591 /* xfer buffer, multiple of 4K only */
592 if (!xfer_buf_len)
593 xfer_buf_len = PAGE_SIZE;
594
595 mult = xfer_buf_len / PAGE_SIZE;
596 remainder = xfer_buf_len % PAGE_SIZE;
597 len = mult * PAGE_SIZE;
598 len += remainder ? PAGE_SIZE : 0;
599
600 if (len > MAX_XFER_BUFF_LEN) {
601 pr_err("%s: req buf len %d > max buf len %lu, setting %lu\n",
602 __func__, len, MAX_XFER_BUFF_LEN, MAX_XFER_BUFF_LEN);
603 len = MAX_XFER_BUFF_LEN;
604 }
605
606 xfer_buf = usb_alloc_coherent(subs->dev, len, GFP_KERNEL, &xfer_buf_pa);
607 if (!xfer_buf)
608 goto unmap_sync;
609
610 resp->xhci_mem_info.xfer_buff.pa = xfer_buf_pa;
611 resp->xhci_mem_info.xfer_buff.size = len;
612
613 va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len);
614 if (!va)
615 goto unmap_sync;
616
617 xfer_buf_va = va;
618 resp->xhci_mem_info.xfer_buff.va = PREPEND_SID_TO_IOVA(va,
619 uaudio_qdev->sid);
620
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700621 resp->xhci_mem_info_valid = 1;
622
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800623 if (!atomic_read(&uadev[card_num].in_use)) {
624 kref_init(&uadev[card_num].kref);
625 init_waitqueue_head(&uadev[card_num].disconnect_wq);
Hemant Kumard2a54502016-03-22 16:35:16 -0700626 uadev[card_num].num_intf =
627 subs->dev->config->desc.bNumInterfaces;
628 uadev[card_num].info =
629 kzalloc(sizeof(struct intf_info) *
630 uadev[card_num].num_intf, GFP_KERNEL);
631 if (!uadev[card_num].info) {
632 ret = -ENOMEM;
633 goto unmap_xfer_buf;
634 }
635 uadev[card_num].udev = subs->dev;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800636 atomic_set(&uadev[card_num].in_use, 1);
637 } else {
638 kref_get(&uadev[card_num].kref);
639 }
640
Hemant Kumard2a54502016-03-22 16:35:16 -0700641 uadev[card_num].card_num = card_num;
642
643 /* cache intf specific info to use it for unmap and free xfer buf */
644 uadev[card_num].info[subs->interface].data_xfer_ring_va = tr_data_va;
645 uadev[card_num].info[subs->interface].data_xfer_ring_size = PAGE_SIZE;
646 uadev[card_num].info[subs->interface].sync_xfer_ring_va = tr_sync_va;
647 uadev[card_num].info[subs->interface].sync_xfer_ring_size = PAGE_SIZE;
648 uadev[card_num].info[subs->interface].xfer_buf_va = xfer_buf_va;
649 uadev[card_num].info[subs->interface].xfer_buf_pa = xfer_buf_pa;
650 uadev[card_num].info[subs->interface].xfer_buf_size = len;
651 uadev[card_num].info[subs->interface].xfer_buf = xfer_buf;
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700652 uadev[card_num].info[subs->interface].pcm_card_num = card_num;
653 uadev[card_num].info[subs->interface].pcm_dev_num = pcm_dev_num;
654 uadev[card_num].info[subs->interface].direction = subs->direction;
Hemant Kumard2a54502016-03-22 16:35:16 -0700655 uadev[card_num].info[subs->interface].in_use = true;
656
657 set_bit(card_num, &uaudio_qdev->card_slot);
658
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800659 return 0;
Hemant Kumard2a54502016-03-22 16:35:16 -0700660
661unmap_xfer_buf:
662 uaudio_iommu_unmap(MEM_XFER_BUF, xfer_buf_va, len);
663unmap_sync:
664 usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_pa);
665 uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE);
666unmap_data:
667 uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE);
668unmap_dcba:
669 uaudio_iommu_unmap(MEM_DCBA, dcba_va, PAGE_SIZE);
670unmap_er:
671 uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800672err:
Hemant Kumard2a54502016-03-22 16:35:16 -0700673 return ret;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800674}
675
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700676static void uaudio_dev_intf_cleanup(struct usb_device *udev,
677 struct intf_info *info)
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800678{
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700679 uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va,
680 info->data_xfer_ring_size);
681 info->data_xfer_ring_va = 0;
682 info->data_xfer_ring_size = 0;
683
684 uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va,
685 info->sync_xfer_ring_size);
686 info->sync_xfer_ring_va = 0;
687 info->sync_xfer_ring_size = 0;
688
689 uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va,
690 info->xfer_buf_size);
691 info->xfer_buf_va = 0;
692
693 usb_free_coherent(udev, info->xfer_buf_size,
694 info->xfer_buf, info->xfer_buf_pa);
695 info->xfer_buf_size = 0;
696 info->xfer_buf = NULL;
697 info->xfer_buf_pa = 0;
698
699 info->in_use = false;
700}
701
702static void uaudio_dev_cleanup(struct uaudio_dev *dev)
703{
704 int if_idx;
705
706 /* free xfer buffer and unmap xfer ring and buf per interface */
707 for (if_idx = 0; if_idx < dev->num_intf; if_idx++) {
708 if (!dev->info[if_idx].in_use)
709 continue;
710 uaudio_dev_intf_cleanup(dev->udev, &dev->info[if_idx]);
711 pr_debug("%s: release resources: intf# %d card# %d\n", __func__,
712 if_idx, dev->card_num);
713 }
714
715 /* iommu_unmap dcba iova for a usb device */
716 uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size);
717
718 dev->dcba_iova = 0;
719 dev->dcba_size = 0;
720 dev->num_intf = 0;
721
722 /* free interface info */
723 kfree(dev->info);
724 dev->info = NULL;
725
726 clear_bit(dev->card_num, &uaudio_qdev->card_slot);
727
728 /* all audio devices are disconnected */
729 if (!uaudio_qdev->card_slot) {
730 uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
731 usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
732 pr_debug("%s: all audio devices disconnected\n", __func__);
733 }
734
735 dev->udev = NULL;
736}
737
738static void uaudio_disconnect_cb(struct snd_usb_audio *chip)
739{
740 int ret;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800741 struct uaudio_dev *dev;
742 int card_num = chip->card_num;
Vamsi Krishna Samavedam1e634532016-09-13 14:09:37 -0700743 struct uaudio_qmi_svc *svc = uaudio_svc;
744 struct qmi_uaudio_stream_ind_msg_v01 disconnect_ind = {0};
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800745
Hemant Kumard2a54502016-03-22 16:35:16 -0700746 pr_debug("%s: for card# %d\n", __func__, card_num);
747
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800748 if (card_num >= SNDRV_CARDS) {
749 pr_err("%s: invalid card number\n", __func__);
Vamsi Krishna Samavedam1e634532016-09-13 14:09:37 -0700750 return;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800751 }
752
Vamsi Krishna Samavedam1e634532016-09-13 14:09:37 -0700753 mutex_lock(&chip->dev_lock);
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800754 dev = &uadev[card_num];
Hemant Kumard2a54502016-03-22 16:35:16 -0700755
756 /* clean up */
757 if (!dev->udev) {
758 pr_debug("%s: no clean up required\n", __func__);
759 goto done;
760 }
761
Vamsi Krishna Samavedam1e634532016-09-13 14:09:37 -0700762 if (atomic_read(&dev->in_use)) {
763 mutex_unlock(&chip->dev_lock);
764
765 pr_debug("%s: sending qmi indication disconnect\n", __func__);
766 disconnect_ind.dev_event = USB_AUDIO_DEV_DISCONNECT_V01;
767 disconnect_ind.slot_id = dev->udev->slot_id;
768 ret = qmi_send_ind(svc->uaudio_svc_hdl, svc->curr_conn,
769 &uaudio_stream_ind_desc, &disconnect_ind,
770 sizeof(disconnect_ind));
771 if (ret < 0) {
772 pr_err("%s: qmi send failed wiht err: %d\n",
773 __func__, ret);
774 return;
775 }
776
777 ret = wait_event_interruptible(dev->disconnect_wq,
778 !atomic_read(&dev->in_use));
779 if (ret < 0) {
780 pr_debug("%s: failed with ret %d\n", __func__, ret);
781 return;
782 }
783 mutex_lock(&chip->dev_lock);
784 }
785
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700786 uaudio_dev_cleanup(dev);
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800787done:
788 mutex_unlock(&chip->dev_lock);
789}
790
791static void uaudio_dev_release(struct kref *kref)
792{
793 struct uaudio_dev *dev = container_of(kref, struct uaudio_dev, kref);
794
Hemant Kumard2a54502016-03-22 16:35:16 -0700795 pr_debug("%s for dev %p\n", __func__, dev);
796
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800797 atomic_set(&dev->in_use, 0);
Hemant Kumard2a54502016-03-22 16:35:16 -0700798
799 clear_bit(dev->card_num, &uaudio_qdev->card_slot);
800
801 /* all audio devices are disconnected */
802 if (!uaudio_qdev->card_slot) {
803 usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
804 uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
805 pr_debug("%s: all audio devices disconnected\n", __func__);
806 }
807
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800808 wake_up(&dev->disconnect_wq);
809}
810
Hemant Kumara4f61012016-10-13 15:41:55 -0700811/* maps audio format received over QMI to asound.h based pcm format */
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700812static int map_pcm_format(unsigned int fmt_received)
Hemant Kumara4f61012016-10-13 15:41:55 -0700813{
814 switch (fmt_received) {
815 case USB_QMI_PCM_FORMAT_S8:
816 return SNDRV_PCM_FORMAT_S8;
817 case USB_QMI_PCM_FORMAT_U8:
818 return SNDRV_PCM_FORMAT_U8;
819 case USB_QMI_PCM_FORMAT_S16_LE:
820 return SNDRV_PCM_FORMAT_S16_LE;
821 case USB_QMI_PCM_FORMAT_S16_BE:
822 return SNDRV_PCM_FORMAT_S16_BE;
823 case USB_QMI_PCM_FORMAT_U16_LE:
824 return SNDRV_PCM_FORMAT_U16_LE;
825 case USB_QMI_PCM_FORMAT_U16_BE:
826 return SNDRV_PCM_FORMAT_U16_BE;
827 case USB_QMI_PCM_FORMAT_S24_LE:
828 return SNDRV_PCM_FORMAT_S24_LE;
829 case USB_QMI_PCM_FORMAT_S24_BE:
830 return SNDRV_PCM_FORMAT_S24_BE;
831 case USB_QMI_PCM_FORMAT_U24_LE:
832 return SNDRV_PCM_FORMAT_U24_LE;
833 case USB_QMI_PCM_FORMAT_U24_BE:
834 return SNDRV_PCM_FORMAT_U24_BE;
835 case USB_QMI_PCM_FORMAT_S24_3LE:
836 return SNDRV_PCM_FORMAT_S24_3LE;
837 case USB_QMI_PCM_FORMAT_S24_3BE:
838 return SNDRV_PCM_FORMAT_S24_3BE;
839 case USB_QMI_PCM_FORMAT_U24_3LE:
840 return SNDRV_PCM_FORMAT_U24_3LE;
841 case USB_QMI_PCM_FORMAT_U24_3BE:
842 return SNDRV_PCM_FORMAT_U24_3BE;
843 case USB_QMI_PCM_FORMAT_S32_LE:
844 return SNDRV_PCM_FORMAT_S32_LE;
845 case USB_QMI_PCM_FORMAT_S32_BE:
846 return SNDRV_PCM_FORMAT_S32_BE;
847 case USB_QMI_PCM_FORMAT_U32_LE:
848 return SNDRV_PCM_FORMAT_U32_LE;
849 case USB_QMI_PCM_FORMAT_U32_BE:
850 return SNDRV_PCM_FORMAT_U32_BE;
851 default:
852 return -EINVAL;
853 }
854}
855
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800856static int handle_uaudio_stream_req(void *req_h, void *req)
857{
858 struct qmi_uaudio_stream_req_msg_v01 *req_msg;
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700859 struct qmi_uaudio_stream_resp_msg_v01 resp = {{0}, 0};
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800860 struct snd_usb_substream *subs;
861 struct snd_usb_audio *chip = NULL;
862 struct uaudio_qmi_svc *svc = uaudio_svc;
Hemant Kumard2a54502016-03-22 16:35:16 -0700863 struct intf_info *info;
Hemant Kumara4f61012016-10-13 15:41:55 -0700864 int pcm_format;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800865 u8 pcm_card_num, pcm_dev_num, direction;
Hemant Kumard2a54502016-03-22 16:35:16 -0700866 int intf_num = -1, ret = 0;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800867
868 req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)req;
869
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700870 if (!req_msg->audio_format_valid || !req_msg->bit_rate_valid ||
871 !req_msg->number_of_ch_valid || !req_msg->xfer_buff_size_valid) {
872 pr_err("%s: invalid request msg\n", __func__);
873 ret = -EINVAL;
874 goto response;
875 }
876
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800877 direction = req_msg->usb_token & SND_PCM_STREAM_DIRECTION;
878 pcm_dev_num = (req_msg->usb_token & SND_PCM_DEV_NUM_MASK) >> 8;
879 pcm_card_num = (req_msg->usb_token & SND_PCM_CARD_NUM_MASK) >> 16;
880
881 pr_debug("%s:card#:%d dev#:%d dir:%d en:%d fmt:%d rate:%d #ch:%d\n",
882 __func__, pcm_card_num, pcm_dev_num, direction, req_msg->enable,
883 req_msg->audio_format, req_msg->bit_rate,
884 req_msg->number_of_ch);
885
886 if (pcm_card_num >= SNDRV_CARDS) {
887 pr_err("%s: invalid card # %u", __func__, pcm_card_num);
888 ret = -EINVAL;
889 goto response;
890 }
891
Hemant Kumara4f61012016-10-13 15:41:55 -0700892 pcm_format = map_pcm_format(req_msg->audio_format);
893 if (pcm_format == -EINVAL) {
894 pr_err("%s: unsupported pcm format received %d\n",
895 __func__, req_msg->audio_format);
896 ret = -EINVAL;
897 goto response;
898 }
899
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800900 subs = find_snd_usb_substream(pcm_card_num, pcm_dev_num, direction,
901 &chip, uaudio_disconnect_cb);
902 if (!subs || !chip || atomic_read(&chip->shutdown)) {
903 pr_err("%s: can't find substream for card# %u, dev# %u dir%u\n",
904 __func__, pcm_card_num, pcm_dev_num, direction);
905 ret = -ENODEV;
906 goto response;
907 }
908
909 mutex_lock(&chip->dev_lock);
Hemant Kumard2a54502016-03-22 16:35:16 -0700910 intf_num = subs->interface;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800911 if (atomic_read(&chip->shutdown) || !subs->stream || !subs->stream->pcm
912 || !subs->stream->chip) {
913 ret = -ENODEV;
914 mutex_unlock(&chip->dev_lock);
915 goto response;
916 }
917
Hemant Kumara4f61012016-10-13 15:41:55 -0700918 subs->pcm_format = pcm_format;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800919 subs->channels = req_msg->number_of_ch;
920 subs->cur_rate = req_msg->bit_rate;
921
922 ret = snd_usb_enable_audio_stream(subs, req_msg->enable);
923
924 if (!ret && req_msg->enable)
Hemant Kumard2a54502016-03-22 16:35:16 -0700925 ret = prepare_qmi_response(subs, &resp, req_msg->xfer_buff_size,
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700926 pcm_card_num, pcm_dev_num);
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800927
928 mutex_unlock(&chip->dev_lock);
929
930response:
931 if (!req_msg->enable && ret != -EINVAL) {
Hemant Kumard2a54502016-03-22 16:35:16 -0700932 if (intf_num >= 0) {
933 mutex_lock(&chip->dev_lock);
934 info = &uadev[pcm_card_num].info[intf_num];
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700935 uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, info);
Hemant Kumard2a54502016-03-22 16:35:16 -0700936 pr_debug("%s:release resources: intf# %d card# %d\n",
937 __func__, intf_num, pcm_card_num);
938 mutex_unlock(&chip->dev_lock);
939 }
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800940 if (atomic_read(&uadev[pcm_card_num].in_use))
941 kref_put(&uadev[pcm_card_num].kref,
942 uaudio_dev_release);
943 }
944
Hemant Kumaraa2fa3c2016-07-18 16:26:48 -0700945 resp.usb_token = req_msg->usb_token;
946 resp.usb_token_valid = 1;
947 resp.internal_status = ret;
948 resp.internal_status_valid = 1;
949 resp.status = ret ? USB_AUDIO_STREAM_REQ_FAILURE_V01 : ret;
950 resp.status_valid = 1;
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -0800951 ret = qmi_send_resp_from_cb(svc->uaudio_svc_hdl, svc->curr_conn, req_h,
952 &uaudio_stream_resp_desc, &resp, sizeof(resp));
953
954 svc->t_resp_sent = ktime_get();
955
956 pr_debug("%s: t_resp sent - t_req recvd (in ms) %lld\n", __func__,
957 ktime_to_ms(ktime_sub(svc->t_resp_sent, svc->t_request_recvd)));
958
959 return ret;
960}
961
962static int uaudio_qmi_svc_connect_cb(struct qmi_handle *handle,
963 void *conn_h)
964{
965 struct uaudio_qmi_svc *svc = uaudio_svc;
966
967 if (svc->uaudio_svc_hdl != handle || !conn_h) {
968 pr_err("%s: handle mismatch\n", __func__);
969 return -EINVAL;
970 }
971 if (svc->curr_conn) {
972 pr_err("%s: Service is busy\n", __func__);
973 return -ECONNREFUSED;
974 }
975 svc->curr_conn = conn_h;
976 return 0;
977}
978
Hemant Kumar89fa7b92016-10-27 19:56:31 -0700979static void uaudio_qmi_disconnect_work(struct work_struct *w)
980{
981 struct intf_info *info;
982 int idx, if_idx;
983 struct snd_usb_substream *subs;
984 struct snd_usb_audio *chip = NULL;
985
986 /* find all active intf for set alt 0 and cleanup usb audio dev */
987 for (idx = 0; idx < SNDRV_CARDS; idx++) {
988 if (!atomic_read(&uadev[idx].in_use))
989 continue;
990
991 for (if_idx = 0; if_idx < uadev[idx].num_intf; if_idx++) {
992 if (!uadev[idx].info || !uadev[idx].info[if_idx].in_use)
993 continue;
994 info = &uadev[idx].info[if_idx];
995 subs = find_snd_usb_substream(info->pcm_card_num,
996 info->pcm_dev_num,
997 info->direction,
998 &chip,
999 uaudio_disconnect_cb);
1000 if (!subs || !chip || atomic_read(&chip->shutdown)) {
1001 pr_debug("%s:no subs for c#%u, dev#%u dir%u\n",
1002 __func__, info->pcm_card_num,
1003 info->pcm_dev_num,
1004 info->direction);
1005 continue;
1006 }
1007 snd_usb_enable_audio_stream(subs, 0);
1008 }
1009 atomic_set(&uadev[idx].in_use, 0);
1010 mutex_lock(&chip->dev_lock);
1011 uaudio_dev_cleanup(&uadev[idx]);
1012 mutex_unlock(&chip->dev_lock);
1013 }
1014}
1015
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -08001016static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle,
1017 void *conn_h)
1018{
1019 struct uaudio_qmi_svc *svc = uaudio_svc;
1020
1021 if (svc->uaudio_svc_hdl != handle || svc->curr_conn != conn_h) {
1022 pr_err("%s: handle mismatch\n", __func__);
1023 return -EINVAL;
1024 }
1025
1026 svc->curr_conn = NULL;
Hemant Kumar89fa7b92016-10-27 19:56:31 -07001027 queue_work(svc->uaudio_wq, &svc->qmi_disconnect_work);
1028
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -08001029 return 0;
1030}
1031
1032static int uaudio_qmi_svc_req_cb(struct qmi_handle *handle, void *conn_h,
1033 void *req_h, unsigned int msg_id, void *req)
1034{
1035 int ret;
1036 struct uaudio_qmi_svc *svc = uaudio_svc;
1037
1038 if (svc->uaudio_svc_hdl != handle || svc->curr_conn != conn_h) {
1039 pr_err("%s: handle mismatch\n", __func__);
1040 return -EINVAL;
1041 }
1042
1043 switch (msg_id) {
1044 case QMI_UAUDIO_STREAM_REQ_V01:
1045 ret = handle_uaudio_stream_req(req_h, req);
1046 break;
1047
1048 default:
1049 ret = -ENOTSUPP;
1050 break;
1051 }
1052 return ret;
1053}
1054
1055static int uaudio_qmi_svc_req_desc_cb(unsigned int msg_id,
1056 struct msg_desc **req_desc)
1057{
1058 int ret;
1059
1060 pr_debug("%s: msg_id %d\n", __func__, msg_id);
1061
1062 switch (msg_id) {
1063 case QMI_UAUDIO_STREAM_REQ_V01:
1064 *req_desc = &uaudio_stream_req_desc;
1065 ret = sizeof(struct qmi_uaudio_stream_req_msg_v01);
1066 break;
1067
1068 default:
1069 ret = -ENOTSUPP;
1070 break;
1071 }
1072 return ret;
1073}
1074
1075static void uaudio_qmi_svc_recv_msg(struct work_struct *w)
1076{
1077 int ret;
1078 struct uaudio_qmi_svc *svc = container_of(w, struct uaudio_qmi_svc,
1079 recv_msg_work);
1080
1081 do {
1082 pr_debug("%s: Notified about a Receive Event", __func__);
1083 } while ((ret = qmi_recv_msg(svc->uaudio_svc_hdl)) == 0);
1084
1085 if (ret != -ENOMSG)
1086 pr_err("%s: Error receiving message\n", __func__);
1087}
1088
1089static void uaudio_qmi_svc_ntfy(struct qmi_handle *handle,
1090 enum qmi_event_type event, void *priv)
1091{
1092 struct uaudio_qmi_svc *svc = uaudio_svc;
1093
1094 pr_debug("%s: event %d", __func__, event);
1095
1096 svc->t_request_recvd = ktime_get();
1097
1098 switch (event) {
1099 case QMI_RECV_MSG:
1100 queue_work(svc->uaudio_wq, &svc->recv_msg_work);
1101 break;
1102 default:
1103 break;
1104 }
1105}
1106
1107static struct qmi_svc_ops_options uaudio_svc_ops_options = {
1108 .version = 1,
1109 .service_id = UAUDIO_STREAM_SERVICE_ID_V01,
1110 .service_vers = UAUDIO_STREAM_SERVICE_VERS_V01,
1111 .connect_cb = uaudio_qmi_svc_connect_cb,
1112 .disconnect_cb = uaudio_qmi_svc_disconnect_cb,
1113 .req_desc_cb = uaudio_qmi_svc_req_desc_cb,
1114 .req_cb = uaudio_qmi_svc_req_cb,
1115};
1116
Hemant Kumard2a54502016-03-22 16:35:16 -07001117static int uaudio_qmi_plat_probe(struct platform_device *pdev)
1118{
1119 int ret;
1120 struct device_node *node = pdev->dev.of_node;
1121
1122 uaudio_qdev = devm_kzalloc(&pdev->dev, sizeof(struct uaudio_qmi_dev),
1123 GFP_KERNEL);
1124 if (!uaudio_qdev)
1125 return -ENOMEM;
1126
1127 uaudio_qdev->dev = &pdev->dev;
1128
1129 ret = of_property_read_u32(node, "qcom,usb-audio-stream-id",
1130 &uaudio_qdev->sid);
1131 if (ret) {
1132 dev_err(&pdev->dev, "failed to read sid.\n");
1133 return -ENODEV;
1134 }
1135
1136 ret = of_property_read_u32(node, "qcom,usb-audio-intr-num",
1137 &uaudio_qdev->intr_num);
1138 if (ret) {
1139 dev_err(&pdev->dev, "failed to read intr num.\n");
1140 return -ENODEV;
1141 }
1142
1143 uaudio_qdev->domain = iommu_domain_alloc(pdev->dev.bus);
Hemant Kumara2a80912016-08-22 19:31:35 -07001144 if (!uaudio_qdev->domain) {
1145 dev_err(&pdev->dev, "failed to allocate iommu domain\n");
Hemant Kumard2a54502016-03-22 16:35:16 -07001146 return -ENODEV;
1147 }
1148
1149 /* attach to external processor iommu */
1150 ret = iommu_attach_device(uaudio_qdev->domain, &pdev->dev);
1151 if (ret) {
1152 dev_err(&pdev->dev, "failed to attach device ret = %d\n", ret);
1153 goto free_domain;
1154 }
1155
1156 /* initialize dcba, xfer ring and xfer buf iova list */
1157 INIT_LIST_HEAD(&uaudio_qdev->dcba_list);
1158 uaudio_qdev->curr_dcba_iova = IOVA_DCBA_BASE;
1159 uaudio_qdev->dcba_iova_size = SNDRV_CARDS * PAGE_SIZE;
1160
1161 INIT_LIST_HEAD(&uaudio_qdev->xfer_ring_list);
1162 uaudio_qdev->curr_xfer_ring_iova = IOVA_XFER_RING_BASE;
1163 uaudio_qdev->xfer_ring_iova_size =
1164 IOVA_XFER_RING_MAX - IOVA_XFER_RING_BASE;
1165
1166 INIT_LIST_HEAD(&uaudio_qdev->xfer_buf_list);
1167 uaudio_qdev->curr_xfer_buf_iova = IOVA_XFER_BUF_BASE;
1168 uaudio_qdev->xfer_buf_iova_size =
1169 IOVA_XFER_BUF_MAX - IOVA_XFER_BUF_BASE;
1170
1171 return 0;
1172
1173free_domain:
1174 iommu_domain_free(uaudio_qdev->domain);
1175 return ret;
1176}
1177
1178static int uaudio_qmi_plat_remove(struct platform_device *pdev)
1179{
1180 iommu_detach_device(uaudio_qdev->domain, &pdev->dev);
1181 iommu_domain_free(uaudio_qdev->domain);
1182 uaudio_qdev->domain = NULL;
1183
1184 return 0;
1185}
1186
1187static const struct of_device_id of_uaudio_matach[] = {
1188 {
1189 .compatible = "qcom,usb-audio-qmi-dev",
1190 },
1191 { },
1192};
1193MODULE_DEVICE_TABLE(of, of_uaudio_matach);
1194
1195static struct platform_driver uaudio_qmi_driver = {
1196 .probe = uaudio_qmi_plat_probe,
1197 .remove = uaudio_qmi_plat_remove,
1198 .driver = {
1199 .name = "uaudio-qmi",
1200 .of_match_table = of_uaudio_matach,
1201 },
1202};
1203
1204static int uaudio_qmi_svc_init(void)
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -08001205{
1206 int ret;
1207 struct uaudio_qmi_svc *svc;
1208
1209 svc = kzalloc(sizeof(struct uaudio_qmi_svc), GFP_KERNEL);
1210 if (!svc)
1211 return -ENOMEM;
1212
1213 svc->uaudio_wq = create_singlethread_workqueue("uaudio_svc");
1214 if (!svc->uaudio_wq) {
1215 ret = -ENOMEM;
1216 goto free_svc;
1217 }
1218
1219 svc->uaudio_svc_hdl = qmi_handle_create(uaudio_qmi_svc_ntfy, NULL);
1220 if (!svc->uaudio_svc_hdl) {
1221 pr_err("%s: Error creating svc_hdl\n", __func__);
1222 ret = -EFAULT;
1223 goto destroy_uaudio_wq;
1224 }
1225
1226 ret = qmi_svc_register(svc->uaudio_svc_hdl, &uaudio_svc_ops_options);
1227 if (ret < 0) {
1228 pr_err("%s:Error registering uaudio svc %d\n", __func__, ret);
1229 goto destroy_svc_handle;
1230 }
1231
1232 INIT_WORK(&svc->recv_msg_work, uaudio_qmi_svc_recv_msg);
Hemant Kumar89fa7b92016-10-27 19:56:31 -07001233 INIT_WORK(&svc->qmi_disconnect_work, uaudio_qmi_disconnect_work);
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -08001234
1235 uaudio_svc = svc;
1236
1237 return 0;
1238
1239destroy_svc_handle:
1240 qmi_handle_destroy(svc->uaudio_svc_hdl);
1241destroy_uaudio_wq:
1242 destroy_workqueue(svc->uaudio_wq);
1243free_svc:
1244 kfree(svc);
1245 return ret;
1246}
1247
Hemant Kumard2a54502016-03-22 16:35:16 -07001248static void uaudio_qmi_svc_exit(void)
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -08001249{
1250 struct uaudio_qmi_svc *svc = uaudio_svc;
1251
1252 qmi_svc_unregister(svc->uaudio_svc_hdl);
1253 flush_workqueue(svc->uaudio_wq);
1254 qmi_handle_destroy(svc->uaudio_svc_hdl);
1255 destroy_workqueue(svc->uaudio_wq);
1256 kfree(svc);
1257 uaudio_svc = NULL;
1258}
1259
Hemant Kumard2a54502016-03-22 16:35:16 -07001260static int __init uaudio_qmi_plat_init(void)
1261{
1262 int ret;
1263
1264 ret = platform_driver_register(&uaudio_qmi_driver);
1265 if (ret)
1266 return ret;
1267
1268 return uaudio_qmi_svc_init();
1269}
1270
1271static void __exit uaudio_qmi_plat_exit(void)
1272{
1273 uaudio_qmi_svc_exit();
1274 platform_driver_unregister(&uaudio_qmi_driver);
1275}
1276
1277module_init(uaudio_qmi_plat_init);
1278module_exit(uaudio_qmi_plat_exit);
Hemant Kumar0ef9fbb2016-01-28 11:41:42 -08001279
1280MODULE_DESCRIPTION("USB AUDIO QMI Service Driver");
1281MODULE_LICENSE("GPL v2");