blob: d37a3255c55e7cd74015b8cbfb8a73357361be27 [file] [log] [blame]
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +03001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02002 *
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/fs.h>
15#include <linux/module.h>
16#include <linux/miscdevice.h>
17#include <linux/sched.h>
18#include <linux/slab.h>
19#include <linux/wait.h>
20#include <linux/input.h>
21#include <linux/uaccess.h>
22#include <linux/time.h>
23#include <asm/mach-types.h>
24#include <sound/apr_audio.h>
25#include <mach/qdsp6v2/usf.h>
26#include "q6usm.h"
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +030027#include "usfcdev.h"
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020028
29/* The driver version*/
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +030030#define DRV_VERSION "1.4.2"
31#define USF_VERSION_ID 0x0142
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020032
33/* Standard timeout in the asynchronous ops */
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +030034#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020035
36/* Undefined USF device */
37#define USF_UNDEF_DEV_ID 0xffff
38
39/* RX memory mapping flag */
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +020040#define USF_VM_WRITE 2
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020041
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +020042/* Number of events, copied from the user space to kernel one */
43#define USF_EVENTS_PORTION_SIZE 20
44
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +020045/* Indexes in range definitions */
46#define MIN_IND 0
47#define MAX_IND 1
48
49/* The coordinates indexes */
50#define X_IND 0
51#define Y_IND 1
52#define Z_IND 2
53
54/* Place for opreation result, received from QDSP6 */
55#define APR_RESULT_IND 1
56
57/* Place for US detection result, received from QDSP6 */
58#define APR_US_DETECT_RESULT_IND 0
59
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020060/* The driver states */
61enum usf_state_type {
62 USF_IDLE_STATE,
63 USF_OPENED_STATE,
64 USF_CONFIGURED_STATE,
65 USF_WORK_STATE,
66 USF_ERROR_STATE
67};
68
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +020069/* The US detection status upon FW/HW based US detection results */
70enum usf_us_detect_type {
71 USF_US_DETECT_UNDEF,
72 USF_US_DETECT_YES,
73 USF_US_DETECT_NO
74};
75
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020076struct usf_xx_type {
77 /* Name of the client - event calculator */
78 char client_name[USF_MAX_CLIENT_NAME_SIZE];
79 /* The driver state in TX or RX direction */
80 enum usf_state_type usf_state;
81 /* wait for q6 events mechanism */
82 wait_queue_head_t wait;
83 /* IF with q6usm info */
84 struct us_client *usc;
85 /* Q6:USM' Encoder/decoder configuration */
86 struct us_encdec_cfg encdec_cfg;
87 /* Shared buffer (with Q6:USM) size */
88 uint32_t buffer_size;
89 /* Number of the shared buffers (with Q6:USM) */
90 uint32_t buffer_count;
91 /* Shared memory (Cyclic buffer with 1 gap) control */
92 uint32_t new_region;
93 uint32_t prev_region;
94 /* Q6:USM's events handler */
95 void (*cb)(uint32_t, uint32_t, uint32_t *, void *);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +020096 /* US detection result */
97 enum usf_us_detect_type us_detect_type;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020098 /* User's update info isn't acceptable */
99 u8 user_upd_info_na;
100};
101
102struct usf_type {
103 /* TX device component configuration & control */
104 struct usf_xx_type usf_tx;
105 /* RX device component configuration & control */
106 struct usf_xx_type usf_rx;
107 /* Index into the opened device container */
108 /* To prevent mutual usage of the same device */
109 uint16_t dev_ind;
110 /* Event types, supported by device */
111 uint16_t event_types;
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300112 /* The input devices are "input" module registered clients */
113 struct input_dev *input_ifs[USF_MAX_EVENT_IND];
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200114 /* The event source */
115 int event_src;
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300116 /* Bitmap of types of events, conflicting to USF's ones */
117 uint16_t conflicting_event_types;
118 /* Bitmap of types of events from devs, conflicting with USF */
119 uint16_t conflicting_event_filters;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200120};
121
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300122struct usf_input_dev_type {
123 /* Input event type, supported by the input device */
124 uint16_t event_type;
125 /* Input device name */
126 const char *input_dev_name;
127 /* Input device registration function */
128 int (*prepare_dev)(uint16_t, struct usf_type *,
129 struct us_input_info_type *,
130 const char *);
131 /* Input event notification function */
132 void (*notify_event)(struct usf_type *,
133 uint16_t,
134 struct usf_event_type *
135 );
136};
137
138
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200139/* The MAX number of the supported devices */
140#define MAX_DEVS_NUMBER 1
141
142/* The opened devices container */
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200143static const int s_event_src_map[] = {
144 BTN_TOOL_PEN, /* US_INPUT_SRC_PEN*/
145 0, /* US_INPUT_SRC_FINGER */
146 0, /* US_INPUT_SRC_UNDEF */
147};
148
149/* The opened devices container */
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200150static int s_opened_devs[MAX_DEVS_NUMBER];
151
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300152#define USF_NAME_PREFIX "usf_"
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300153#define USF_NAME_PREFIX_SIZE 4
154
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300155
156static struct input_dev *allocate_dev(uint16_t ind, const char *name)
157{
158 struct input_dev *in_dev = input_allocate_device();
159
160 if (in_dev == NULL) {
161 pr_err("%s: input_allocate_device() failed\n", __func__);
162 } else {
163 /* Common part configuration */
164 in_dev->name = name;
165 in_dev->phys = NULL;
166 in_dev->id.bustype = BUS_HOST;
167 in_dev->id.vendor = 0x0001;
168 in_dev->id.product = 0x0001;
169 in_dev->id.version = USF_VERSION_ID;
170 }
171 return in_dev;
172}
173
174static int prepare_tsc_input_device(uint16_t ind,
175 struct usf_type *usf_info,
176 struct us_input_info_type *input_info,
177 const char *name)
178{
179 struct input_dev *in_dev = allocate_dev(ind, name);
180
181 if (in_dev == NULL)
182 return -ENOMEM;
183
184 usf_info->input_ifs[ind] = in_dev;
185 in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
186 in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
187 input_set_abs_params(in_dev, ABS_X,
188 input_info->tsc_x_dim[MIN_IND],
189 input_info->tsc_x_dim[MAX_IND],
190 0, 0);
191 input_set_abs_params(in_dev, ABS_Y,
192 input_info->tsc_y_dim[MIN_IND],
193 input_info->tsc_y_dim[MAX_IND],
194 0, 0);
195 input_set_abs_params(in_dev, ABS_DISTANCE,
196 input_info->tsc_z_dim[MIN_IND],
197 input_info->tsc_z_dim[MAX_IND],
198 0, 0);
199
200 input_set_abs_params(in_dev, ABS_PRESSURE,
201 input_info->tsc_pressure[MIN_IND],
202 input_info->tsc_pressure[MAX_IND],
203 0, 0);
204
205 input_set_abs_params(in_dev, ABS_TILT_X,
206 input_info->tsc_x_tilt[MIN_IND],
207 input_info->tsc_x_tilt[MAX_IND],
208 0, 0);
209 input_set_abs_params(in_dev, ABS_TILT_Y,
210 input_info->tsc_y_tilt[MIN_IND],
211 input_info->tsc_y_tilt[MAX_IND],
212 0, 0);
213
214 return 0;
215}
216
217static int prepare_mouse_input_device(uint16_t ind, struct usf_type *usf_info,
218 struct us_input_info_type *input_info,
219 const char *name)
220{
221 struct input_dev *in_dev = allocate_dev(ind, name);
222
223 if (in_dev == NULL)
224 return -ENOMEM;
225
226 usf_info->input_ifs[ind] = in_dev;
227 in_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
228
229 in_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
230 BIT_MASK(BTN_RIGHT) |
231 BIT_MASK(BTN_MIDDLE);
232 in_dev->relbit[0] = BIT_MASK(REL_X) |
233 BIT_MASK(REL_Y) |
234 BIT_MASK(REL_Z);
235
236 return 0;
237}
238
239static int prepare_keyboard_input_device(
240 uint16_t ind,
241 struct usf_type *usf_info,
242 struct us_input_info_type *input_info,
243 const char *name)
244{
245 struct input_dev *in_dev = allocate_dev(ind, name);
246
247 if (in_dev == NULL)
248 return -ENOMEM;
249
250 usf_info->input_ifs[ind] = in_dev;
251 in_dev->evbit[0] |= BIT_MASK(EV_KEY);
252 /* All keys are permitted */
253 memset(in_dev->keybit, 0xff, sizeof(in_dev->keybit));
254
255 return 0;
256}
257
258static void notify_tsc_event(struct usf_type *usf_info,
259 uint16_t if_ind,
260 struct usf_event_type *event)
261
262{
263 struct input_dev *input_if = usf_info->input_ifs[if_ind];
264 struct point_event_type *pe = &(event->event_data.point_event);
265
266 input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
267 input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
268 input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
269
270 input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
271 input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
272
273 input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
274 input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
275
276 if (usf_info->event_src)
277 input_report_key(input_if, usf_info->event_src, 1);
278
279 input_sync(input_if);
280
281 pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
282 __func__,
283 pe->coordinates[X_IND],
284 pe->coordinates[Y_IND],
285 pe->coordinates[Z_IND],
286 pe->inclinations[X_IND],
287 pe->inclinations[Y_IND],
288 pe->pressure);
289}
290
291static void notify_mouse_event(struct usf_type *usf_info,
292 uint16_t if_ind,
293 struct usf_event_type *event)
294{
295 struct input_dev *input_if = usf_info->input_ifs[if_ind];
296 struct mouse_event_type *me = &(event->event_data.mouse_event);
297
298 input_report_rel(input_if, REL_X, me->rels[X_IND]);
299 input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
300 input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
301
302 input_report_key(input_if, BTN_LEFT,
303 me->buttons_states & USF_BUTTON_LEFT_MASK);
304 input_report_key(input_if, BTN_MIDDLE,
305 me->buttons_states & USF_BUTTON_MIDDLE_MASK);
306 input_report_key(input_if, BTN_RIGHT,
307 me->buttons_states & USF_BUTTON_RIGHT_MASK);
308
309 input_sync(input_if);
310
311 pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
312 __func__, me->rels[X_IND],
313 me->rels[Y_IND], me->buttons_states);
314}
315
316static void notify_key_event(struct usf_type *usf_info,
317 uint16_t if_ind,
318 struct usf_event_type *event)
319{
320 struct input_dev *input_if = usf_info->input_ifs[if_ind];
321 struct key_event_type *ke = &(event->event_data.key_event);
322
323 input_report_key(input_if, ke->key, ke->key_state);
324 input_sync(input_if);
325 pr_debug("%s: key event: key[%d], state[%d]\n",
326 __func__,
327 ke->key,
328 ke->key_state);
329
330}
331
332static struct usf_input_dev_type s_usf_input_devs[] = {
333 {USF_TSC_EVENT, "usf_tsc",
334 prepare_tsc_input_device, notify_tsc_event},
335 {USF_TSC_PTR_EVENT, "usf_tsc_ptr",
336 prepare_tsc_input_device, notify_tsc_event},
337 {USF_MOUSE_EVENT, "usf_mouse",
338 prepare_mouse_input_device, notify_mouse_event},
339 {USF_KEYBOARD_EVENT, "usf_kb",
340 prepare_keyboard_input_device, notify_key_event},
341};
342
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200343static void usf_rx_cb(uint32_t opcode, uint32_t token,
344 uint32_t *payload, void *priv)
345{
346 struct usf_xx_type *usf_xx = (struct usf_xx_type *) priv;
347
348 if (usf_xx == NULL) {
349 pr_err("%s: the private data is NULL\n", __func__);
350 return;
351 }
352
353 switch (opcode) {
Baruch Eruchimovitch258b3472012-10-14 21:46:35 +0200354 case Q6USM_EVENT_WRITE_DONE:
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200355 wake_up(&usf_xx->wait);
356 break;
357 default:
358 break;
359 }
360}
361
362static void usf_tx_cb(uint32_t opcode, uint32_t token,
363 uint32_t *payload, void *priv)
364{
365 struct usf_xx_type *usf_xx = (struct usf_xx_type *) priv;
366
367 if (usf_xx == NULL) {
368 pr_err("%s: the private data is NULL\n", __func__);
369 return;
370 }
371
372 switch (opcode) {
Baruch Eruchimovitch258b3472012-10-14 21:46:35 +0200373 case Q6USM_EVENT_READ_DONE:
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200374 if (token == USM_WRONG_TOKEN)
375 usf_xx->usf_state = USF_ERROR_STATE;
376 usf_xx->new_region = token;
377 wake_up(&usf_xx->wait);
378 break;
379
Baruch Eruchimovitch258b3472012-10-14 21:46:35 +0200380 case Q6USM_EVENT_SIGNAL_DETECT_RESULT:
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200381 usf_xx->us_detect_type = (payload[APR_US_DETECT_RESULT_IND]) ?
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200382 USF_US_DETECT_YES :
383 USF_US_DETECT_NO;
384
385 wake_up(&usf_xx->wait);
386 break;
387
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200388 case APR_BASIC_RSP_RESULT:
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200389 if (payload[APR_RESULT_IND]) {
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200390 usf_xx->usf_state = USF_ERROR_STATE;
391 usf_xx->new_region = USM_WRONG_TOKEN;
392 wake_up(&usf_xx->wait);
393 }
394 break;
395
396 default:
397 break;
398 }
399}
400
401static void release_xx(struct usf_xx_type *usf_xx)
402{
403 if (usf_xx != NULL) {
404 if (usf_xx->usc) {
405 q6usm_us_client_free(usf_xx->usc);
406 usf_xx->usc = NULL;
407 }
408
409 if (usf_xx->encdec_cfg.params != NULL) {
410 kfree(usf_xx->encdec_cfg.params);
411 usf_xx->encdec_cfg.params = NULL;
412 }
413 }
414}
415
416static void usf_disable(struct usf_xx_type *usf_xx)
417{
418 if (usf_xx != NULL) {
419 if ((usf_xx->usf_state != USF_IDLE_STATE) &&
420 (usf_xx->usf_state != USF_OPENED_STATE)) {
421 (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
422 usf_xx->usf_state = USF_OPENED_STATE;
423 wake_up(&usf_xx->wait);
424 }
425 release_xx(usf_xx);
426 }
427}
428
429static int config_xx(struct usf_xx_type *usf_xx, struct us_xx_info_type *config)
430{
431 int rc = 0;
432 uint16_t data_map_size = 0;
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300433 uint16_t min_map_size = 0;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200434
435 if ((usf_xx == NULL) ||
436 (config == NULL))
437 return -EINVAL;
438
439 data_map_size = sizeof(usf_xx->encdec_cfg.cfg_common.data_map);
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300440 min_map_size = min(data_map_size, config->port_cnt);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200441
442 if (config->client_name != NULL) {
443 if (strncpy_from_user(usf_xx->client_name,
444 config->client_name,
445 sizeof(usf_xx->client_name) - 1) < 0) {
446 pr_err("%s: get client name failed\n", __func__);
447 return -EINVAL;
448 }
449 }
450
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200451 pr_debug("%s: name=%s; buf_size:%d; dev_id:0x%x; sample_rate:%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200452 __func__, usf_xx->client_name, config->buf_size,
453 config->dev_id, config->sample_rate);
454
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200455 pr_debug("%s: buf_num:%d; format:%d; port_cnt:%d; data_size=%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200456 __func__, config->buf_num, config->stream_format,
457 config->port_cnt, config->params_data_size);
458
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300459 pr_debug("%s: id[0]=%d, id[1]=%d, id[2]=%d, id[3]=%d, id[4]=%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200460 __func__,
461 config->port_id[0],
462 config->port_id[1],
463 config->port_id[2],
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300464 config->port_id[3],
465 config->port_id[4]);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200466
467 /* q6usm allocation & configuration */
468 usf_xx->buffer_size = config->buf_size;
469 usf_xx->buffer_count = config->buf_num;
470 usf_xx->encdec_cfg.cfg_common.bits_per_sample =
471 config->bits_per_sample;
472 usf_xx->encdec_cfg.cfg_common.sample_rate = config->sample_rate;
473 /* AFE port e.g. AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX */
474 usf_xx->encdec_cfg.cfg_common.dev_id = config->dev_id;
475
476 usf_xx->encdec_cfg.cfg_common.ch_cfg = config->port_cnt;
477 memcpy((void *)&usf_xx->encdec_cfg.cfg_common.data_map,
478 (void *)config->port_id,
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300479 min_map_size);
480
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200481 if (rc) {
482 pr_err("%s: ports offsets copy failure\n", __func__);
483 return -EINVAL;
484 }
485
486 usf_xx->encdec_cfg.format_id = config->stream_format;
487 usf_xx->encdec_cfg.params_size = config->params_data_size;
488 usf_xx->user_upd_info_na = 1; /* it's used in US_GET_TX_UPDATE */
489
490 if (config->params_data_size > 0) { /* transparent data copy */
491 usf_xx->encdec_cfg.params = kzalloc(config->params_data_size,
492 GFP_KERNEL);
493 if (usf_xx->encdec_cfg.params == NULL) {
494 pr_err("%s: params memory alloc[%d] failure\n",
495 __func__,
496 config->params_data_size);
497 return -ENOMEM;
498 }
499 rc = copy_from_user(usf_xx->encdec_cfg.params,
500 config->params_data,
501 config->params_data_size);
502 if (rc) {
503 pr_err("%s: transparent data copy failure\n",
504 __func__);
505 kfree(usf_xx->encdec_cfg.params);
506 usf_xx->encdec_cfg.params = NULL;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200507 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200508 }
509 pr_debug("%s: params_size[%d]; params[%d,%d,%d,%d, %d]\n",
510 __func__,
511 config->params_data_size,
512 usf_xx->encdec_cfg.params[0],
513 usf_xx->encdec_cfg.params[1],
514 usf_xx->encdec_cfg.params[2],
515 usf_xx->encdec_cfg.params[3],
516 usf_xx->encdec_cfg.params[4]
517 );
518 }
519
520 usf_xx->usc = q6usm_us_client_alloc(usf_xx->cb, (void *)usf_xx);
521 if (!usf_xx->usc) {
522 pr_err("%s: Could not allocate q6usm client\n", __func__);
523 rc = -EFAULT;
524 }
525
526 return rc;
527}
528
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300529static bool usf_match(uint16_t event_type_ind, struct input_dev *dev)
530{
531 bool rc = false;
532
533 rc = (event_type_ind < MAX_EVENT_TYPE_NUM) &&
534 ((dev->name == NULL) ||
535 strncmp(dev->name, USF_NAME_PREFIX, USF_NAME_PREFIX_SIZE));
536 pr_debug("%s: name=[%s]; rc=%d\n",
537 __func__, dev->name, rc);
538
539 return rc;
540}
541
542static bool usf_register_conflicting_events(uint16_t event_types)
543{
544 bool rc = true;
545 uint16_t ind = 0;
546 uint16_t mask = 1;
547
548 for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
549 if (event_types & mask) {
550 rc = usfcdev_register(ind, usf_match);
551 if (!rc)
552 break;
553 }
554 mask = mask << 1;
555 }
556
557 return rc;
558}
559
560static void usf_unregister_conflicting_events(uint16_t event_types)
561{
562 uint16_t ind = 0;
563 uint16_t mask = 1;
564
565 for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
566 if (event_types & mask)
567 usfcdev_unregister(ind);
568 mask = mask << 1;
569 }
570}
571
572static void usf_set_event_filters(struct usf_type *usf, uint16_t event_filters)
573{
574 uint16_t ind = 0;
575 uint16_t mask = 1;
576
577 if (usf->conflicting_event_filters != event_filters) {
578 for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
579 if (usf->conflicting_event_types & mask)
580 usfcdev_set_filter(ind, event_filters&mask);
581 mask = mask << 1;
582 }
583 usf->conflicting_event_filters = event_filters;
584 }
585}
586
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200587static int register_input_device(struct usf_type *usf_info,
588 struct us_input_info_type *input_info)
589{
590 int rc = 0;
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300591 bool ret = true;
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300592 uint16_t ind = 0;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200593
594 if ((usf_info == NULL) ||
595 (input_info == NULL) ||
596 !(input_info->event_types & USF_ALL_EVENTS)) {
597 pr_err("%s: wrong input parameter(s)\n", __func__);
598 return -EINVAL;
599 }
600
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200601 if (input_info->event_src < ARRAY_SIZE(s_event_src_map))
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300602 usf_info->event_src =
603 s_event_src_map[input_info->event_src];
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200604 else
605 usf_info->event_src = 0;
606
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300607 for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
608 if (usf_info->input_ifs[ind] != NULL) {
609 pr_err("%s: input_if[%d] is already allocated\n",
610 __func__, ind);
611 return -EFAULT;
612 }
613 if ((input_info->event_types &
614 s_usf_input_devs[ind].event_type) &&
615 s_usf_input_devs[ind].prepare_dev) {
616 rc = (*s_usf_input_devs[ind].prepare_dev)(
617 ind,
618 usf_info,
619 input_info,
620 s_usf_input_devs[ind].input_dev_name);
621 if (rc)
622 return rc;
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200623
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200624
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300625 if (usf_info->event_src)
626 input_set_capability(usf_info->input_ifs[ind],
627 EV_KEY,
628 usf_info->event_src);
629
630 rc = input_register_device(usf_info->input_ifs[ind]);
631 if (rc) {
632 pr_err("%s: input_reg_dev() failed; rc=%d\n",
633 __func__, rc);
634 input_free_device(usf_info->input_ifs[ind]);
635 usf_info->input_ifs[ind] = NULL;
636 } else {
637 usf_info->event_types |=
638 s_usf_input_devs[ind].event_type;
639 pr_debug("%s: input device[%s] was registered\n",
640 __func__,
641 s_usf_input_devs[ind].input_dev_name);
642 }
643 } /* supported event */
644 } /* event types loop */
645
646 ret = usf_register_conflicting_events(
647 input_info->conflicting_event_types);
648 if (ret)
649 usf_info->conflicting_event_types =
650 input_info->conflicting_event_types;
651
652 return 0;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200653}
654
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200655
656static void handle_input_event(struct usf_type *usf_info,
657 uint16_t event_counter,
658 struct usf_event_type *event)
659{
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200660 uint16_t ind = 0;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200661 uint16_t events_num = 0;
662 struct usf_event_type usf_events[USF_EVENTS_PORTION_SIZE];
663 int rc = 0;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200664
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300665 if ((usf_info == NULL) ||
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200666 (event == NULL) || (!event_counter)) {
667 return;
668 }
669
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200670 while (event_counter > 0) {
671 if (event_counter > USF_EVENTS_PORTION_SIZE) {
672 events_num = USF_EVENTS_PORTION_SIZE;
673 event_counter -= USF_EVENTS_PORTION_SIZE;
674 } else {
675 events_num = event_counter;
676 event_counter = 0;
677 }
678 rc = copy_from_user(usf_events,
679 event,
680 events_num * sizeof(struct usf_event_type));
681 if (rc) {
682 pr_err("%s: copy upd_rx_info from user; rc=%d\n",
683 __func__, rc);
684 return;
685 }
686 for (ind = 0; ind < events_num; ++ind) {
687 struct usf_event_type *p_event = &usf_events[ind];
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +0300688 uint16_t if_ind = p_event->event_type_ind;
689
690 if ((if_ind >= USF_MAX_EVENT_IND) ||
691 (usf_info->input_ifs[if_ind] == NULL))
692 continue; /* event isn't supported */
693
694 if (s_usf_input_devs[if_ind].notify_event)
695 (*s_usf_input_devs[if_ind].notify_event)(
696 usf_info,
697 if_ind,
698 p_event);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200699 } /* loop in the portion */
700 } /* all events loop */
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200701}
702
703static int usf_start_tx(struct usf_xx_type *usf_xx)
704{
705 int rc = q6usm_run(usf_xx->usc, 0, 0, 0);
706
707 pr_debug("%s: tx: q6usm_run; rc=%d\n", __func__, rc);
708 if (!rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200709 if (usf_xx->buffer_count >= USM_MIN_BUF_CNT) {
710 /* supply all buffers */
711 rc = q6usm_read(usf_xx->usc,
712 usf_xx->buffer_count);
713 pr_debug("%s: q6usm_read[%d]\n",
714 __func__, rc);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200715
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200716 if (rc)
717 pr_err("%s: buf read failed",
718 __func__);
719 else
720 usf_xx->usf_state =
721 USF_WORK_STATE;
722 } else
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200723 usf_xx->usf_state =
724 USF_WORK_STATE;
725 }
726
727 return rc;
728} /* usf_start_tx */
729
730static int usf_start_rx(struct usf_xx_type *usf_xx)
731{
732 int rc = q6usm_run(usf_xx->usc, 0, 0, 0);
733
734 pr_debug("%s: rx: q6usm_run; rc=%d\n",
735 __func__, rc);
736 if (!rc)
737 usf_xx->usf_state = USF_WORK_STATE;
738
739 return rc;
740} /* usf_start_rx */
741
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200742static int usf_set_us_detection(struct usf_type *usf, unsigned long arg)
743{
744 uint32_t timeout = 0;
745 struct us_detect_info_type detect_info;
746 struct usm_session_cmd_detect_info usm_detect_info;
747 struct usm_session_cmd_detect_info *p_usm_detect_info =
748 &usm_detect_info;
749 uint32_t detect_info_size = sizeof(struct usm_session_cmd_detect_info);
750 struct usf_xx_type *usf_xx = &usf->usf_tx;
751 int rc = copy_from_user(&detect_info,
752 (void *) arg,
753 sizeof(detect_info));
754
755 if (rc) {
756 pr_err("%s: copy detect_info from user; rc=%d\n",
757 __func__, rc);
758 return -EFAULT;
759 }
760
761 if (detect_info.us_detector != US_DETECT_FW) {
762 pr_err("%s: unsupported detector: %d\n",
763 __func__, detect_info.us_detector);
764 return -EINVAL;
765 }
766
767 if ((detect_info.params_data_size != 0) &&
768 (detect_info.params_data != NULL)) {
769 uint8_t *p_data = NULL;
770
771 detect_info_size += detect_info.params_data_size;
772 p_usm_detect_info = kzalloc(detect_info_size, GFP_KERNEL);
773 if (p_usm_detect_info == NULL) {
774 pr_err("%s: detect_info[%d] allocation failed\n",
775 __func__, detect_info_size);
776 return -ENOMEM;
777 }
778 p_data = (uint8_t *)p_usm_detect_info +
779 sizeof(struct usm_session_cmd_detect_info);
780
781 rc = copy_from_user(p_data,
782 (void *)detect_info.params_data,
783 detect_info.params_data_size);
784 if (rc) {
785 pr_err("%s: copy params from user; rc=%d\n",
786 __func__, rc);
787 kfree(p_usm_detect_info);
788 return -EFAULT;
789 }
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200790 p_usm_detect_info->algorithm_cfg_size =
791 detect_info.params_data_size;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200792 } else
793 usm_detect_info.algorithm_cfg_size = 0;
794
795 p_usm_detect_info->detect_mode = detect_info.us_detect_mode;
796 p_usm_detect_info->skip_interval = detect_info.skip_time;
797
798 usf_xx->us_detect_type = USF_US_DETECT_UNDEF;
799
800 rc = q6usm_set_us_detection(usf_xx->usc,
801 p_usm_detect_info,
802 detect_info_size);
803 if (rc || (detect_info.detect_timeout == USF_NO_WAIT_TIMEOUT)) {
804 if (detect_info_size >
805 sizeof(struct usm_session_cmd_detect_info))
806 kfree(p_usm_detect_info);
807 return rc;
808 }
809
810 /* Get US detection result */
811 if (detect_info.detect_timeout == USF_INFINITIVE_TIMEOUT) {
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300812 rc = wait_event_interruptible(usf_xx->wait,
813 (usf_xx->us_detect_type !=
814 USF_US_DETECT_UNDEF));
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200815 } else {
816 if (detect_info.detect_timeout == USF_DEFAULT_TIMEOUT)
817 timeout = USF_TIMEOUT_JIFFIES;
818 else
819 timeout = detect_info.detect_timeout * HZ;
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300820 }
821 rc = wait_event_interruptible_timeout(usf_xx->wait,
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200822 (usf_xx->us_detect_type !=
823 USF_US_DETECT_UNDEF),
824 timeout);
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300825 /* In the case of timeout, "no US" is assumed */
826 if (rc < 0) {
827 pr_err("%s: Getting US detection failed rc[%d]\n",
828 __func__, rc);
829 return rc;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200830 }
831
832 usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200833 detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
834 rc = copy_to_user((void __user *)arg,
835 &detect_info,
836 sizeof(detect_info));
837 if (rc) {
838 pr_err("%s: copy detect_info to user; rc=%d\n",
839 __func__, rc);
840 rc = -EFAULT;
841 }
842
843 if (detect_info_size > sizeof(struct usm_session_cmd_detect_info))
844 kfree(p_usm_detect_info);
845
846 return rc;
847} /* usf_set_us_detection */
848
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200849static int usf_set_tx_info(struct usf_type *usf, unsigned long arg)
850{
851 struct us_tx_info_type config_tx;
852 const char *name = NULL;
853 struct usf_xx_type *usf_xx = &usf->usf_tx;
854 int rc = copy_from_user(&config_tx,
855 (void *) arg,
856 sizeof(config_tx));
857
858 if (rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200859 pr_err("%s: copy config_tx from user; rc=%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200860 __func__, rc);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200861 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200862 }
863
864 name = config_tx.us_xx_info.client_name;
865
866 usf_xx->new_region = USM_UNDEF_TOKEN;
867 usf_xx->prev_region = USM_UNDEF_TOKEN;
868 usf_xx->cb = usf_tx_cb;
869
870 init_waitqueue_head(&usf_xx->wait);
871
872 if (name != NULL) {
873 int res = strncpy_from_user(
874 usf_xx->client_name,
875 name,
876 sizeof(usf_xx->client_name)-1);
877 if (res < 0) {
878 pr_err("%s: get client name failed\n",
879 __func__);
880 return -EINVAL;
881 }
882 }
883
884 rc = config_xx(usf_xx, &config_tx.us_xx_info);
885 if (rc)
886 return rc;
887
888 rc = q6usm_open_read(usf_xx->usc,
889 usf_xx->encdec_cfg.format_id);
890 if (rc)
891 return rc;
892
893 rc = q6usm_us_client_buf_alloc(OUT, usf_xx->usc,
894 usf_xx->buffer_size,
895 usf_xx->buffer_count);
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300896 if (rc) {
897 (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200898 return rc;
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300899 }
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200900
901 rc = q6usm_enc_cfg_blk(usf_xx->usc,
902 &usf_xx->encdec_cfg);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200903 if (!rc &&
904 (config_tx.input_info.event_types != USF_NO_EVENT)) {
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200905 rc = register_input_device(usf,
906 &config_tx.input_info);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200907 }
908
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300909 if (rc)
910 (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
911 else
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200912 usf_xx->usf_state = USF_CONFIGURED_STATE;
913
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200914 return rc;
915} /* usf_set_tx_info */
916
917static int usf_set_rx_info(struct usf_type *usf, unsigned long arg)
918{
919 struct us_rx_info_type config_rx;
920 struct usf_xx_type *usf_xx = &usf->usf_rx;
921 int rc = copy_from_user(&config_rx,
922 (void *) arg,
923 sizeof(config_rx));
924
925 if (rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200926 pr_err("%s: copy config_rx from user; rc=%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200927 __func__, rc);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200928 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200929 }
930
931 usf_xx->new_region = USM_UNDEF_TOKEN;
932 usf_xx->prev_region = USM_UNDEF_TOKEN;
933
934 usf_xx->cb = usf_rx_cb;
935
936 rc = config_xx(usf_xx, &config_rx.us_xx_info);
937 if (rc)
938 return rc;
939
940 rc = q6usm_open_write(usf_xx->usc,
941 usf_xx->encdec_cfg.format_id);
942 if (rc)
943 return rc;
944
945 if (usf_xx->buffer_size && usf_xx->buffer_count) {
946 rc = q6usm_us_client_buf_alloc(
947 IN,
948 usf_xx->usc,
949 usf_xx->buffer_size,
950 usf_xx->buffer_count);
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300951 if (rc) {
952 (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200953 return rc;
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300954 }
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200955 }
956
957 rc = q6usm_dec_cfg_blk(usf_xx->usc,
958 &usf_xx->encdec_cfg);
Baruch Eruchimovitch64eb8da2013-04-08 14:33:17 +0300959 if (rc)
960 (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
961 else {
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200962 init_waitqueue_head(&usf_xx->wait);
963 usf_xx->usf_state = USF_CONFIGURED_STATE;
964 }
965
966 return rc;
967} /* usf_set_rx_info */
968
969
970static int usf_get_tx_update(struct usf_type *usf, unsigned long arg)
971{
972 struct us_tx_update_info_type upd_tx_info;
973 unsigned long prev_jiffies = 0;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200974 uint32_t timeout = 0;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200975 struct usf_xx_type *usf_xx = &usf->usf_tx;
976 int rc = copy_from_user(&upd_tx_info, (void *) arg,
977 sizeof(upd_tx_info));
978
979 if (rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200980 pr_err("%s: copy upd_tx_info from user; rc=%d\n",
981 __func__, rc);
982 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200983 }
984
985 if (!usf_xx->user_upd_info_na) {
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300986 usf_set_event_filters(usf, upd_tx_info.event_filters);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200987 handle_input_event(usf,
988 upd_tx_info.event_counter,
989 upd_tx_info.event);
990
991 /* Release available regions */
992 rc = q6usm_read(usf_xx->usc,
993 upd_tx_info.free_region);
994 if (rc)
995 return rc;
996 } else
997 usf_xx->user_upd_info_na = 0;
998
999 /* Get data ready regions */
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001000 if (upd_tx_info.timeout == USF_INFINITIVE_TIMEOUT) {
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +03001001 rc = wait_event_interruptible(usf_xx->wait,
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001002 (usf_xx->prev_region !=
1003 usf_xx->new_region) ||
1004 (usf_xx->usf_state !=
1005 USF_WORK_STATE));
1006 } else {
1007 if (upd_tx_info.timeout == USF_NO_WAIT_TIMEOUT)
1008 rc = (usf_xx->prev_region != usf_xx->new_region);
1009 else {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001010 prev_jiffies = jiffies;
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +03001011 if (upd_tx_info.timeout == USF_DEFAULT_TIMEOUT) {
1012 timeout = USF_TIMEOUT_JIFFIES;
1013 rc = wait_event_timeout(
1014 usf_xx->wait,
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001015 (usf_xx->prev_region !=
1016 usf_xx->new_region) ||
1017 (usf_xx->usf_state !=
1018 USF_WORK_STATE),
1019 timeout);
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +03001020 } else {
1021 timeout = upd_tx_info.timeout * HZ;
1022 rc = wait_event_interruptible_timeout(
1023 usf_xx->wait,
1024 (usf_xx->prev_region !=
1025 usf_xx->new_region) ||
1026 (usf_xx->usf_state !=
1027 USF_WORK_STATE),
1028 timeout);
1029 }
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001030 }
1031 if (!rc) {
1032 pr_debug("%s: timeout. prev_j=%lu; j=%lu\n",
1033 __func__, prev_jiffies, jiffies);
1034 pr_debug("%s: timeout. prev=%d; new=%d\n",
1035 __func__, usf_xx->prev_region,
1036 usf_xx->new_region);
1037 pr_debug("%s: timeout. free_region=%d;\n",
1038 __func__, upd_tx_info.free_region);
1039 if (usf_xx->prev_region ==
1040 usf_xx->new_region) {
1041 pr_err("%s:read data: timeout\n",
1042 __func__);
1043 return -ETIME;
1044 }
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001045 }
1046 }
1047
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +03001048 if ((usf_xx->usf_state != USF_WORK_STATE) ||
1049 (rc == -ERESTARTSYS)) {
Baruch Eruchimovitch258b3472012-10-14 21:46:35 +02001050 pr_err("%s: Get ready region failure; state[%d]; rc[%d]\n",
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +03001051 __func__, usf_xx->usf_state, rc);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001052 return -EINTR;
1053 }
1054
1055 upd_tx_info.ready_region = usf_xx->new_region;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001056 usf_xx->prev_region = upd_tx_info.ready_region;
1057
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001058 if (upd_tx_info.ready_region == USM_WRONG_TOKEN) {
1059 pr_err("%s: TX path corrupted; prev=%d\n",
1060 __func__, usf_xx->prev_region);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001061 return -EIO;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001062 }
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001063
1064 rc = copy_to_user((void __user *)arg, &upd_tx_info,
1065 sizeof(upd_tx_info));
1066 if (rc) {
1067 pr_err("%s: copy upd_tx_info to user; rc=%d\n",
1068 __func__, rc);
1069 rc = -EFAULT;
1070 }
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001071
1072 return rc;
1073} /* usf_get_tx_update */
1074
1075static int usf_set_rx_update(struct usf_xx_type *usf_xx, unsigned long arg)
1076{
1077 struct us_rx_update_info_type upd_rx_info;
1078 int rc = copy_from_user(&upd_rx_info, (void *) arg,
1079 sizeof(upd_rx_info));
1080
1081 if (rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001082 pr_err("%s: copy upd_rx_info from user; rc=%d\n",
1083 __func__, rc);
1084 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001085 }
1086
1087 /* Send available data regions */
1088 if (upd_rx_info.ready_region !=
1089 usf_xx->buffer_count) {
1090 rc = q6usm_write(
1091 usf_xx->usc,
1092 upd_rx_info.ready_region);
1093 if (rc)
1094 return rc;
1095 }
1096
1097 /* Get free regions */
1098 rc = wait_event_timeout(
1099 usf_xx->wait,
1100 !q6usm_is_write_buf_full(
1101 usf_xx->usc,
1102 &upd_rx_info.free_region) ||
1103 (usf_xx->usf_state == USF_IDLE_STATE),
1104 USF_TIMEOUT_JIFFIES);
1105
1106 if (!rc) {
1107 rc = -ETIME;
1108 pr_err("%s:timeout. wait for write buf not full\n",
1109 __func__);
1110 } else {
1111 if (usf_xx->usf_state !=
1112 USF_WORK_STATE) {
1113 pr_err("%s: RX: state[%d]\n",
1114 __func__,
1115 usf_xx->usf_state);
1116 rc = -EINTR;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001117 } else {
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001118 rc = copy_to_user(
1119 (void __user *)arg,
1120 &upd_rx_info,
1121 sizeof(upd_rx_info));
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001122 if (rc) {
1123 pr_err("%s: copy rx_info to user; rc=%d\n",
1124 __func__, rc);
1125 rc = -EFAULT;
1126 }
1127 }
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001128 }
1129
1130 return rc;
1131} /* usf_set_rx_update */
1132
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +03001133static void usf_release_input(struct usf_type *usf)
1134{
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +03001135 uint16_t ind = 0;
1136
Baruch Eruchimovitch32b44a22012-07-24 15:42:59 +03001137 usf_unregister_conflicting_events(
1138 usf->conflicting_event_types);
1139 usf->conflicting_event_types = 0;
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +03001140 for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
1141 if (usf->input_ifs[ind] == NULL)
1142 continue;
Baruch Eruchimovitchcf5a4d12012-05-31 21:48:18 +03001143 input_unregister_device(usf->input_ifs[ind]);
1144 usf->input_ifs[ind] = NULL;
1145 pr_debug("%s input_unregister_device[%s]\n",
1146 __func__,
1147 s_usf_input_devs[ind].input_dev_name);
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +03001148 }
1149} /* usf_release_input */
1150
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001151static int usf_stop_tx(struct usf_type *usf)
1152{
1153 struct usf_xx_type *usf_xx = &usf->usf_tx;
1154
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +03001155 usf_release_input(usf);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001156 usf_disable(usf_xx);
1157
1158 return 0;
1159} /* usf_stop_tx */
1160
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001161static int usf_get_version(unsigned long arg)
1162{
1163 struct us_version_info_type version_info;
1164 int rc = copy_from_user(&version_info, (void *) arg,
1165 sizeof(version_info));
1166
1167 if (rc) {
1168 pr_err("%s: copy version_info from user; rc=%d\n",
1169 __func__, rc);
1170 return -EFAULT;
1171 }
1172
1173 /* version_info.buf is pointer to place for the version string */
1174 rc = copy_to_user(version_info.pbuf,
1175 DRV_VERSION,
1176 version_info.buf_size);
1177 if (rc) {
1178 pr_err("%s: copy to version_info.pbuf; rc=%d\n",
1179 __func__, rc);
1180 rc = -EFAULT;
1181 }
1182
1183 rc = copy_to_user((void __user *)arg,
1184 &version_info,
1185 sizeof(version_info));
1186 if (rc) {
1187 pr_err("%s: copy version_info to user; rc=%d\n",
1188 __func__, rc);
1189 rc = -EFAULT;
1190 }
1191
1192 return rc;
1193} /* usf_get_version */
1194
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001195static long usf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1196{
1197 int rc = 0;
1198 struct usf_type *usf = file->private_data;
1199 struct usf_xx_type *usf_xx = NULL;
1200
1201 switch (cmd) {
1202 case US_START_TX: {
1203 usf_xx = &usf->usf_tx;
1204 if (usf_xx->usf_state == USF_CONFIGURED_STATE)
1205 rc = usf_start_tx(usf_xx);
1206 else {
1207 pr_err("%s: start_tx: wrong state[%d]\n",
1208 __func__,
1209 usf_xx->usf_state);
1210 return -EBADFD;
1211 }
1212 break;
1213 }
1214
1215 case US_START_RX: {
1216 usf_xx = &usf->usf_rx;
1217 if (usf_xx->usf_state == USF_CONFIGURED_STATE)
1218 rc = usf_start_rx(usf_xx);
1219 else {
1220 pr_err("%s: start_rx: wrong state[%d]\n",
1221 __func__,
1222 usf_xx->usf_state);
1223 return -EBADFD;
1224 }
1225 break;
1226 }
1227
1228 case US_SET_TX_INFO: {
1229 usf_xx = &usf->usf_tx;
1230 if (usf_xx->usf_state == USF_OPENED_STATE)
1231 rc = usf_set_tx_info(usf, arg);
1232 else {
1233 pr_err("%s: set_tx_info: wrong state[%d]\n",
1234 __func__,
1235 usf_xx->usf_state);
1236 return -EBADFD;
1237 }
1238
1239 break;
1240 } /* US_SET_TX_INFO */
1241
1242 case US_SET_RX_INFO: {
1243 usf_xx = &usf->usf_rx;
1244 if (usf_xx->usf_state == USF_OPENED_STATE)
1245 rc = usf_set_rx_info(usf, arg);
1246 else {
1247 pr_err("%s: set_rx_info: wrong state[%d]\n",
1248 __func__,
1249 usf_xx->usf_state);
1250 return -EBADFD;
1251 }
1252
1253 break;
1254 } /* US_SET_RX_INFO */
1255
1256 case US_GET_TX_UPDATE: {
1257 struct usf_xx_type *usf_xx = &usf->usf_tx;
1258 if (usf_xx->usf_state == USF_WORK_STATE)
1259 rc = usf_get_tx_update(usf, arg);
1260 else {
1261 pr_err("%s: get_tx_update: wrong state[%d]\n", __func__,
1262 usf_xx->usf_state);
1263 rc = -EBADFD;
1264 }
1265 break;
1266 } /* US_GET_TX_UPDATE */
1267
1268 case US_SET_RX_UPDATE: {
1269 struct usf_xx_type *usf_xx = &usf->usf_rx;
1270 if (usf_xx->usf_state == USF_WORK_STATE)
1271 rc = usf_set_rx_update(usf_xx, arg);
1272 else {
1273 pr_err("%s: set_rx_update: wrong state[%d]\n",
1274 __func__,
1275 usf_xx->usf_state);
1276 rc = -EBADFD;
1277 }
1278 break;
1279 } /* US_SET_RX_UPDATE */
1280
1281 case US_STOP_TX: {
1282 usf_xx = &usf->usf_tx;
1283 if (usf_xx->usf_state == USF_WORK_STATE)
1284 rc = usf_stop_tx(usf);
1285 else {
1286 pr_err("%s: stop_tx: wrong state[%d]\n",
1287 __func__,
1288 usf_xx->usf_state);
1289 return -EBADFD;
1290 }
1291 break;
1292 } /* US_STOP_TX */
1293
1294 case US_STOP_RX: {
1295 usf_xx = &usf->usf_rx;
1296 if (usf_xx->usf_state == USF_WORK_STATE)
1297 usf_disable(usf_xx);
1298 else {
1299 pr_err("%s: stop_rx: wrong state[%d]\n",
1300 __func__,
1301 usf_xx->usf_state);
1302 return -EBADFD;
1303 }
1304 break;
1305 } /* US_STOP_RX */
1306
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001307 case US_SET_DETECTION: {
1308 struct usf_xx_type *usf_xx = &usf->usf_tx;
1309 if (usf_xx->usf_state == USF_WORK_STATE)
1310 rc = usf_set_us_detection(usf, arg);
1311 else {
1312 pr_err("%s: set us detection: wrong state[%d]\n",
1313 __func__,
1314 usf_xx->usf_state);
1315 rc = -EBADFD;
1316 }
1317 break;
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001318 } /* US_SET_DETECTION */
1319
1320 case US_GET_VERSION: {
1321 rc = usf_get_version(arg);
1322 break;
1323 } /* US_GET_VERSION */
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001324
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001325 default:
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001326 pr_err("%s: unsupported IOCTL command [%d]\n",
1327 __func__,
1328 cmd);
1329 rc = -ENOTTY;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001330 break;
1331 }
1332
1333 if (rc &&
1334 ((cmd == US_SET_TX_INFO) ||
1335 (cmd == US_SET_RX_INFO)))
1336 release_xx(usf_xx);
1337
1338 return rc;
1339} /* usf_ioctl */
1340
1341static int usf_mmap(struct file *file, struct vm_area_struct *vms)
1342{
1343 struct usf_type *usf = file->private_data;
1344 int dir = OUT;
1345 struct usf_xx_type *usf_xx = &usf->usf_tx;
1346
1347 if (vms->vm_flags & USF_VM_WRITE) { /* RX buf mapping */
1348 dir = IN;
1349 usf_xx = &usf->usf_rx;
1350 }
1351
1352 return q6usm_get_virtual_address(dir, usf_xx->usc, vms);
1353}
1354
1355static uint16_t add_opened_dev(int minor)
1356{
1357 uint16_t ind = 0;
1358
1359 for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
1360 if (minor == s_opened_devs[ind]) {
1361 pr_err("%s: device %d is already opened\n",
1362 __func__, minor);
1363 return USF_UNDEF_DEV_ID;
1364 }
1365
1366 if (s_opened_devs[ind] == 0) {
1367 s_opened_devs[ind] = minor;
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001368 pr_debug("%s: device %d is added; ind=%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001369 __func__, minor, ind);
1370 return ind;
1371 }
1372 }
1373
1374 pr_err("%s: there is no place for device %d\n",
1375 __func__, minor);
1376 return USF_UNDEF_DEV_ID;
1377}
1378
1379static int usf_open(struct inode *inode, struct file *file)
1380{
1381 struct usf_type *usf = NULL;
1382 uint16_t dev_ind = 0;
1383 int minor = MINOR(inode->i_rdev);
1384
1385 dev_ind = add_opened_dev(minor);
1386 if (dev_ind == USF_UNDEF_DEV_ID)
1387 return -EBUSY;
1388
1389 usf = kzalloc(sizeof(struct usf_type), GFP_KERNEL);
1390 if (usf == NULL) {
1391 pr_err("%s:usf allocation failed\n", __func__);
1392 return -ENOMEM;
1393 }
1394
1395 file->private_data = usf;
1396 usf->dev_ind = dev_ind;
1397
1398 usf->usf_tx.usf_state = USF_OPENED_STATE;
1399 usf->usf_rx.usf_state = USF_OPENED_STATE;
1400
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001401 usf->usf_tx.us_detect_type = USF_US_DETECT_UNDEF;
1402 usf->usf_rx.us_detect_type = USF_US_DETECT_UNDEF;
1403
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001404 pr_debug("%s:usf in open\n", __func__);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001405 return 0;
1406}
1407
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001408static int usf_release(struct inode *inode, struct file *file)
1409{
1410 struct usf_type *usf = file->private_data;
1411
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001412 pr_debug("%s: release entry\n", __func__);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001413
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +03001414 usf_release_input(usf);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001415
1416 usf_disable(&usf->usf_tx);
1417 usf_disable(&usf->usf_rx);
1418
1419 s_opened_devs[usf->dev_ind] = 0;
1420
1421 kfree(usf);
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001422 pr_debug("%s: release exit\n", __func__);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001423 return 0;
1424}
1425
1426static const struct file_operations usf_fops = {
1427 .owner = THIS_MODULE,
1428 .open = usf_open,
1429 .release = usf_release,
1430 .unlocked_ioctl = usf_ioctl,
1431 .mmap = usf_mmap,
1432};
1433
1434struct miscdevice usf_misc[MAX_DEVS_NUMBER] = {
1435 {
1436 .minor = MISC_DYNAMIC_MINOR,
1437 .name = "usf1",
1438 .fops = &usf_fops,
1439 },
1440};
1441
1442static int __init usf_init(void)
1443{
1444 int rc = 0;
1445 uint16_t ind = 0;
1446
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001447 pr_debug("%s: USF SW version %s.\n", __func__, DRV_VERSION);
1448 pr_debug("%s: Max %d devs registration\n", __func__, MAX_DEVS_NUMBER);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001449
1450 for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
1451 rc = misc_register(&usf_misc[ind]);
1452 if (rc) {
1453 pr_err("%s: misc_register() failed ind=%d; rc = %d\n",
1454 __func__, ind, rc);
1455 break;
1456 }
1457 }
1458
1459 return rc;
1460}
1461
1462device_initcall(usf_init);
1463
1464MODULE_DESCRIPTION("Ultrasound framework driver");