blob: 614339b41eb23688eb87bbbceb0e8f652aa3df5f [file] [log] [blame]
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001/* Copyright (c) 2011-2012, Code Aurora Forum. 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 Eruchimovitchd0c077f2012-05-03 18:38:34 +030030#define DRV_VERSION "1.3.1"
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020031
32/* Standard timeout in the asynchronous ops */
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +030033#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020034
35/* Undefined USF device */
36#define USF_UNDEF_DEV_ID 0xffff
37
38/* RX memory mapping flag */
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +020039#define USF_VM_WRITE 2
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020040
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +020041/* Number of events, copied from the user space to kernel one */
42#define USF_EVENTS_PORTION_SIZE 20
43
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +020044/* Indexes in range definitions */
45#define MIN_IND 0
46#define MAX_IND 1
47
48/* The coordinates indexes */
49#define X_IND 0
50#define Y_IND 1
51#define Z_IND 2
52
53/* Place for opreation result, received from QDSP6 */
54#define APR_RESULT_IND 1
55
56/* Place for US detection result, received from QDSP6 */
57#define APR_US_DETECT_RESULT_IND 0
58
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020059/* The driver states */
60enum usf_state_type {
61 USF_IDLE_STATE,
62 USF_OPENED_STATE,
63 USF_CONFIGURED_STATE,
64 USF_WORK_STATE,
65 USF_ERROR_STATE
66};
67
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +020068/* The US detection status upon FW/HW based US detection results */
69enum usf_us_detect_type {
70 USF_US_DETECT_UNDEF,
71 USF_US_DETECT_YES,
72 USF_US_DETECT_NO
73};
74
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020075struct usf_xx_type {
76 /* Name of the client - event calculator */
77 char client_name[USF_MAX_CLIENT_NAME_SIZE];
78 /* The driver state in TX or RX direction */
79 enum usf_state_type usf_state;
80 /* wait for q6 events mechanism */
81 wait_queue_head_t wait;
82 /* IF with q6usm info */
83 struct us_client *usc;
84 /* Q6:USM' Encoder/decoder configuration */
85 struct us_encdec_cfg encdec_cfg;
86 /* Shared buffer (with Q6:USM) size */
87 uint32_t buffer_size;
88 /* Number of the shared buffers (with Q6:USM) */
89 uint32_t buffer_count;
90 /* Shared memory (Cyclic buffer with 1 gap) control */
91 uint32_t new_region;
92 uint32_t prev_region;
93 /* Q6:USM's events handler */
94 void (*cb)(uint32_t, uint32_t, uint32_t *, void *);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +020095 /* US detection result */
96 enum usf_us_detect_type us_detect_type;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +020097 /* User's update info isn't acceptable */
98 u8 user_upd_info_na;
99};
100
101struct usf_type {
102 /* TX device component configuration & control */
103 struct usf_xx_type usf_tx;
104 /* RX device component configuration & control */
105 struct usf_xx_type usf_rx;
106 /* Index into the opened device container */
107 /* To prevent mutual usage of the same device */
108 uint16_t dev_ind;
109 /* Event types, supported by device */
110 uint16_t event_types;
111 /* The device is "input" module registered client */
112 struct input_dev *input_if;
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200113 /* The event source */
114 int event_src;
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300115 /* Bitmap of types of events, conflicting to USF's ones */
116 uint16_t conflicting_event_types;
117 /* Bitmap of types of events from devs, conflicting with USF */
118 uint16_t conflicting_event_filters;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200119};
120
121/* The MAX number of the supported devices */
122#define MAX_DEVS_NUMBER 1
123
124/* The opened devices container */
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200125static const int s_event_src_map[] = {
126 BTN_TOOL_PEN, /* US_INPUT_SRC_PEN*/
127 0, /* US_INPUT_SRC_FINGER */
128 0, /* US_INPUT_SRC_UNDEF */
129};
130
131/* The opened devices container */
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200132static int s_opened_devs[MAX_DEVS_NUMBER];
133
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300134#define USF_NAME_PREFIX "USF_"
135#define USF_NAME_PREFIX_SIZE 4
136
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200137static void usf_rx_cb(uint32_t opcode, uint32_t token,
138 uint32_t *payload, void *priv)
139{
140 struct usf_xx_type *usf_xx = (struct usf_xx_type *) priv;
141
142 if (usf_xx == NULL) {
143 pr_err("%s: the private data is NULL\n", __func__);
144 return;
145 }
146
147 switch (opcode) {
148 case USM_DATA_EVENT_WRITE_DONE:
149 wake_up(&usf_xx->wait);
150 break;
151 default:
152 break;
153 }
154}
155
156static void usf_tx_cb(uint32_t opcode, uint32_t token,
157 uint32_t *payload, void *priv)
158{
159 struct usf_xx_type *usf_xx = (struct usf_xx_type *) priv;
160
161 if (usf_xx == NULL) {
162 pr_err("%s: the private data is NULL\n", __func__);
163 return;
164 }
165
166 switch (opcode) {
167 case USM_DATA_EVENT_READ_DONE:
168 if (token == USM_WRONG_TOKEN)
169 usf_xx->usf_state = USF_ERROR_STATE;
170 usf_xx->new_region = token;
171 wake_up(&usf_xx->wait);
172 break;
173
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200174 case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT:
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200175 usf_xx->us_detect_type = (payload[APR_US_DETECT_RESULT_IND]) ?
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200176 USF_US_DETECT_YES :
177 USF_US_DETECT_NO;
178
179 wake_up(&usf_xx->wait);
180 break;
181
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200182 case APR_BASIC_RSP_RESULT:
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200183 if (payload[APR_RESULT_IND]) {
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200184 usf_xx->usf_state = USF_ERROR_STATE;
185 usf_xx->new_region = USM_WRONG_TOKEN;
186 wake_up(&usf_xx->wait);
187 }
188 break;
189
190 default:
191 break;
192 }
193}
194
195static void release_xx(struct usf_xx_type *usf_xx)
196{
197 if (usf_xx != NULL) {
198 if (usf_xx->usc) {
199 q6usm_us_client_free(usf_xx->usc);
200 usf_xx->usc = NULL;
201 }
202
203 if (usf_xx->encdec_cfg.params != NULL) {
204 kfree(usf_xx->encdec_cfg.params);
205 usf_xx->encdec_cfg.params = NULL;
206 }
207 }
208}
209
210static void usf_disable(struct usf_xx_type *usf_xx)
211{
212 if (usf_xx != NULL) {
213 if ((usf_xx->usf_state != USF_IDLE_STATE) &&
214 (usf_xx->usf_state != USF_OPENED_STATE)) {
215 (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
216 usf_xx->usf_state = USF_OPENED_STATE;
217 wake_up(&usf_xx->wait);
218 }
219 release_xx(usf_xx);
220 }
221}
222
223static int config_xx(struct usf_xx_type *usf_xx, struct us_xx_info_type *config)
224{
225 int rc = 0;
226 uint16_t data_map_size = 0;
227
228 if ((usf_xx == NULL) ||
229 (config == NULL))
230 return -EINVAL;
231
232 data_map_size = sizeof(usf_xx->encdec_cfg.cfg_common.data_map);
233
234 if (config->client_name != NULL) {
235 if (strncpy_from_user(usf_xx->client_name,
236 config->client_name,
237 sizeof(usf_xx->client_name) - 1) < 0) {
238 pr_err("%s: get client name failed\n", __func__);
239 return -EINVAL;
240 }
241 }
242
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200243 pr_debug("%s: name=%s; buf_size:%d; dev_id:0x%x; sample_rate:%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200244 __func__, usf_xx->client_name, config->buf_size,
245 config->dev_id, config->sample_rate);
246
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200247 pr_debug("%s: buf_num:%d; format:%d; port_cnt:%d; data_size=%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200248 __func__, config->buf_num, config->stream_format,
249 config->port_cnt, config->params_data_size);
250
251 pr_debug("%s: p_id[0]=%d, p_id[1]=%d, p_id[2]=%d, p_id[3]=%d\n",
252 __func__,
253 config->port_id[0],
254 config->port_id[1],
255 config->port_id[2],
256 config->port_id[3]);
257
258 if (data_map_size < config->port_cnt) {
259 pr_err("%s: number of supported ports:%d < requested:%d\n",
260 __func__,
261 data_map_size,
262 config->port_cnt);
263 return -EINVAL;
264 }
265
266 /* q6usm allocation & configuration */
267 usf_xx->buffer_size = config->buf_size;
268 usf_xx->buffer_count = config->buf_num;
269 usf_xx->encdec_cfg.cfg_common.bits_per_sample =
270 config->bits_per_sample;
271 usf_xx->encdec_cfg.cfg_common.sample_rate = config->sample_rate;
272 /* AFE port e.g. AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX */
273 usf_xx->encdec_cfg.cfg_common.dev_id = config->dev_id;
274
275 usf_xx->encdec_cfg.cfg_common.ch_cfg = config->port_cnt;
276 memcpy((void *)&usf_xx->encdec_cfg.cfg_common.data_map,
277 (void *)config->port_id,
278 config->port_cnt);
279 if (rc) {
280 pr_err("%s: ports offsets copy failure\n", __func__);
281 return -EINVAL;
282 }
283
284 usf_xx->encdec_cfg.format_id = config->stream_format;
285 usf_xx->encdec_cfg.params_size = config->params_data_size;
286 usf_xx->user_upd_info_na = 1; /* it's used in US_GET_TX_UPDATE */
287
288 if (config->params_data_size > 0) { /* transparent data copy */
289 usf_xx->encdec_cfg.params = kzalloc(config->params_data_size,
290 GFP_KERNEL);
291 if (usf_xx->encdec_cfg.params == NULL) {
292 pr_err("%s: params memory alloc[%d] failure\n",
293 __func__,
294 config->params_data_size);
295 return -ENOMEM;
296 }
297 rc = copy_from_user(usf_xx->encdec_cfg.params,
298 config->params_data,
299 config->params_data_size);
300 if (rc) {
301 pr_err("%s: transparent data copy failure\n",
302 __func__);
303 kfree(usf_xx->encdec_cfg.params);
304 usf_xx->encdec_cfg.params = NULL;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200305 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200306 }
307 pr_debug("%s: params_size[%d]; params[%d,%d,%d,%d, %d]\n",
308 __func__,
309 config->params_data_size,
310 usf_xx->encdec_cfg.params[0],
311 usf_xx->encdec_cfg.params[1],
312 usf_xx->encdec_cfg.params[2],
313 usf_xx->encdec_cfg.params[3],
314 usf_xx->encdec_cfg.params[4]
315 );
316 }
317
318 usf_xx->usc = q6usm_us_client_alloc(usf_xx->cb, (void *)usf_xx);
319 if (!usf_xx->usc) {
320 pr_err("%s: Could not allocate q6usm client\n", __func__);
321 rc = -EFAULT;
322 }
323
324 return rc;
325}
326
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300327static bool usf_match(uint16_t event_type_ind, struct input_dev *dev)
328{
329 bool rc = false;
330
331 rc = (event_type_ind < MAX_EVENT_TYPE_NUM) &&
332 ((dev->name == NULL) ||
333 strncmp(dev->name, USF_NAME_PREFIX, USF_NAME_PREFIX_SIZE));
334 pr_debug("%s: name=[%s]; rc=%d\n",
335 __func__, dev->name, rc);
336
337 return rc;
338}
339
340static bool usf_register_conflicting_events(uint16_t event_types)
341{
342 bool rc = true;
343 uint16_t ind = 0;
344 uint16_t mask = 1;
345
346 for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
347 if (event_types & mask) {
348 rc = usfcdev_register(ind, usf_match);
349 if (!rc)
350 break;
351 }
352 mask = mask << 1;
353 }
354
355 return rc;
356}
357
358static void usf_unregister_conflicting_events(uint16_t event_types)
359{
360 uint16_t ind = 0;
361 uint16_t mask = 1;
362
363 for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
364 if (event_types & mask)
365 usfcdev_unregister(ind);
366 mask = mask << 1;
367 }
368}
369
370static void usf_set_event_filters(struct usf_type *usf, uint16_t event_filters)
371{
372 uint16_t ind = 0;
373 uint16_t mask = 1;
374
375 if (usf->conflicting_event_filters != event_filters) {
376 for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
377 if (usf->conflicting_event_types & mask)
378 usfcdev_set_filter(ind, event_filters&mask);
379 mask = mask << 1;
380 }
381 usf->conflicting_event_filters = event_filters;
382 }
383}
384
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200385static int register_input_device(struct usf_type *usf_info,
386 struct us_input_info_type *input_info)
387{
388 int rc = 0;
389 struct input_dev *input_dev = NULL;
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300390 bool ret = true;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200391
392 if ((usf_info == NULL) ||
393 (input_info == NULL) ||
394 !(input_info->event_types & USF_ALL_EVENTS)) {
395 pr_err("%s: wrong input parameter(s)\n", __func__);
396 return -EINVAL;
397 }
398
399 if (usf_info->input_if != NULL) {
400 pr_err("%s: input_if is already allocated\n", __func__);
401 return -EFAULT;
402 }
403
404 input_dev = input_allocate_device();
405 if (input_dev == NULL) {
406 pr_err("%s: input_allocate_device() failed\n", __func__);
407 return -ENOMEM;
408 }
409
410 /* Common part configuration */
411 input_dev->name = (const char *)(usf_info->usf_tx.client_name);
412 input_dev->phys = NULL;
413 input_dev->id.bustype = BUS_HOST;
414 input_dev->id.vendor = 0x0001;
415 input_dev->id.product = 0x0001;
416 input_dev->id.version = 0x0001;
417
418 if (input_info->event_types & USF_TSC_EVENT) {
419 /* TSC part configuration */
420 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
421 input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
422 input_set_abs_params(input_dev, ABS_X,
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200423 input_info->tsc_x_dim[MIN_IND],
424 input_info->tsc_x_dim[MAX_IND],
425 0, 0);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200426 input_set_abs_params(input_dev, ABS_Y,
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200427 input_info->tsc_y_dim[MIN_IND],
428 input_info->tsc_y_dim[MAX_IND],
429 0, 0);
430 input_set_abs_params(input_dev, ABS_DISTANCE,
431 input_info->tsc_z_dim[MIN_IND],
432 input_info->tsc_z_dim[MAX_IND],
433 0, 0);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200434
435 input_set_abs_params(input_dev, ABS_PRESSURE,
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200436 input_info->tsc_pressure[MIN_IND],
437 input_info->tsc_pressure[MAX_IND], 0, 0);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200438
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200439 input_set_abs_params(input_dev, ABS_TILT_X,
440 input_info->tsc_x_tilt[MIN_IND],
441 input_info->tsc_x_tilt[MAX_IND],
442 0, 0);
443 input_set_abs_params(input_dev, ABS_TILT_Y,
444 input_info->tsc_y_tilt[MIN_IND],
445 input_info->tsc_y_tilt[MAX_IND],
446 0, 0);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200447 }
448
449 if (input_info->event_types & USF_MOUSE_EVENT) {
450 /* Mouse part configuration */
451 input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
452
453 input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
454 BIT_MASK(BTN_RIGHT) |
455 BIT_MASK(BTN_MIDDLE);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200456 input_dev->relbit[0] = BIT_MASK(REL_X) |
457 BIT_MASK(REL_Y) |
458 BIT_MASK(REL_Z);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200459 }
460
461 if (input_info->event_types & USF_KEYBOARD_EVENT) {
462 /* Keyboard part configuration */
463 input_dev->evbit[0] |= BIT_MASK(EV_KEY);
464
465 /* All keys are permitted */
466 memset(input_dev->keybit, 0xff, sizeof(input_dev->keybit));
467 }
468
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200469 if (input_info->event_src < ARRAY_SIZE(s_event_src_map))
470 usf_info->event_src = s_event_src_map[input_info->event_src];
471 else
472 usf_info->event_src = 0;
473
474 if (usf_info->event_src)
475 input_set_capability(input_dev, EV_KEY, usf_info->event_src);
476
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200477 rc = input_register_device(input_dev);
478 if (rc) {
479 pr_err("%s: input_register_device() failed; rc=%d\n",
480 __func__, rc);
481 input_free_device(input_dev);
482 } else {
483 usf_info->input_if = input_dev;
484 usf_info->event_types = input_info->event_types;
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200485 pr_debug("%s: input device[%s] was registered\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200486 __func__, input_dev->name);
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300487 ret = usf_register_conflicting_events(
488 input_info->conflicting_event_types);
489 if (ret)
490 usf_info->conflicting_event_types =
491 input_info->conflicting_event_types;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200492 }
493
494 return rc;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200495}
496
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200497static void notify_tsc_event(struct usf_type *usf_info,
498 struct point_event_type *pe)
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200499{
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200500 struct input_dev *input_if = usf_info->input_if;
501
502 input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
503 input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
504 input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
505
506 input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
507 input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
508
509 input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
510 input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
511
512 if (usf_info->event_src)
513 input_report_key(input_if, usf_info->event_src, 1);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200514
515 input_sync(input_if);
516
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200517 pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
518 __func__,
519 pe->coordinates[X_IND],
520 pe->coordinates[Y_IND],
521 pe->coordinates[Z_IND],
522 pe->inclinations[X_IND],
523 pe->inclinations[Y_IND],
524 pe->pressure);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200525}
526
527static void notify_mouse_event(struct input_dev *input_if,
528 struct mouse_event_type *me)
529{
530 if (me == NULL) {
531 pr_err("%s: mouse event is NULL\n", __func__);
532 return;
533 }
534
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200535 input_report_rel(input_if, REL_X, me->rels[X_IND]);
536 input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
537 input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200538
539 input_report_key(input_if, BTN_LEFT,
540 me->buttons_states & USF_BUTTON_LEFT_MASK);
541 input_report_key(input_if, BTN_MIDDLE,
542 me->buttons_states & USF_BUTTON_MIDDLE_MASK);
543 input_report_key(input_if, BTN_RIGHT,
544 me->buttons_states & USF_BUTTON_RIGHT_MASK);
545
546 input_sync(input_if);
547
548 pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200549 __func__, me->rels[X_IND],
550 me->rels[Y_IND], me->buttons_states);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200551}
552
553static void notify_key_event(struct input_dev *input_if,
554 struct key_event_type *ke)
555{
556 if (ke == NULL) {
557 pr_err("%s: key event is NULL\n", __func__);
558 return;
559 }
560
561 input_report_key(input_if, ke->key, ke->key_state);
562 input_sync(input_if);
563 pr_debug("%s: key event: key[%d], state[%d]\n",
564 __func__,
565 ke->key,
566 ke->key_state);
567
568}
569
570static void handle_input_event(struct usf_type *usf_info,
571 uint16_t event_counter,
572 struct usf_event_type *event)
573{
574 struct input_dev *input_if = NULL;
575 uint16_t ind = 0;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200576 uint16_t events_num = 0;
577 struct usf_event_type usf_events[USF_EVENTS_PORTION_SIZE];
578 int rc = 0;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200579
580 if ((usf_info == NULL) || (usf_info->input_if == NULL) ||
581 (event == NULL) || (!event_counter)) {
582 return;
583 }
584
585 input_if = usf_info->input_if;
586
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200587 while (event_counter > 0) {
588 if (event_counter > USF_EVENTS_PORTION_SIZE) {
589 events_num = USF_EVENTS_PORTION_SIZE;
590 event_counter -= USF_EVENTS_PORTION_SIZE;
591 } else {
592 events_num = event_counter;
593 event_counter = 0;
594 }
595 rc = copy_from_user(usf_events,
596 event,
597 events_num * sizeof(struct usf_event_type));
598 if (rc) {
599 pr_err("%s: copy upd_rx_info from user; rc=%d\n",
600 __func__, rc);
601 return;
602 }
603 for (ind = 0; ind < events_num; ++ind) {
604 struct usf_event_type *p_event = &usf_events[ind];
605 if (p_event->event_type & USF_TSC_EVENT) {
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200606 struct point_event_type *pe =
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200607 &(p_event->event_data.point_event);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200608 if (pe->coordinates_type ==
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200609 USF_PIX_COORDINATE)
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200610 notify_tsc_event(usf_info, pe);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200611 else
612 pr_debug("%s: wrong coord type: %d",
613 __func__,
614 pe->coordinates_type);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200615 continue;
616 }
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200617 if (p_event->event_type & USF_MOUSE_EVENT) {
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200618 notify_mouse_event(input_if,
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200619 &(p_event->event_data.mouse_event));
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200620 continue;
621 }
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200622 if (p_event->event_type & USF_KEYBOARD_EVENT)
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200623 notify_key_event(input_if,
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200624 &(p_event->event_data.key_event));
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200625 } /* loop in the portion */
626 } /* all events loop */
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200627}
628
629static int usf_start_tx(struct usf_xx_type *usf_xx)
630{
631 int rc = q6usm_run(usf_xx->usc, 0, 0, 0);
632
633 pr_debug("%s: tx: q6usm_run; rc=%d\n", __func__, rc);
634 if (!rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200635 if (usf_xx->buffer_count >= USM_MIN_BUF_CNT) {
636 /* supply all buffers */
637 rc = q6usm_read(usf_xx->usc,
638 usf_xx->buffer_count);
639 pr_debug("%s: q6usm_read[%d]\n",
640 __func__, rc);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200641
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200642 if (rc)
643 pr_err("%s: buf read failed",
644 __func__);
645 else
646 usf_xx->usf_state =
647 USF_WORK_STATE;
648 } else
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200649 usf_xx->usf_state =
650 USF_WORK_STATE;
651 }
652
653 return rc;
654} /* usf_start_tx */
655
656static int usf_start_rx(struct usf_xx_type *usf_xx)
657{
658 int rc = q6usm_run(usf_xx->usc, 0, 0, 0);
659
660 pr_debug("%s: rx: q6usm_run; rc=%d\n",
661 __func__, rc);
662 if (!rc)
663 usf_xx->usf_state = USF_WORK_STATE;
664
665 return rc;
666} /* usf_start_rx */
667
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200668static int usf_set_us_detection(struct usf_type *usf, unsigned long arg)
669{
670 uint32_t timeout = 0;
671 struct us_detect_info_type detect_info;
672 struct usm_session_cmd_detect_info usm_detect_info;
673 struct usm_session_cmd_detect_info *p_usm_detect_info =
674 &usm_detect_info;
675 uint32_t detect_info_size = sizeof(struct usm_session_cmd_detect_info);
676 struct usf_xx_type *usf_xx = &usf->usf_tx;
677 int rc = copy_from_user(&detect_info,
678 (void *) arg,
679 sizeof(detect_info));
680
681 if (rc) {
682 pr_err("%s: copy detect_info from user; rc=%d\n",
683 __func__, rc);
684 return -EFAULT;
685 }
686
687 if (detect_info.us_detector != US_DETECT_FW) {
688 pr_err("%s: unsupported detector: %d\n",
689 __func__, detect_info.us_detector);
690 return -EINVAL;
691 }
692
693 if ((detect_info.params_data_size != 0) &&
694 (detect_info.params_data != NULL)) {
695 uint8_t *p_data = NULL;
696
697 detect_info_size += detect_info.params_data_size;
698 p_usm_detect_info = kzalloc(detect_info_size, GFP_KERNEL);
699 if (p_usm_detect_info == NULL) {
700 pr_err("%s: detect_info[%d] allocation failed\n",
701 __func__, detect_info_size);
702 return -ENOMEM;
703 }
704 p_data = (uint8_t *)p_usm_detect_info +
705 sizeof(struct usm_session_cmd_detect_info);
706
707 rc = copy_from_user(p_data,
708 (void *)detect_info.params_data,
709 detect_info.params_data_size);
710 if (rc) {
711 pr_err("%s: copy params from user; rc=%d\n",
712 __func__, rc);
713 kfree(p_usm_detect_info);
714 return -EFAULT;
715 }
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +0200716 p_usm_detect_info->algorithm_cfg_size =
717 detect_info.params_data_size;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200718 } else
719 usm_detect_info.algorithm_cfg_size = 0;
720
721 p_usm_detect_info->detect_mode = detect_info.us_detect_mode;
722 p_usm_detect_info->skip_interval = detect_info.skip_time;
723
724 usf_xx->us_detect_type = USF_US_DETECT_UNDEF;
725
726 rc = q6usm_set_us_detection(usf_xx->usc,
727 p_usm_detect_info,
728 detect_info_size);
729 if (rc || (detect_info.detect_timeout == USF_NO_WAIT_TIMEOUT)) {
730 if (detect_info_size >
731 sizeof(struct usm_session_cmd_detect_info))
732 kfree(p_usm_detect_info);
733 return rc;
734 }
735
736 /* Get US detection result */
737 if (detect_info.detect_timeout == USF_INFINITIVE_TIMEOUT) {
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300738 rc = wait_event_interruptible(usf_xx->wait,
739 (usf_xx->us_detect_type !=
740 USF_US_DETECT_UNDEF));
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200741 } else {
742 if (detect_info.detect_timeout == USF_DEFAULT_TIMEOUT)
743 timeout = USF_TIMEOUT_JIFFIES;
744 else
745 timeout = detect_info.detect_timeout * HZ;
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300746 }
747 rc = wait_event_interruptible_timeout(usf_xx->wait,
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200748 (usf_xx->us_detect_type !=
749 USF_US_DETECT_UNDEF),
750 timeout);
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300751 /* In the case of timeout, "no US" is assumed */
752 if (rc < 0) {
753 pr_err("%s: Getting US detection failed rc[%d]\n",
754 __func__, rc);
755 return rc;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200756 }
757
758 usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200759 detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
760 rc = copy_to_user((void __user *)arg,
761 &detect_info,
762 sizeof(detect_info));
763 if (rc) {
764 pr_err("%s: copy detect_info to user; rc=%d\n",
765 __func__, rc);
766 rc = -EFAULT;
767 }
768
769 if (detect_info_size > sizeof(struct usm_session_cmd_detect_info))
770 kfree(p_usm_detect_info);
771
772 return rc;
773} /* usf_set_us_detection */
774
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200775static int usf_set_tx_info(struct usf_type *usf, unsigned long arg)
776{
777 struct us_tx_info_type config_tx;
778 const char *name = NULL;
779 struct usf_xx_type *usf_xx = &usf->usf_tx;
780 int rc = copy_from_user(&config_tx,
781 (void *) arg,
782 sizeof(config_tx));
783
784 if (rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200785 pr_err("%s: copy config_tx from user; rc=%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200786 __func__, rc);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200787 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200788 }
789
790 name = config_tx.us_xx_info.client_name;
791
792 usf_xx->new_region = USM_UNDEF_TOKEN;
793 usf_xx->prev_region = USM_UNDEF_TOKEN;
794 usf_xx->cb = usf_tx_cb;
795
796 init_waitqueue_head(&usf_xx->wait);
797
798 if (name != NULL) {
799 int res = strncpy_from_user(
800 usf_xx->client_name,
801 name,
802 sizeof(usf_xx->client_name)-1);
803 if (res < 0) {
804 pr_err("%s: get client name failed\n",
805 __func__);
806 return -EINVAL;
807 }
808 }
809
810 rc = config_xx(usf_xx, &config_tx.us_xx_info);
811 if (rc)
812 return rc;
813
814 rc = q6usm_open_read(usf_xx->usc,
815 usf_xx->encdec_cfg.format_id);
816 if (rc)
817 return rc;
818
819 rc = q6usm_us_client_buf_alloc(OUT, usf_xx->usc,
820 usf_xx->buffer_size,
821 usf_xx->buffer_count);
822 if (rc)
823 return rc;
824
825 rc = q6usm_enc_cfg_blk(usf_xx->usc,
826 &usf_xx->encdec_cfg);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200827 if (!rc &&
828 (config_tx.input_info.event_types != USF_NO_EVENT)) {
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200829 rc = register_input_device(usf,
830 &config_tx.input_info);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200831 }
832
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200833 if (!rc)
834 usf_xx->usf_state = USF_CONFIGURED_STATE;
835
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200836 return rc;
837} /* usf_set_tx_info */
838
839static int usf_set_rx_info(struct usf_type *usf, unsigned long arg)
840{
841 struct us_rx_info_type config_rx;
842 struct usf_xx_type *usf_xx = &usf->usf_rx;
843 int rc = copy_from_user(&config_rx,
844 (void *) arg,
845 sizeof(config_rx));
846
847 if (rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200848 pr_err("%s: copy config_rx from user; rc=%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200849 __func__, rc);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200850 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200851 }
852
853 usf_xx->new_region = USM_UNDEF_TOKEN;
854 usf_xx->prev_region = USM_UNDEF_TOKEN;
855
856 usf_xx->cb = usf_rx_cb;
857
858 rc = config_xx(usf_xx, &config_rx.us_xx_info);
859 if (rc)
860 return rc;
861
862 rc = q6usm_open_write(usf_xx->usc,
863 usf_xx->encdec_cfg.format_id);
864 if (rc)
865 return rc;
866
867 if (usf_xx->buffer_size && usf_xx->buffer_count) {
868 rc = q6usm_us_client_buf_alloc(
869 IN,
870 usf_xx->usc,
871 usf_xx->buffer_size,
872 usf_xx->buffer_count);
873 if (rc)
874 return rc;
875 }
876
877 rc = q6usm_dec_cfg_blk(usf_xx->usc,
878 &usf_xx->encdec_cfg);
879 if (!rc) {
880 init_waitqueue_head(&usf_xx->wait);
881 usf_xx->usf_state = USF_CONFIGURED_STATE;
882 }
883
884 return rc;
885} /* usf_set_rx_info */
886
887
888static int usf_get_tx_update(struct usf_type *usf, unsigned long arg)
889{
890 struct us_tx_update_info_type upd_tx_info;
891 unsigned long prev_jiffies = 0;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200892 uint32_t timeout = 0;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200893 struct usf_xx_type *usf_xx = &usf->usf_tx;
894 int rc = copy_from_user(&upd_tx_info, (void *) arg,
895 sizeof(upd_tx_info));
896
897 if (rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200898 pr_err("%s: copy upd_tx_info from user; rc=%d\n",
899 __func__, rc);
900 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200901 }
902
903 if (!usf_xx->user_upd_info_na) {
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +0300904 usf_set_event_filters(usf, upd_tx_info.event_filters);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200905 handle_input_event(usf,
906 upd_tx_info.event_counter,
907 upd_tx_info.event);
908
909 /* Release available regions */
910 rc = q6usm_read(usf_xx->usc,
911 upd_tx_info.free_region);
912 if (rc)
913 return rc;
914 } else
915 usf_xx->user_upd_info_na = 0;
916
917 /* Get data ready regions */
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200918 if (upd_tx_info.timeout == USF_INFINITIVE_TIMEOUT) {
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300919 rc = wait_event_interruptible(usf_xx->wait,
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200920 (usf_xx->prev_region !=
921 usf_xx->new_region) ||
922 (usf_xx->usf_state !=
923 USF_WORK_STATE));
924 } else {
925 if (upd_tx_info.timeout == USF_NO_WAIT_TIMEOUT)
926 rc = (usf_xx->prev_region != usf_xx->new_region);
927 else {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200928 prev_jiffies = jiffies;
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300929 if (upd_tx_info.timeout == USF_DEFAULT_TIMEOUT) {
930 timeout = USF_TIMEOUT_JIFFIES;
931 rc = wait_event_timeout(
932 usf_xx->wait,
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200933 (usf_xx->prev_region !=
934 usf_xx->new_region) ||
935 (usf_xx->usf_state !=
936 USF_WORK_STATE),
937 timeout);
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300938 } else {
939 timeout = upd_tx_info.timeout * HZ;
940 rc = wait_event_interruptible_timeout(
941 usf_xx->wait,
942 (usf_xx->prev_region !=
943 usf_xx->new_region) ||
944 (usf_xx->usf_state !=
945 USF_WORK_STATE),
946 timeout);
947 }
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200948 }
949 if (!rc) {
950 pr_debug("%s: timeout. prev_j=%lu; j=%lu\n",
951 __func__, prev_jiffies, jiffies);
952 pr_debug("%s: timeout. prev=%d; new=%d\n",
953 __func__, usf_xx->prev_region,
954 usf_xx->new_region);
955 pr_debug("%s: timeout. free_region=%d;\n",
956 __func__, upd_tx_info.free_region);
957 if (usf_xx->prev_region ==
958 usf_xx->new_region) {
959 pr_err("%s:read data: timeout\n",
960 __func__);
961 return -ETIME;
962 }
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200963 }
964 }
965
Baruch Eruchimovitchd0c077f2012-05-03 18:38:34 +0300966 if ((usf_xx->usf_state != USF_WORK_STATE) ||
967 (rc == -ERESTARTSYS)) {
968 pr_err("%s: Getting ready region failed "
969 "work state[%d]; rc[%d]\n",
970 __func__, usf_xx->usf_state, rc);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200971 return -EINTR;
972 }
973
974 upd_tx_info.ready_region = usf_xx->new_region;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200975 usf_xx->prev_region = upd_tx_info.ready_region;
976
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200977 if (upd_tx_info.ready_region == USM_WRONG_TOKEN) {
978 pr_err("%s: TX path corrupted; prev=%d\n",
979 __func__, usf_xx->prev_region);
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200980 return -EIO;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200981 }
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +0200982
983 rc = copy_to_user((void __user *)arg, &upd_tx_info,
984 sizeof(upd_tx_info));
985 if (rc) {
986 pr_err("%s: copy upd_tx_info to user; rc=%d\n",
987 __func__, rc);
988 rc = -EFAULT;
989 }
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +0200990
991 return rc;
992} /* usf_get_tx_update */
993
994static int usf_set_rx_update(struct usf_xx_type *usf_xx, unsigned long arg)
995{
996 struct us_rx_update_info_type upd_rx_info;
997 int rc = copy_from_user(&upd_rx_info, (void *) arg,
998 sizeof(upd_rx_info));
999
1000 if (rc) {
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001001 pr_err("%s: copy upd_rx_info from user; rc=%d\n",
1002 __func__, rc);
1003 return -EFAULT;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001004 }
1005
1006 /* Send available data regions */
1007 if (upd_rx_info.ready_region !=
1008 usf_xx->buffer_count) {
1009 rc = q6usm_write(
1010 usf_xx->usc,
1011 upd_rx_info.ready_region);
1012 if (rc)
1013 return rc;
1014 }
1015
1016 /* Get free regions */
1017 rc = wait_event_timeout(
1018 usf_xx->wait,
1019 !q6usm_is_write_buf_full(
1020 usf_xx->usc,
1021 &upd_rx_info.free_region) ||
1022 (usf_xx->usf_state == USF_IDLE_STATE),
1023 USF_TIMEOUT_JIFFIES);
1024
1025 if (!rc) {
1026 rc = -ETIME;
1027 pr_err("%s:timeout. wait for write buf not full\n",
1028 __func__);
1029 } else {
1030 if (usf_xx->usf_state !=
1031 USF_WORK_STATE) {
1032 pr_err("%s: RX: state[%d]\n",
1033 __func__,
1034 usf_xx->usf_state);
1035 rc = -EINTR;
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001036 } else {
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001037 rc = copy_to_user(
1038 (void __user *)arg,
1039 &upd_rx_info,
1040 sizeof(upd_rx_info));
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001041 if (rc) {
1042 pr_err("%s: copy rx_info to user; rc=%d\n",
1043 __func__, rc);
1044 rc = -EFAULT;
1045 }
1046 }
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001047 }
1048
1049 return rc;
1050} /* usf_set_rx_update */
1051
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +03001052static void usf_release_input(struct usf_type *usf)
1053{
1054 if (usf->input_if != NULL) {
1055 usf_unregister_conflicting_events(
1056 usf->conflicting_event_types);
1057 usf->conflicting_event_types = 0;
1058 input_unregister_device(usf->input_if);
1059 usf->input_if = NULL;
1060 pr_debug("%s input_unregister_device\n", __func__);
1061 }
1062} /* usf_release_input */
1063
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001064static int usf_stop_tx(struct usf_type *usf)
1065{
1066 struct usf_xx_type *usf_xx = &usf->usf_tx;
1067
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +03001068 usf_release_input(usf);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001069 usf_disable(usf_xx);
1070
1071 return 0;
1072} /* usf_stop_tx */
1073
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001074static int usf_get_version(unsigned long arg)
1075{
1076 struct us_version_info_type version_info;
1077 int rc = copy_from_user(&version_info, (void *) arg,
1078 sizeof(version_info));
1079
1080 if (rc) {
1081 pr_err("%s: copy version_info from user; rc=%d\n",
1082 __func__, rc);
1083 return -EFAULT;
1084 }
1085
1086 /* version_info.buf is pointer to place for the version string */
1087 rc = copy_to_user(version_info.pbuf,
1088 DRV_VERSION,
1089 version_info.buf_size);
1090 if (rc) {
1091 pr_err("%s: copy to version_info.pbuf; rc=%d\n",
1092 __func__, rc);
1093 rc = -EFAULT;
1094 }
1095
1096 rc = copy_to_user((void __user *)arg,
1097 &version_info,
1098 sizeof(version_info));
1099 if (rc) {
1100 pr_err("%s: copy version_info to user; rc=%d\n",
1101 __func__, rc);
1102 rc = -EFAULT;
1103 }
1104
1105 return rc;
1106} /* usf_get_version */
1107
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001108static long usf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1109{
1110 int rc = 0;
1111 struct usf_type *usf = file->private_data;
1112 struct usf_xx_type *usf_xx = NULL;
1113
1114 switch (cmd) {
1115 case US_START_TX: {
1116 usf_xx = &usf->usf_tx;
1117 if (usf_xx->usf_state == USF_CONFIGURED_STATE)
1118 rc = usf_start_tx(usf_xx);
1119 else {
1120 pr_err("%s: start_tx: wrong state[%d]\n",
1121 __func__,
1122 usf_xx->usf_state);
1123 return -EBADFD;
1124 }
1125 break;
1126 }
1127
1128 case US_START_RX: {
1129 usf_xx = &usf->usf_rx;
1130 if (usf_xx->usf_state == USF_CONFIGURED_STATE)
1131 rc = usf_start_rx(usf_xx);
1132 else {
1133 pr_err("%s: start_rx: wrong state[%d]\n",
1134 __func__,
1135 usf_xx->usf_state);
1136 return -EBADFD;
1137 }
1138 break;
1139 }
1140
1141 case US_SET_TX_INFO: {
1142 usf_xx = &usf->usf_tx;
1143 if (usf_xx->usf_state == USF_OPENED_STATE)
1144 rc = usf_set_tx_info(usf, arg);
1145 else {
1146 pr_err("%s: set_tx_info: wrong state[%d]\n",
1147 __func__,
1148 usf_xx->usf_state);
1149 return -EBADFD;
1150 }
1151
1152 break;
1153 } /* US_SET_TX_INFO */
1154
1155 case US_SET_RX_INFO: {
1156 usf_xx = &usf->usf_rx;
1157 if (usf_xx->usf_state == USF_OPENED_STATE)
1158 rc = usf_set_rx_info(usf, arg);
1159 else {
1160 pr_err("%s: set_rx_info: wrong state[%d]\n",
1161 __func__,
1162 usf_xx->usf_state);
1163 return -EBADFD;
1164 }
1165
1166 break;
1167 } /* US_SET_RX_INFO */
1168
1169 case US_GET_TX_UPDATE: {
1170 struct usf_xx_type *usf_xx = &usf->usf_tx;
1171 if (usf_xx->usf_state == USF_WORK_STATE)
1172 rc = usf_get_tx_update(usf, arg);
1173 else {
1174 pr_err("%s: get_tx_update: wrong state[%d]\n", __func__,
1175 usf_xx->usf_state);
1176 rc = -EBADFD;
1177 }
1178 break;
1179 } /* US_GET_TX_UPDATE */
1180
1181 case US_SET_RX_UPDATE: {
1182 struct usf_xx_type *usf_xx = &usf->usf_rx;
1183 if (usf_xx->usf_state == USF_WORK_STATE)
1184 rc = usf_set_rx_update(usf_xx, arg);
1185 else {
1186 pr_err("%s: set_rx_update: wrong state[%d]\n",
1187 __func__,
1188 usf_xx->usf_state);
1189 rc = -EBADFD;
1190 }
1191 break;
1192 } /* US_SET_RX_UPDATE */
1193
1194 case US_STOP_TX: {
1195 usf_xx = &usf->usf_tx;
1196 if (usf_xx->usf_state == USF_WORK_STATE)
1197 rc = usf_stop_tx(usf);
1198 else {
1199 pr_err("%s: stop_tx: wrong state[%d]\n",
1200 __func__,
1201 usf_xx->usf_state);
1202 return -EBADFD;
1203 }
1204 break;
1205 } /* US_STOP_TX */
1206
1207 case US_STOP_RX: {
1208 usf_xx = &usf->usf_rx;
1209 if (usf_xx->usf_state == USF_WORK_STATE)
1210 usf_disable(usf_xx);
1211 else {
1212 pr_err("%s: stop_rx: wrong state[%d]\n",
1213 __func__,
1214 usf_xx->usf_state);
1215 return -EBADFD;
1216 }
1217 break;
1218 } /* US_STOP_RX */
1219
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001220 case US_SET_DETECTION: {
1221 struct usf_xx_type *usf_xx = &usf->usf_tx;
1222 if (usf_xx->usf_state == USF_WORK_STATE)
1223 rc = usf_set_us_detection(usf, arg);
1224 else {
1225 pr_err("%s: set us detection: wrong state[%d]\n",
1226 __func__,
1227 usf_xx->usf_state);
1228 rc = -EBADFD;
1229 }
1230 break;
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001231 } /* US_SET_DETECTION */
1232
1233 case US_GET_VERSION: {
1234 rc = usf_get_version(arg);
1235 break;
1236 } /* US_GET_VERSION */
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001237
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001238 default:
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001239 pr_err("%s: unsupported IOCTL command [%d]\n",
1240 __func__,
1241 cmd);
1242 rc = -ENOTTY;
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001243 break;
1244 }
1245
1246 if (rc &&
1247 ((cmd == US_SET_TX_INFO) ||
1248 (cmd == US_SET_RX_INFO)))
1249 release_xx(usf_xx);
1250
1251 return rc;
1252} /* usf_ioctl */
1253
1254static int usf_mmap(struct file *file, struct vm_area_struct *vms)
1255{
1256 struct usf_type *usf = file->private_data;
1257 int dir = OUT;
1258 struct usf_xx_type *usf_xx = &usf->usf_tx;
1259
1260 if (vms->vm_flags & USF_VM_WRITE) { /* RX buf mapping */
1261 dir = IN;
1262 usf_xx = &usf->usf_rx;
1263 }
1264
1265 return q6usm_get_virtual_address(dir, usf_xx->usc, vms);
1266}
1267
1268static uint16_t add_opened_dev(int minor)
1269{
1270 uint16_t ind = 0;
1271
1272 for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
1273 if (minor == s_opened_devs[ind]) {
1274 pr_err("%s: device %d is already opened\n",
1275 __func__, minor);
1276 return USF_UNDEF_DEV_ID;
1277 }
1278
1279 if (s_opened_devs[ind] == 0) {
1280 s_opened_devs[ind] = minor;
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001281 pr_debug("%s: device %d is added; ind=%d\n",
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001282 __func__, minor, ind);
1283 return ind;
1284 }
1285 }
1286
1287 pr_err("%s: there is no place for device %d\n",
1288 __func__, minor);
1289 return USF_UNDEF_DEV_ID;
1290}
1291
1292static int usf_open(struct inode *inode, struct file *file)
1293{
1294 struct usf_type *usf = NULL;
1295 uint16_t dev_ind = 0;
1296 int minor = MINOR(inode->i_rdev);
1297
1298 dev_ind = add_opened_dev(minor);
1299 if (dev_ind == USF_UNDEF_DEV_ID)
1300 return -EBUSY;
1301
1302 usf = kzalloc(sizeof(struct usf_type), GFP_KERNEL);
1303 if (usf == NULL) {
1304 pr_err("%s:usf allocation failed\n", __func__);
1305 return -ENOMEM;
1306 }
1307
1308 file->private_data = usf;
1309 usf->dev_ind = dev_ind;
1310
1311 usf->usf_tx.usf_state = USF_OPENED_STATE;
1312 usf->usf_rx.usf_state = USF_OPENED_STATE;
1313
Baruch Eruchimovitch24dda6a2012-01-02 20:28:19 +02001314 usf->usf_tx.us_detect_type = USF_US_DETECT_UNDEF;
1315 usf->usf_rx.us_detect_type = USF_US_DETECT_UNDEF;
1316
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001317 pr_debug("%s:usf in open\n", __func__);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001318 return 0;
1319}
1320
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001321static int usf_release(struct inode *inode, struct file *file)
1322{
1323 struct usf_type *usf = file->private_data;
1324
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001325 pr_debug("%s: release entry\n", __func__);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001326
Baruch Eruchimovitch1221b852012-04-02 11:21:30 +03001327 usf_release_input(usf);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001328
1329 usf_disable(&usf->usf_tx);
1330 usf_disable(&usf->usf_rx);
1331
1332 s_opened_devs[usf->dev_ind] = 0;
1333
1334 kfree(usf);
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001335 pr_debug("%s: release exit\n", __func__);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001336 return 0;
1337}
1338
1339static const struct file_operations usf_fops = {
1340 .owner = THIS_MODULE,
1341 .open = usf_open,
1342 .release = usf_release,
1343 .unlocked_ioctl = usf_ioctl,
1344 .mmap = usf_mmap,
1345};
1346
1347struct miscdevice usf_misc[MAX_DEVS_NUMBER] = {
1348 {
1349 .minor = MISC_DYNAMIC_MINOR,
1350 .name = "usf1",
1351 .fops = &usf_fops,
1352 },
1353};
1354
1355static int __init usf_init(void)
1356{
1357 int rc = 0;
1358 uint16_t ind = 0;
1359
Baruch Eruchimovitchdac24742012-02-01 15:29:29 +02001360 pr_debug("%s: USF SW version %s.\n", __func__, DRV_VERSION);
1361 pr_debug("%s: Max %d devs registration\n", __func__, MAX_DEVS_NUMBER);
Baruch Eruchimovitche9cbfc12011-10-09 19:47:08 +02001362
1363 for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
1364 rc = misc_register(&usf_misc[ind]);
1365 if (rc) {
1366 pr_err("%s: misc_register() failed ind=%d; rc = %d\n",
1367 __func__, ind, rc);
1368 break;
1369 }
1370 }
1371
1372 return rc;
1373}
1374
1375device_initcall(usf_init);
1376
1377MODULE_DESCRIPTION("Ultrasound framework driver");
1378MODULE_VERSION(DRV_VERSION);