blob: afb40be494df410e835fc1fd6435867ea90b753f [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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#define DRIVER_AUTHOR "Archana Ramchandran <archanar@codeaurora.org>"
14#define DRIVER_NAME "radio-iris"
15#define DRIVER_CARD "Qualcomm FM Radio Transceiver"
16#define DRIVER_DESC "Driver for Qualcomm FM Radio Transceiver "
17
18#include <linux/version.h>
19#include <linux/init.h>
20#include <linux/delay.h>
21#include <linux/uaccess.h>
22#include <linux/kfifo.h>
23#include <linux/param.h>
24#include <linux/interrupt.h>
25#include <linux/kernel.h>
26#include <linux/module.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070027#include <linux/sched.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include <linux/version.h>
29#include <linux/videodev2.h>
30#include <linux/mutex.h>
31#include <linux/unistd.h>
32#include <linux/atomic.h>
33#include <linux/platform_device.h>
34#include <linux/workqueue.h>
35#include <linux/slab.h>
36#include <media/v4l2-common.h>
37#include <media/v4l2-ioctl.h>
38#include <media/radio-iris.h>
39#include <asm/unaligned.h>
40
41static unsigned int rds_buf = 100;
Ayaz Ahmad89265112012-10-05 19:39:11 +053042static int oda_agt;
43static int grp_mask;
44static int rt_plus_carrier = -1;
45static int ert_carrier = -1;
46static unsigned char ert_buf[256];
47static unsigned char ert_len;
48static unsigned char c_byt_pair_index;
49static char utf_8_flag;
50static char rt_ert_flag;
51static char formatting_dir;
52
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053module_param(rds_buf, uint, 0);
54MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
55
56static void radio_hci_cmd_task(unsigned long arg);
57static void radio_hci_rx_task(unsigned long arg);
58static struct video_device *video_get_dev(void);
59static DEFINE_RWLOCK(hci_task_lock);
60
61struct iris_device {
62 struct device *dev;
63 struct kfifo data_buf[IRIS_BUF_MAX];
64
65 int pending_xfrs[IRIS_XFR_MAX];
66 int xfr_bytes_left;
67 int xfr_in_progress;
68 struct completion sync_xfr_start;
69 int tune_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -070070 unsigned int mode;
71
72 __u16 pi;
73 __u8 pty;
74 __u8 ps_repeatcount;
Ankur Nandwani8f972e52011-08-24 11:48:32 -070075 __u8 prev_trans_rds;
Srinivasa Rao Uppala1da1a242012-01-11 11:00:10 +053076 __u8 af_jump_bit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070077 struct video_device *videodev;
78
79 struct mutex lock;
80 spinlock_t buf_lock[IRIS_BUF_MAX];
81 wait_queue_head_t event_queue;
82 wait_queue_head_t read_queue;
83
84 struct radio_hci_dev *fm_hdev;
85
86 struct v4l2_capability *g_cap;
87 struct v4l2_control *g_ctl;
88
89 struct hci_fm_mute_mode_req mute_mode;
90 struct hci_fm_stereo_mode_req stereo_mode;
91 struct hci_fm_station_rsp fm_st_rsp;
92 struct hci_fm_search_station_req srch_st;
93 struct hci_fm_search_rds_station_req srch_rds;
94 struct hci_fm_search_station_list_req srch_st_list;
95 struct hci_fm_recv_conf_req recv_conf;
Ankur Nandwanid928d542011-08-11 13:15:41 -070096 struct hci_fm_trans_conf_req_struct trans_conf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097 struct hci_fm_rds_grp_req rds_grp;
98 unsigned char g_search_mode;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +053099 unsigned char power_mode;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +0530100 int search_on;
Ankur Nandwanid928d542011-08-11 13:15:41 -0700101 unsigned int tone_freq;
Anantha Krishnanf950e322012-06-06 14:25:49 +0530102 unsigned char spur_table_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103 unsigned char g_scan_time;
104 unsigned int g_antenna;
105 unsigned int g_rds_grp_proc_ps;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +0530106 unsigned char event_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107 enum iris_region_t region;
108 struct hci_fm_dbg_param_rsp st_dbg_param;
109 struct hci_ev_srch_list_compl srch_st_result;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700110 struct hci_fm_riva_poke riva_data_req;
111 struct hci_fm_ssbi_req ssbi_data_accs;
112 struct hci_fm_ssbi_peek ssbi_peek_reg;
Venkateshwarlu Domakonda3d1d6e42011-12-09 15:08:58 +0530113 struct hci_fm_sig_threshold_rsp sig_th;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +0530114 struct hci_fm_ch_det_threshold ch_det_threshold;
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +0530115 struct hci_fm_data_rd_rsp default_data;
Anantha Krishnanf950e322012-06-06 14:25:49 +0530116 struct hci_fm_spur_data spur_data;
Ayaz Ahmad37294ba2012-07-10 16:38:11 +0530117 unsigned char is_station_valid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700118};
119
120static struct video_device *priv_videodev;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530121static int iris_do_calibration(struct iris_device *radio);
Ayaz Ahmad89265112012-10-05 19:39:11 +0530122static void hci_buff_ert(struct iris_device *radio,
123 struct rds_grp_data *rds_buf);
124static void hci_ev_rt_plus(struct iris_device *radio,
125 struct rds_grp_data rds_buf);
126static void hci_ev_ert(struct iris_device *radio);
Anantha Krishnanf950e322012-06-06 14:25:49 +0530127static int update_spur_table(struct iris_device *radio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
129 {
130 .id = V4L2_CID_AUDIO_VOLUME,
131 .type = V4L2_CTRL_TYPE_INTEGER,
132 .name = "Volume",
133 .minimum = 0,
134 .maximum = 15,
135 .step = 1,
136 .default_value = 15,
137 },
138 {
139 .id = V4L2_CID_AUDIO_BALANCE,
140 .flags = V4L2_CTRL_FLAG_DISABLED,
141 },
142 {
143 .id = V4L2_CID_AUDIO_BASS,
144 .flags = V4L2_CTRL_FLAG_DISABLED,
145 },
146 {
147 .id = V4L2_CID_AUDIO_TREBLE,
148 .flags = V4L2_CTRL_FLAG_DISABLED,
149 },
150 {
151 .id = V4L2_CID_AUDIO_MUTE,
152 .type = V4L2_CTRL_TYPE_BOOLEAN,
153 .name = "Mute",
154 .minimum = 0,
155 .maximum = 1,
156 .step = 1,
157 .default_value = 1,
158 },
159 {
160 .id = V4L2_CID_AUDIO_LOUDNESS,
161 .flags = V4L2_CTRL_FLAG_DISABLED,
162 },
163 {
164 .id = V4L2_CID_PRIVATE_IRIS_SRCHMODE,
165 .type = V4L2_CTRL_TYPE_INTEGER,
166 .name = "Search mode",
167 .minimum = 0,
168 .maximum = 7,
169 .step = 1,
170 .default_value = 0,
171 },
172 {
173 .id = V4L2_CID_PRIVATE_IRIS_SCANDWELL,
174 .type = V4L2_CTRL_TYPE_INTEGER,
175 .name = "Search dwell time",
176 .minimum = 0,
177 .maximum = 7,
178 .step = 1,
179 .default_value = 0,
180 },
181 {
182 .id = V4L2_CID_PRIVATE_IRIS_SRCHON,
183 .type = V4L2_CTRL_TYPE_BOOLEAN,
184 .name = "Search on/off",
185 .minimum = 0,
186 .maximum = 1,
187 .step = 1,
188 .default_value = 1,
189
190 },
191 {
192 .id = V4L2_CID_PRIVATE_IRIS_STATE,
193 .type = V4L2_CTRL_TYPE_INTEGER,
194 .name = "radio 0ff/rx/tx/reset",
195 .minimum = 0,
196 .maximum = 3,
197 .step = 1,
198 .default_value = 1,
199
200 },
201 {
202 .id = V4L2_CID_PRIVATE_IRIS_REGION,
203 .type = V4L2_CTRL_TYPE_INTEGER,
204 .name = "radio standard",
205 .minimum = 0,
206 .maximum = 2,
207 .step = 1,
208 .default_value = 0,
209 },
210 {
211 .id = V4L2_CID_PRIVATE_IRIS_SIGNAL_TH,
212 .type = V4L2_CTRL_TYPE_INTEGER,
213 .name = "Signal Threshold",
214 .minimum = 0x80,
215 .maximum = 0x7F,
216 .step = 1,
217 .default_value = 0,
218 },
219 {
220 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PTY,
221 .type = V4L2_CTRL_TYPE_INTEGER,
222 .name = "Search PTY",
223 .minimum = 0,
224 .maximum = 31,
225 .default_value = 0,
226 },
227 {
228 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PI,
229 .type = V4L2_CTRL_TYPE_INTEGER,
230 .name = "Search PI",
231 .minimum = 0,
232 .maximum = 0xFF,
233 .default_value = 0,
234 },
235 {
236 .id = V4L2_CID_PRIVATE_IRIS_SRCH_CNT,
237 .type = V4L2_CTRL_TYPE_INTEGER,
238 .name = "Preset num",
239 .minimum = 0,
240 .maximum = 12,
241 .default_value = 0,
242 },
243 {
244 .id = V4L2_CID_PRIVATE_IRIS_EMPHASIS,
245 .type = V4L2_CTRL_TYPE_BOOLEAN,
246 .name = "Emphasis",
247 .minimum = 0,
248 .maximum = 1,
249 .default_value = 0,
250 },
251 {
252 .id = V4L2_CID_PRIVATE_IRIS_RDS_STD,
253 .type = V4L2_CTRL_TYPE_BOOLEAN,
254 .name = "RDS standard",
255 .minimum = 0,
256 .maximum = 1,
257 .default_value = 0,
258 },
259 {
260 .id = V4L2_CID_PRIVATE_IRIS_SPACING,
261 .type = V4L2_CTRL_TYPE_INTEGER,
262 .name = "Channel spacing",
263 .minimum = 0,
264 .maximum = 2,
265 .default_value = 0,
266 },
267 {
268 .id = V4L2_CID_PRIVATE_IRIS_RDSON,
269 .type = V4L2_CTRL_TYPE_BOOLEAN,
270 .name = "RDS on/off",
271 .minimum = 0,
272 .maximum = 1,
273 .default_value = 0,
274 },
275 {
276 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK,
277 .type = V4L2_CTRL_TYPE_INTEGER,
278 .name = "RDS group mask",
279 .minimum = 0,
280 .maximum = 0xFFFFFFFF,
281 .default_value = 0,
282 },
283 {
284 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC,
285 .type = V4L2_CTRL_TYPE_INTEGER,
286 .name = "RDS processing",
287 .minimum = 0,
288 .maximum = 0xFF,
289 .default_value = 0,
290 },
291 {
292 .id = V4L2_CID_PRIVATE_IRIS_RDSD_BUF,
293 .type = V4L2_CTRL_TYPE_INTEGER,
294 .name = "RDS data groups to buffer",
295 .minimum = 1,
296 .maximum = 21,
297 .default_value = 0,
298 },
299 {
300 .id = V4L2_CID_PRIVATE_IRIS_PSALL,
301 .type = V4L2_CTRL_TYPE_BOOLEAN,
302 .name = "pass all ps strings",
303 .minimum = 0,
304 .maximum = 1,
305 .default_value = 0,
306 },
307 {
308 .id = V4L2_CID_PRIVATE_IRIS_LP_MODE,
309 .type = V4L2_CTRL_TYPE_BOOLEAN,
310 .name = "Low power mode",
311 .minimum = 0,
312 .maximum = 1,
313 .default_value = 0,
314 },
315 {
316 .id = V4L2_CID_PRIVATE_IRIS_ANTENNA,
317 .type = V4L2_CTRL_TYPE_BOOLEAN,
318 .name = "headset/internal",
319 .minimum = 0,
320 .maximum = 1,
321 .default_value = 0,
322 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 {
324 .id = V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT,
325 .type = V4L2_CTRL_TYPE_INTEGER,
326 .name = "Set PS REPEATCOUNT",
327 .minimum = 0,
328 .maximum = 15,
329 },
330 {
331 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME,
332 .type = V4L2_CTRL_TYPE_BOOLEAN,
333 .name = "Stop PS NAME",
334 .minimum = 0,
335 .maximum = 1,
336 },
337 {
338 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT,
339 .type = V4L2_CTRL_TYPE_BOOLEAN,
340 .name = "Stop RT",
341 .minimum = 0,
342 .maximum = 1,
343 },
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700344 {
345 .id = V4L2_CID_PRIVATE_IRIS_SOFT_MUTE,
346 .type = V4L2_CTRL_TYPE_BOOLEAN,
347 .name = "Soft Mute",
348 .minimum = 0,
349 .maximum = 1,
350 },
351 {
352 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR,
353 .type = V4L2_CTRL_TYPE_BOOLEAN,
354 .name = "Riva addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530355 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700356 .maximum = 0x31E0004,
357 },
358 {
359 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN,
360 .type = V4L2_CTRL_TYPE_INTEGER,
361 .name = "Data len",
362 .minimum = 0,
363 .maximum = 0xFF,
364 },
365 {
366 .id = V4L2_CID_PRIVATE_IRIS_RIVA_PEEK,
367 .type = V4L2_CTRL_TYPE_BOOLEAN,
368 .name = "Riva peek",
369 .minimum = 0,
370 .maximum = 1,
371 },
372 {
373 .id = V4L2_CID_PRIVATE_IRIS_RIVA_POKE,
374 .type = V4L2_CTRL_TYPE_INTEGER,
375 .name = "Riva poke",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530376 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700377 .maximum = 0x31E0004,
378 },
379 {
380 .id = V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR,
381 .type = V4L2_CTRL_TYPE_INTEGER,
382 .name = "Ssbi addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530383 .minimum = 0x280,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700384 .maximum = 0x37F,
385 },
386 {
387 .id = V4L2_CID_PRIVATE_IRIS_SSBI_PEEK,
388 .type = V4L2_CTRL_TYPE_INTEGER,
389 .name = "Ssbi peek",
390 .minimum = 0,
391 .maximum = 0x37F,
392 },
393 {
394 .id = V4L2_CID_PRIVATE_IRIS_SSBI_POKE,
395 .type = V4L2_CTRL_TYPE_INTEGER,
396 .name = "ssbi poke",
397 .minimum = 0x01,
398 .maximum = 0xFF,
399 },
400 {
401 .id = V4L2_CID_PRIVATE_IRIS_HLSI,
402 .type = V4L2_CTRL_TYPE_INTEGER,
403 .name = "set hlsi",
404 .minimum = 0,
405 .maximum = 2,
406 },
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530407 {
408 .id = V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS,
409 .type = V4L2_CTRL_TYPE_BOOLEAN,
410 .name = "RDS grp",
411 .minimum = 0,
412 .maximum = 1,
413 },
414 {
415 .id = V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER,
416 .type = V4L2_CTRL_TYPE_INTEGER,
417 .name = "Notch filter",
418 .minimum = 0,
419 .maximum = 2,
420 },
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530421 {
422 .id = V4L2_CID_PRIVATE_IRIS_READ_DEFAULT,
423 .type = V4L2_CTRL_TYPE_INTEGER,
424 .name = "Read default",
425 },
426 {
427 .id = V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT,
428 .type = V4L2_CTRL_TYPE_INTEGER,
429 .name = "Write default",
430 },
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530431 {
432 .id = V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION,
433 .type = V4L2_CTRL_TYPE_BOOLEAN,
434 .name = "SET Calibration",
435 .minimum = 0,
436 .maximum = 1,
437 },
438 {
439 .id = V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION,
440 .type = V4L2_CTRL_TYPE_BOOLEAN,
441 .name = "SET Calibration",
442 .minimum = 0,
443 .maximum = 1,
444 },
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +0530445 {
446 .id = V4L2_CID_PRIVATE_IRIS_GET_SINR,
447 .type = V4L2_CTRL_TYPE_INTEGER,
448 .name = "GET SINR",
449 .minimum = -128,
450 .maximum = 127,
451 },
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +0530452 {
453 .id = V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD,
454 .type = V4L2_CTRL_TYPE_INTEGER,
455 .name = "Intf High Threshold",
456 .minimum = 0,
457 .maximum = 0xFF,
458 .default_value = 0,
459 },
460 {
461 .id = V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD,
462 .type = V4L2_CTRL_TYPE_INTEGER,
463 .name = "Intf low Threshold",
464 .minimum = 0,
465 .maximum = 0xFF,
466 .default_value = 0,
467 },
468 {
469 .id = V4L2_CID_PRIVATE_SINR_THRESHOLD,
470 .type = V4L2_CTRL_TYPE_INTEGER,
471 .name = "SINR Threshold",
472 .minimum = -128,
473 .maximum = 127,
474 .default_value = 0,
475 },
476 {
477 .id = V4L2_CID_PRIVATE_SINR_SAMPLES,
478 .type = V4L2_CTRL_TYPE_INTEGER,
479 .name = "SINR samples",
480 .minimum = 1,
481 .maximum = 0xFF,
482 .default_value = 0,
483 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484};
485
486static void iris_q_event(struct iris_device *radio,
487 enum iris_evt_t event)
488{
489 struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
490 unsigned char evt = event;
491 if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
492 wake_up_interruptible(&radio->event_queue);
493}
494
495static int hci_send_frame(struct sk_buff *skb)
496{
497 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
498
499 if (!hdev) {
500 kfree_skb(skb);
501 return -ENODEV;
502 }
503
504 __net_timestamp(skb);
505
506 skb_orphan(skb);
507 return hdev->send(skb);
508}
509
510static void radio_hci_cmd_task(unsigned long arg)
511{
512 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
513 struct sk_buff *skb;
514 if (!(atomic_read(&hdev->cmd_cnt))
515 && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
516 FMDERR("%s command tx timeout", hdev->name);
517 atomic_set(&hdev->cmd_cnt, 1);
518 }
519
520 skb = skb_dequeue(&hdev->cmd_q);
521 if (atomic_read(&hdev->cmd_cnt) && skb) {
522 kfree_skb(hdev->sent_cmd);
523 hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
524 if (hdev->sent_cmd) {
525 atomic_dec(&hdev->cmd_cnt);
526 hci_send_frame(skb);
527 hdev->cmd_last_tx = jiffies;
528 } else {
529 skb_queue_head(&hdev->cmd_q, skb);
530 tasklet_schedule(&hdev->cmd_task);
531 }
532 }
533
534}
535
536static void radio_hci_rx_task(unsigned long arg)
537{
538 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
539 struct sk_buff *skb;
540
541 read_lock(&hci_task_lock);
542
543 skb = skb_dequeue(&hdev->rx_q);
544 radio_hci_event_packet(hdev, skb);
545
546 read_unlock(&hci_task_lock);
547}
548
549int radio_hci_register_dev(struct radio_hci_dev *hdev)
550{
551 struct iris_device *radio = video_get_drvdata(video_get_dev());
552 if (!radio) {
553 FMDERR(":radio is null");
554 return -EINVAL;
555 }
556
557 if (!hdev) {
558 FMDERR("hdev is null");
559 return -EINVAL;
560 }
561
562 hdev->flags = 0;
563
564 tasklet_init(&hdev->cmd_task, radio_hci_cmd_task, (unsigned long)
565 hdev);
566 tasklet_init(&hdev->rx_task, radio_hci_rx_task, (unsigned long)
567 hdev);
568
569 init_waitqueue_head(&hdev->req_wait_q);
570
571 skb_queue_head_init(&hdev->rx_q);
572 skb_queue_head_init(&hdev->cmd_q);
573 skb_queue_head_init(&hdev->raw_q);
574
575 if (!radio)
576 FMDERR(":radio is null");
577
578 radio->fm_hdev = hdev;
579
580 return 0;
581}
582EXPORT_SYMBOL(radio_hci_register_dev);
583
584int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
585{
586 struct iris_device *radio = video_get_drvdata(video_get_dev());
587 if (!radio) {
588 FMDERR(":radio is null");
589 return -EINVAL;
590 }
591
592 tasklet_kill(&hdev->rx_task);
593 tasklet_kill(&hdev->cmd_task);
594 skb_queue_purge(&hdev->rx_q);
595 skb_queue_purge(&hdev->cmd_q);
596 skb_queue_purge(&hdev->raw_q);
597 kfree(radio->fm_hdev);
598 kfree(radio->videodev);
599
600 return 0;
601}
602EXPORT_SYMBOL(radio_hci_unregister_dev);
603
604int radio_hci_recv_frame(struct sk_buff *skb)
605{
606 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
607 if (!hdev) {
608 FMDERR("%s hdev is null while receiving frame", hdev->name);
609 kfree_skb(skb);
610 return -ENXIO;
611 }
612
613 __net_timestamp(skb);
614
615 radio_hci_event_packet(hdev, skb);
Srinivasa Rao Uppalacf3a8112011-09-22 21:02:02 +0530616 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 return 0;
618}
619EXPORT_SYMBOL(radio_hci_recv_frame);
620
621int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
622 void *param)
623{
624 int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
625 struct radio_hci_command_hdr *hdr;
626 struct sk_buff *skb;
627 int ret = 0;
628
629 skb = alloc_skb(len, GFP_ATOMIC);
630 if (!skb) {
631 FMDERR("%s no memory for command", hdev->name);
632 return -ENOMEM;
633 }
634
635 hdr = (struct radio_hci_command_hdr *) skb_put(skb,
636 RADIO_HCI_COMMAND_HDR_SIZE);
637 hdr->opcode = cpu_to_le16(opcode);
638 hdr->plen = plen;
639
640 if (plen)
641 memcpy(skb_put(skb, plen), param, plen);
642
643 skb->dev = (void *) hdev;
644
645 ret = hci_send_frame(skb);
646
647 return ret;
648}
649EXPORT_SYMBOL(radio_hci_send_cmd);
650
651static int hci_fm_enable_recv_req(struct radio_hci_dev *hdev,
652 unsigned long param)
653{
654 __u16 opcode = 0;
655
656 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
657 HCI_OCF_FM_ENABLE_RECV_REQ);
658 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
659}
660
Ankur Nandwanid928d542011-08-11 13:15:41 -0700661static int hci_fm_tone_generator(struct radio_hci_dev *hdev,
662 unsigned long param)
663{
664 struct iris_device *radio = video_get_drvdata(video_get_dev());
665 __u16 opcode = 0;
666
667 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
668 HCI_FM_SET_INTERNAL_TONE_GENRATOR);
669 return radio_hci_send_cmd(hdev, opcode,
670 sizeof(radio->tone_freq), &radio->tone_freq);
671}
672
673static int hci_fm_enable_trans_req(struct radio_hci_dev *hdev,
674 unsigned long param)
675{
676 __u16 opcode = 0;
677
678 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
679 HCI_OCF_FM_ENABLE_TRANS_REQ);
680 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
681}
682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683static int hci_fm_disable_recv_req(struct radio_hci_dev *hdev,
684 unsigned long param)
685{
686 __u16 opcode = 0;
687
688 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
689 HCI_OCF_FM_DISABLE_RECV_REQ);
690 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
691}
692
Ankur Nandwanid928d542011-08-11 13:15:41 -0700693static int hci_fm_disable_trans_req(struct radio_hci_dev *hdev,
694 unsigned long param)
695{
696 __u16 opcode = 0;
697
698 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
699 HCI_OCF_FM_DISABLE_TRANS_REQ);
700 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
701}
702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700703static int hci_get_fm_recv_conf_req(struct radio_hci_dev *hdev,
704 unsigned long param)
705{
706 __u16 opcode = 0;
707
708 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
709 HCI_OCF_FM_GET_RECV_CONF_REQ);
710 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
711}
712
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +0530713static int hci_get_fm_trans_conf_req(struct radio_hci_dev *hdev,
714 unsigned long param)
715{
716 u16 opcode = 0;
717
718 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
719 HCI_OCF_FM_GET_TRANS_CONF_REQ);
720 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
721}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
723 unsigned long param)
724{
725 __u16 opcode = 0;
726
727 struct hci_fm_recv_conf_req *recv_conf_req =
728 (struct hci_fm_recv_conf_req *) param;
729
730 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
731 HCI_OCF_FM_SET_RECV_CONF_REQ);
732 return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
733 recv_conf_req);
734}
735
Ankur Nandwanid928d542011-08-11 13:15:41 -0700736static int hci_set_fm_trans_conf_req(struct radio_hci_dev *hdev,
737 unsigned long param)
738{
739 __u16 opcode = 0;
740
741 struct hci_fm_trans_conf_req_struct *trans_conf_req =
742 (struct hci_fm_trans_conf_req_struct *) param;
743
744 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
745 HCI_OCF_FM_SET_TRANS_CONF_REQ);
746 return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
747 trans_conf_req);
748}
749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
751 unsigned long param)
752{
753 __u16 opcode = 0;
754
755 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
756 HCI_OCF_FM_GET_STATION_PARAM_REQ);
757 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
758}
759
760static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
761 unsigned long param)
762{
763 __u16 opcode = 0;
764 struct hci_fm_mute_mode_req *mute_mode_req =
765 (struct hci_fm_mute_mode_req *) param;
766
767 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
768 HCI_OCF_FM_SET_MUTE_MODE_REQ);
769 return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
770 mute_mode_req);
771}
772
Ankur Nandwanid928d542011-08-11 13:15:41 -0700773
774static int hci_trans_ps_req(struct radio_hci_dev *hdev,
775 unsigned long param)
776{
777 __u16 opcode = 0;
778 struct hci_fm_tx_ps *tx_ps_req =
779 (struct hci_fm_tx_ps *) param;
780
781 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
782 HCI_OCF_FM_RDS_PS_REQ);
783
784 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_ps_req)),
785 tx_ps_req);
786}
787
788static int hci_trans_rt_req(struct radio_hci_dev *hdev,
789 unsigned long param)
790{
791 __u16 opcode = 0;
792 struct hci_fm_tx_rt *tx_rt_req =
793 (struct hci_fm_tx_rt *) param;
794
795 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
796 HCI_OCF_FM_RDS_RT_REQ);
797
798 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_rt_req)),
799 tx_rt_req);
800}
801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
803 unsigned long param)
804{
805 __u16 opcode = 0;
806 struct hci_fm_stereo_mode_req *stereo_mode_req =
807 (struct hci_fm_stereo_mode_req *) param;
808 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
809 HCI_OCF_FM_SET_STEREO_MODE_REQ);
810 return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
811 stereo_mode_req);
812}
813
814static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
815 unsigned long param)
816{
817 __u16 opcode = 0;
818
819 __u8 antenna = param;
820
821 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
822 HCI_OCF_FM_SET_ANTENNA);
823 return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
824}
825
826static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
827 unsigned long param)
828{
829 __u16 opcode = 0;
830
831 __u8 sig_threshold = param;
832
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530833 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834 HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
835 return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
836 &sig_threshold);
837}
838
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +0530839static int hci_fm_set_event_mask(struct radio_hci_dev *hdev,
840 unsigned long param)
841{
842 u16 opcode = 0;
843 u8 event_mask = param;
844
845 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
846 HCI_OCF_FM_SET_EVENT_MASK);
847 return radio_hci_send_cmd(hdev, opcode, sizeof(event_mask),
848 &event_mask);
849}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
851 unsigned long param)
852{
853 __u16 opcode = 0;
854
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530855 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856 HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
857 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
858}
859
860static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
861 unsigned long param)
862{
863 __u16 opcode = 0;
864
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530865 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700866 HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
867 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
868}
869
870static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
871 unsigned long param)
872{
873 __u16 opcode = 0;
874
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530875 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700876 HCI_OCF_FM_GET_RADIO_TEXT_REQ);
877 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
878}
879
880static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
881 unsigned long param)
882{
883 __u16 opcode = 0;
884
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530885 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 HCI_OCF_FM_GET_AF_LIST_REQ);
887 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
888}
889
890static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
891 unsigned long param)
892{
893 __u16 opcode = 0;
894 struct hci_fm_search_station_req *srch_stations =
895 (struct hci_fm_search_station_req *) param;
896
897 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
898 HCI_OCF_FM_SEARCH_STATIONS);
899 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
900 srch_stations);
901}
902
903static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
904 unsigned long param)
905{
906 __u16 opcode = 0;
907 struct hci_fm_search_rds_station_req *srch_stations =
908 (struct hci_fm_search_rds_station_req *) param;
909
910 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
911 HCI_OCF_FM_SEARCH_RDS_STATIONS);
912 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
913 srch_stations);
914}
915
916static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
917 unsigned long param)
918{
919 __u16 opcode = 0;
920 struct hci_fm_search_station_list_req *srch_list =
921 (struct hci_fm_search_station_list_req *) param;
922
923 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
924 HCI_OCF_FM_SEARCH_STATIONS_LIST);
925 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
926 srch_list);
927}
928
929static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
930 unsigned long param)
931{
932 __u16 opcode = 0;
933
934 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
935 HCI_OCF_FM_CANCEL_SEARCH);
936 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
937}
938
Ayaz Ahmad89265112012-10-05 19:39:11 +0530939static int hci_fm_rds_grp_mask_req(struct radio_hci_dev *hdev,
940 unsigned long param)
941{
942 __u16 opcode = 0;
943
944 struct hci_fm_rds_grp_req *fm_grp_mask =
945 (struct hci_fm_rds_grp_req *)param;
946
947 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
948 HCI_OCF_FM_RDS_GRP);
949 return radio_hci_send_cmd(hdev, opcode, sizeof(*fm_grp_mask),
950 fm_grp_mask);
951}
952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700953static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
954 unsigned long param)
955{
956 __u16 opcode = 0;
957
958 __u32 fm_grps_process = param;
959
960 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
961 HCI_OCF_FM_RDS_GRP_PROCESS);
962 return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
963 &fm_grps_process);
964}
965
966static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
967 unsigned long param)
968{
969 __u16 opcode = 0;
970
971 __u32 tune_freq = param;
972
973 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
974 HCI_OCF_FM_TUNE_STATION_REQ);
975 return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
976}
977
978static int hci_def_data_read_req(struct radio_hci_dev *hdev,
979 unsigned long param)
980{
981 __u16 opcode = 0;
982 struct hci_fm_def_data_rd_req *def_data_rd =
983 (struct hci_fm_def_data_rd_req *) param;
984
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530985 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 HCI_OCF_FM_DEFAULT_DATA_READ);
987 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
988 def_data_rd);
989}
990
991static int hci_def_data_write_req(struct radio_hci_dev *hdev,
992 unsigned long param)
993{
994 __u16 opcode = 0;
995 struct hci_fm_def_data_wr_req *def_data_wr =
996 (struct hci_fm_def_data_wr_req *) param;
997
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530998 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 HCI_OCF_FM_DEFAULT_DATA_WRITE);
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05301000
1001 return radio_hci_send_cmd(hdev, opcode, (def_data_wr->length+2),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001002 def_data_wr);
1003}
1004
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301005static int hci_set_notch_filter_req(struct radio_hci_dev *hdev,
1006 unsigned long param)
1007{
1008 __u16 opcode = 0;
1009 __u8 notch_filter_val = param;
1010
1011 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
1012 HCI_OCF_FM_EN_NOTCH_CTRL);
1013 return radio_hci_send_cmd(hdev, opcode, sizeof(notch_filter_val),
1014 &notch_filter_val);
1015}
1016
1017
1018
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
1020{
1021 __u16 opcode = 0;
1022
1023 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1024 HCI_OCF_FM_RESET);
1025 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1026}
1027
1028static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
1029 unsigned long param)
1030{
1031 __u16 opcode = 0;
1032
1033 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1034 HCI_OCF_FM_GET_FEATURE_LIST);
1035 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1036}
1037
1038static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
1039 unsigned long param)
1040{
1041 __u16 opcode = 0;
1042
1043 __u8 mode = param;
1044
1045 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1046 HCI_OCF_FM_DO_CALIBRATION);
1047 return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
1048}
1049
1050static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
1051 unsigned long param)
1052{
1053 __u16 opcode = 0;
1054
1055 __u8 reset_counters = param;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301056 opcode = hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057 HCI_OCF_FM_READ_GRP_COUNTERS);
1058 return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
1059 &reset_counters);
1060}
1061
1062static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
1063{
1064 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001065 struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001067 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001068 HCI_OCF_FM_PEEK_DATA);
1069 return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
1070 peek_data);
1071}
1072
1073static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
1074{
1075 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001076 struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001077
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07001078 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 HCI_OCF_FM_POKE_DATA);
1080 return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
1081 poke_data);
1082}
1083
1084static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
1085 unsigned long param)
1086{
1087 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001088 struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001090 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 HCI_OCF_FM_SSBI_PEEK_REG);
1092 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
1093 ssbi_peek);
1094}
1095
1096static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
1097 unsigned long param)
1098{
1099 __u16 opcode = 0;
1100 struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
1101
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001102 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 HCI_OCF_FM_SSBI_POKE_REG);
1104 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
1105 ssbi_poke);
1106}
1107
1108static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
1109 unsigned long param)
1110{
1111 __u16 opcode = 0;
1112
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +05301113 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 HCI_OCF_FM_STATION_DBG_PARAM);
1115 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1116}
1117
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301118static int hci_fm_set_ch_det_th(struct radio_hci_dev *hdev,
1119 unsigned long param)
1120{
1121 struct hci_fm_ch_det_threshold *ch_det_th =
1122 (struct hci_fm_ch_det_threshold *) param;
1123 u16 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
1124 HCI_OCF_FM_SET_CH_DET_THRESHOLD);
1125 return radio_hci_send_cmd(hdev, opcode, sizeof((*ch_det_th)),
1126 ch_det_th);
1127}
1128
1129static int hci_fm_get_ch_det_th(struct radio_hci_dev *hdev,
1130 unsigned long param)
1131{
1132 u16 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
1133 HCI_OCF_FM_GET_CH_DET_THRESHOLD);
1134 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1135}
1136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137static int radio_hci_err(__u16 code)
1138{
1139 switch (code) {
1140 case 0:
1141 return 0;
1142 case 0x01:
1143 return -EBADRQC;
1144 case 0x02:
1145 return -ENOTCONN;
1146 case 0x03:
1147 return -EIO;
1148 case 0x07:
1149 return -ENOMEM;
1150 case 0x0c:
1151 return -EBUSY;
1152 case 0x11:
1153 return -EOPNOTSUPP;
1154 case 0x12:
1155 return -EINVAL;
1156 default:
1157 return -ENOSYS;
1158 }
1159}
1160
1161static int __radio_hci_request(struct radio_hci_dev *hdev,
1162 int (*req)(struct radio_hci_dev *hdev,
1163 unsigned long param),
1164 unsigned long param, __u32 timeout)
1165{
1166 int err = 0;
1167
1168 DECLARE_WAITQUEUE(wait, current);
1169
1170 hdev->req_status = HCI_REQ_PEND;
1171
1172 add_wait_queue(&hdev->req_wait_q, &wait);
1173 set_current_state(TASK_INTERRUPTIBLE);
1174
1175 err = req(hdev, param);
1176
1177 schedule_timeout(timeout);
1178
1179 remove_wait_queue(&hdev->req_wait_q, &wait);
1180
1181 if (signal_pending(current))
1182 return -EINTR;
1183
1184 switch (hdev->req_status) {
1185 case HCI_REQ_DONE:
1186 case HCI_REQ_STATUS:
1187 err = radio_hci_err(hdev->req_result);
1188 break;
1189
1190 case HCI_REQ_CANCELED:
1191 err = -hdev->req_result;
1192 break;
1193
1194 default:
1195 err = -ETIMEDOUT;
1196 break;
1197 }
1198
1199 hdev->req_status = hdev->req_result = 0;
1200
1201 return err;
1202}
1203
1204static inline int radio_hci_request(struct radio_hci_dev *hdev,
1205 int (*req)(struct
1206 radio_hci_dev * hdev, unsigned long param),
1207 unsigned long param, __u32 timeout)
1208{
1209 int ret = 0;
1210
1211 ret = __radio_hci_request(hdev, req, param, timeout);
1212
1213 return ret;
1214}
1215
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301216static inline int hci_conf_event_mask(__u8 *arg,
1217 struct radio_hci_dev *hdev)
1218{
1219 u8 event_mask = *arg;
1220 return radio_hci_request(hdev, hci_fm_set_event_mask,
1221 event_mask, RADIO_HCI_TIMEOUT);
1222}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
1224 struct radio_hci_dev *hdev)
1225{
1226 int ret = 0;
1227 struct hci_fm_recv_conf_req *set_recv_conf = arg;
1228
1229 ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
1230 long)set_recv_conf, RADIO_HCI_TIMEOUT);
1231
1232 return ret;
1233}
1234
Ankur Nandwanid928d542011-08-11 13:15:41 -07001235static int hci_set_fm_trans_conf(struct hci_fm_trans_conf_req_struct *arg,
1236 struct radio_hci_dev *hdev)
1237{
1238 int ret = 0;
1239 struct hci_fm_trans_conf_req_struct *set_trans_conf = arg;
1240
1241 ret = radio_hci_request(hdev, hci_set_fm_trans_conf_req, (unsigned
1242 long)set_trans_conf, RADIO_HCI_TIMEOUT);
1243
1244 return ret;
1245}
1246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
1248{
1249 int ret = 0;
1250 __u32 tune_freq = *arg;
1251
1252 ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
1253 RADIO_HCI_TIMEOUT);
1254
1255 return ret;
1256}
1257
1258static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
1259 struct radio_hci_dev *hdev)
1260{
1261 int ret = 0;
1262 struct hci_fm_mute_mode_req *set_mute_conf = arg;
1263
1264 ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
1265 long)set_mute_conf, RADIO_HCI_TIMEOUT);
1266
1267 return ret;
1268}
1269
1270static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
1271 struct radio_hci_dev *hdev)
1272{
1273 int ret = 0;
1274 struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
1275
1276 ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
1277 long)set_stereo_conf, RADIO_HCI_TIMEOUT);
1278
1279 return ret;
1280}
1281
1282static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
1283{
1284 int ret = 0;
1285 __u8 antenna = *arg;
1286
1287 ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
1288 RADIO_HCI_TIMEOUT);
1289
1290 return ret;
1291}
1292
1293static int hci_fm_set_signal_threshold(__u8 *arg,
1294 struct radio_hci_dev *hdev)
1295{
1296 int ret = 0;
1297 __u8 sig_threshold = *arg;
1298
1299 ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
1300 sig_threshold, RADIO_HCI_TIMEOUT);
1301
1302 return ret;
1303}
1304
1305static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
1306 struct radio_hci_dev *hdev)
1307{
1308 int ret = 0;
1309 struct hci_fm_search_station_req *srch_stations = arg;
1310
1311 ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
1312 long)srch_stations, RADIO_HCI_TIMEOUT);
1313
1314 return ret;
1315}
1316
1317static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
1318 struct radio_hci_dev *hdev)
1319{
1320 int ret = 0;
1321 struct hci_fm_search_rds_station_req *srch_stations = arg;
1322
1323 ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
1324 long)srch_stations, RADIO_HCI_TIMEOUT);
1325
1326 return ret;
1327}
1328
1329static int hci_fm_search_station_list
1330 (struct hci_fm_search_station_list_req *arg,
1331 struct radio_hci_dev *hdev)
1332{
1333 int ret = 0;
1334 struct hci_fm_search_station_list_req *srch_list = arg;
1335
1336 ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
1337 long)srch_list, RADIO_HCI_TIMEOUT);
1338
1339 return ret;
1340}
1341
1342static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
1343 struct radio_hci_dev *hdev)
1344{
Ayaz Ahmad89265112012-10-05 19:39:11 +05301345 int ret = 0;
1346 struct hci_fm_rds_grp_req *fm_grp_mask = arg;
1347
1348 ret = radio_hci_request(hdev, hci_fm_rds_grp_mask_req, (unsigned
1349 long)fm_grp_mask, RADIO_HCI_TIMEOUT);
1350
1351 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352}
1353
1354static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
1355{
1356 int ret = 0;
1357 __u32 fm_grps_process = *arg;
1358
1359 ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
1360 fm_grps_process, RADIO_HCI_TIMEOUT);
1361
1362 return ret;
1363}
1364
1365int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
1366 struct radio_hci_dev *hdev)
1367{
1368 int ret = 0;
1369 struct hci_fm_def_data_rd_req *def_data_rd = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
1371 long)def_data_rd, RADIO_HCI_TIMEOUT);
1372
1373 return ret;
1374}
1375
1376int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
1377 struct radio_hci_dev *hdev)
1378{
1379 int ret = 0;
1380 struct hci_fm_def_data_wr_req *def_data_wr = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
1382 long)def_data_wr, RADIO_HCI_TIMEOUT);
1383
1384 return ret;
1385}
1386
1387int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
1388{
1389 int ret = 0;
1390 __u8 mode = *arg;
1391
1392 ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
1393 RADIO_HCI_TIMEOUT);
1394
1395 return ret;
1396}
1397
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301398static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399{
1400 int ret = 0;
1401 __u8 reset_counters = *arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 ret = radio_hci_request(hdev, hci_read_grp_counters_req,
1403 reset_counters, RADIO_HCI_TIMEOUT);
1404
1405 return ret;
1406}
1407
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301408static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
1409{
1410 int ret = 0;
1411 __u8 notch_filter = *arg;
1412 ret = radio_hci_request(hdev, hci_set_notch_filter_req,
1413 notch_filter, RADIO_HCI_TIMEOUT);
1414
1415 return ret;
1416}
1417
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001418static int hci_peek_data(struct hci_fm_riva_data *arg,
1419 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420{
1421 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001422 struct hci_fm_riva_data *peek_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423
1424 ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
1425 long)peek_data, RADIO_HCI_TIMEOUT);
1426
1427 return ret;
1428}
1429
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001430static int hci_poke_data(struct hci_fm_riva_poke *arg,
1431 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432{
1433 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001434 struct hci_fm_riva_poke *poke_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435
1436 ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
1437 long)poke_data, RADIO_HCI_TIMEOUT);
1438
1439 return ret;
1440}
1441
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001442static int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *arg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443 struct radio_hci_dev *hdev)
1444{
1445 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001446 struct hci_fm_ssbi_peek *ssbi_peek_reg = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447
1448 ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
1449 long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
1450
1451 return ret;
1452}
1453
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001454static int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg,
1455 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456{
1457 int ret = 0;
1458 struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
1459
1460 ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
1461 long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
1462
1463 return ret;
1464}
1465
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301466static int hci_set_ch_det_thresholds_req(struct hci_fm_ch_det_threshold *arg,
1467 struct radio_hci_dev *hdev)
1468{
1469 int ret = 0;
1470 struct hci_fm_ch_det_threshold *ch_det_threshold = arg;
1471 ret = radio_hci_request(hdev, hci_fm_set_ch_det_th,
1472 (unsigned long)ch_det_threshold, RADIO_HCI_TIMEOUT);
1473 return ret;
1474}
1475
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301476static int hci_fm_set_cal_req_proc(struct radio_hci_dev *hdev,
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301477 unsigned long param)
1478{
1479 u16 opcode = 0;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301480 struct hci_fm_set_cal_req_proc *cal_req =
1481 (struct hci_fm_set_cal_req_proc *)param;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301482
1483 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1484 HCI_OCF_FM_SET_CALIBRATION);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301485 return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301486 cal_req);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301487}
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301488
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301489static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
1490 unsigned long param)
1491{
1492 u16 opcode = 0;
1493 u8 cal_mode = param;
1494
1495 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1496 HCI_OCF_FM_DO_CALIBRATION);
1497 return radio_hci_send_cmd(hdev, opcode, sizeof(cal_mode),
1498 &cal_mode);
1499
1500}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1502{
1503 int ret = 0;
1504 unsigned long arg = 0;
1505
Ankur Nandwanid928d542011-08-11 13:15:41 -07001506 if (!hdev)
1507 return -ENODEV;
1508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 switch (cmd) {
1510 case HCI_FM_ENABLE_RECV_CMD:
1511 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1512 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1513 break;
1514
1515 case HCI_FM_DISABLE_RECV_CMD:
1516 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1517 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1518 break;
1519
1520 case HCI_FM_GET_RECV_CONF_CMD:
1521 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1522 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1523 break;
1524
1525 case HCI_FM_GET_STATION_PARAM_CMD:
1526 ret = radio_hci_request(hdev,
1527 hci_fm_get_station_param_req, arg,
1528 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1529 break;
1530
1531 case HCI_FM_GET_SIGNAL_TH_CMD:
1532 ret = radio_hci_request(hdev,
1533 hci_fm_get_sig_threshold_req, arg,
1534 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1535 break;
1536
1537 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1538 ret = radio_hci_request(hdev,
1539 hci_fm_get_program_service_req, arg,
1540 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1541 break;
1542
1543 case HCI_FM_GET_RADIO_TEXT_CMD:
1544 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1545 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1546 break;
1547
1548 case HCI_FM_GET_AF_LIST_CMD:
1549 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1550 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1551 break;
1552
1553 case HCI_FM_CANCEL_SEARCH_CMD:
1554 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1555 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1556 break;
1557
1558 case HCI_FM_RESET_CMD:
1559 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1560 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1561 break;
1562
1563 case HCI_FM_GET_FEATURES_CMD:
1564 ret = radio_hci_request(hdev,
1565 hci_fm_get_feature_lists_req, arg,
1566 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1567 break;
1568
1569 case HCI_FM_STATION_DBG_PARAM_CMD:
1570 ret = radio_hci_request(hdev,
1571 hci_fm_get_station_dbg_param_req, arg,
1572 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1573 break;
1574
Ankur Nandwanid928d542011-08-11 13:15:41 -07001575 case HCI_FM_ENABLE_TRANS_CMD:
1576 ret = radio_hci_request(hdev, hci_fm_enable_trans_req, arg,
1577 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1578 break;
1579
1580 case HCI_FM_DISABLE_TRANS_CMD:
1581 ret = radio_hci_request(hdev, hci_fm_disable_trans_req, arg,
1582 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1583 break;
1584
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301585 case HCI_FM_GET_TX_CONFIG:
1586 ret = radio_hci_request(hdev, hci_get_fm_trans_conf_req, arg,
1587 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1588 break;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301589 case HCI_FM_GET_DET_CH_TH_CMD:
1590 ret = radio_hci_request(hdev, hci_fm_get_ch_det_th, arg,
1591 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1592 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593 default:
1594 ret = -EINVAL;
1595 break;
1596 }
1597
1598 return ret;
1599}
1600
1601static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1602{
1603 hdev->req_result = result;
1604 hdev->req_status = HCI_REQ_DONE;
1605 wake_up_interruptible(&hdev->req_wait_q);
1606}
1607
1608static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1609{
1610 hdev->req_result = result;
1611 hdev->req_status = HCI_REQ_STATUS;
1612 wake_up_interruptible(&hdev->req_wait_q);
1613}
1614
1615static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1616{
1617 __u8 status = *((__u8 *) skb->data);
1618
1619 if (status)
1620 return;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 radio_hci_req_complete(hdev, status);
1623}
1624
1625static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1626 struct sk_buff *skb)
1627{
1628 __u8 status = *((__u8 *) skb->data);
1629 struct iris_device *radio = video_get_drvdata(video_get_dev());
1630
1631 if (status)
1632 return;
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05301633 if (radio->mode != FM_CALIB)
1634 iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635
1636 radio_hci_req_complete(hdev, status);
1637}
1638
1639static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1640{
1641 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1642 struct iris_device *radio = video_get_drvdata(video_get_dev());
1643
1644 if (rsp->status)
1645 return;
1646
1647 radio->recv_conf = rsp->recv_conf_rsp;
1648 radio_hci_req_complete(hdev, rsp->status);
1649}
1650
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301651static void hci_cc_fm_trans_get_conf_rsp(struct radio_hci_dev *hdev,
1652 struct sk_buff *skb)
1653{
1654 struct hci_fm_get_trans_conf_rsp *rsp = (void *)skb->data;
1655 struct iris_device *radio = video_get_drvdata(video_get_dev());
1656
1657 if (rsp->status)
1658 return;
1659 memcpy((void *)&radio->trans_conf, (void*)&rsp->trans_conf_rsp,
1660 sizeof(rsp->trans_conf_rsp));
1661 radio_hci_req_complete(hdev, rsp->status);
1662}
1663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1665 struct sk_buff *skb)
1666{
1667 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1668 struct iris_device *radio = video_get_drvdata(video_get_dev());
1669
1670 if (rsp->status)
1671 return;
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05301672 if (radio->mode != FM_CALIB)
1673 iris_q_event(radio, IRIS_EVT_RADIO_READY);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674
1675 radio_hci_req_complete(hdev, rsp->status);
1676}
1677
Ankur Nandwanid928d542011-08-11 13:15:41 -07001678
1679static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
1680 struct sk_buff *skb)
1681{
1682 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1683 struct iris_device *radio = video_get_drvdata(video_get_dev());
1684
1685 if (rsp->status)
1686 return;
1687
1688 iris_q_event(radio, HCI_EV_CMD_COMPLETE);
1689
1690 radio_hci_req_complete(hdev, rsp->status);
1691}
1692
1693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001694static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1695 struct sk_buff *skb)
1696{
1697 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1698 struct iris_device *radio = video_get_drvdata(video_get_dev());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699
1700 if (rsp->status)
1701 return;
1702
Venkateshwarlu Domakonda3d1d6e42011-12-09 15:08:58 +05301703 memcpy(&radio->sig_th, rsp, sizeof(struct hci_fm_sig_threshold_rsp));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001704 radio_hci_req_complete(hdev, rsp->status);
1705}
1706
1707static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1708{
1709 struct iris_device *radio = video_get_drvdata(video_get_dev());
1710 struct hci_fm_station_rsp *rsp = (void *)skb->data;
1711 radio->fm_st_rsp = *(rsp);
1712
1713 /* Tune is always succesful */
1714 radio_hci_req_complete(hdev, 0);
1715}
1716
1717static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1718{
1719 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1720
1721 if (rsp->status)
1722 return;
1723
1724 radio_hci_req_complete(hdev, rsp->status);
1725}
1726
1727static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1728{
1729 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1730
1731 if (rsp->status)
1732 return;
1733
1734 radio_hci_req_complete(hdev, rsp->status);
1735}
1736
1737static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1738{
1739 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1740
1741 if (rsp->status)
1742 return;
1743
1744 radio_hci_req_complete(hdev, rsp->status);
1745}
1746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1748 struct sk_buff *skb)
1749{
1750 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1751 struct iris_device *radio = video_get_drvdata(video_get_dev());
1752 struct v4l2_capability *v4l_cap = radio->g_cap;
1753
1754 if (rsp->status)
1755 return;
1756 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1757 (rsp->feature_mask & 0x000001);
1758
1759 radio_hci_req_complete(hdev, rsp->status);
1760}
1761
1762static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1763 struct sk_buff *skb)
1764{
1765 struct iris_device *radio = video_get_drvdata(video_get_dev());
1766 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
1767 radio->st_dbg_param = *(rsp);
1768
1769 if (radio->st_dbg_param.status)
1770 return;
1771
1772 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1773}
1774
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001775static void iris_q_evt_data(struct iris_device *radio,
1776 char *data, int len, int event)
1777{
1778 struct kfifo *data_b = &radio->data_buf[event];
1779 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1780 wake_up_interruptible(&radio->event_queue);
1781}
1782
1783static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1784 struct sk_buff *skb)
1785{
1786 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301787 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001788 int len;
1789 char *data;
1790
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301791 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001792 return;
1793 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1794 data = kmalloc(len, GFP_ATOMIC);
1795
1796 if (!data) {
1797 FMDERR("Memory allocation failed");
1798 return;
1799 }
1800
1801 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1802 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301803 radio_hci_req_complete(hdev, status);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301804 kfree(data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001805
1806}
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301807
1808static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
1809 struct sk_buff *skb)
1810{
1811 struct iris_device *radio = video_get_drvdata(video_get_dev());
1812 __u8 status = *((__u8 *) skb->data);
1813 __u8 len;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301814
1815 if (status)
1816 return;
1817 len = skb->data[1];
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301818
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05301819 memset(&radio->default_data, 0 , sizeof(struct hci_fm_data_rd_rsp));
1820 memcpy(&radio->default_data, &skb->data[0], len+2);
1821 iris_q_evt_data(radio, &skb->data[0], len+2, IRIS_BUF_RD_DEFAULT);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301822 radio_hci_req_complete(hdev, status);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301823}
1824
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001825static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1826 struct sk_buff *skb)
1827{
1828 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301829 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001830 char *data;
1831
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301832 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001833 return;
1834 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1835 if (!data) {
1836 FMDERR("Memory allocation failed");
1837 return;
1838 }
1839
1840 data[0] = skb->data[PEEK_DATA_OFSET];
1841 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301842 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001843 kfree(data);
1844}
1845
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301846static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
1847 struct sk_buff *skb)
1848{
1849 struct iris_device *radio = video_get_drvdata(video_get_dev());
1850 __u8 status = *((__u8 *) skb->data);
1851 char *data;
1852 if (status)
1853 return;
1854 data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
1855 if (!data) {
1856 FMDERR("memory allocation failed");
1857 return;
1858 }
1859 memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
1860 iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
1861 radio_hci_req_complete(hdev, status);
1862 kfree(data);
1863
1864}
1865
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301866static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
1867 struct sk_buff *skb)
1868{
1869 struct iris_device *radio = video_get_drvdata(video_get_dev());
1870 static struct hci_cc_do_calibration_rsp rsp ;
1871 rsp.status = skb->data[0];
1872 rsp.mode = skb->data[CALIB_MODE_OFSET];
1873
1874 if (rsp.status) {
1875 FMDERR("status = %d", rsp.status);
1876 return;
1877 }
1878 if (rsp.mode == PROCS_CALIB_MODE) {
1879 memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
1880 PROCS_CALIB_SIZE);
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05301881 iris_q_evt_data(radio, rsp.data, PROCS_CALIB_SIZE,
1882 IRIS_BUF_CAL_DATA);
1883 } else {
1884 return;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301885 }
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05301886
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301887 radio_hci_req_complete(hdev, rsp.status);
1888}
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301889
1890static void hci_cc_get_ch_det_threshold_rsp(struct radio_hci_dev *hdev,
1891 struct sk_buff *skb)
1892{
1893 struct iris_device *radio = video_get_drvdata(video_get_dev());
1894 u8 status = skb->data[0];
1895 if (status) {
1896 FMDERR("status = %d", status);
1897 return;
1898 }
1899 memcpy(&radio->ch_det_threshold, &skb->data[1],
1900 sizeof(struct hci_fm_ch_det_threshold));
1901 radio_hci_req_complete(hdev, status);
1902}
1903
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
1905 struct sk_buff *skb)
1906{
1907 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
1908 __u16 opcode;
1909
1910 skb_pull(skb, sizeof(*cmd_compl_ev));
1911
1912 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
1913
1914 switch (opcode) {
1915 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
Ayaz Ahmad3dad6512012-03-13 13:41:19 +05301916 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 hci_cc_fm_enable_rsp(hdev, skb);
1918 break;
1919 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
1920 hci_cc_conf_rsp(hdev, skb);
1921 break;
1922
1923 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
Ayaz Ahmad3dad6512012-03-13 13:41:19 +05301924 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 hci_cc_fm_disable_rsp(hdev, skb);
1926 break;
1927
1928 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
1929 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
1930 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
1931 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
1932 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
1933 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
1934 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
1935 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
1936 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
1937 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301938 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_CH_DET_THRESHOLD):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001939 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
1940 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301942 hci_cc_rsp(hdev, skb);
1943 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001944 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001945 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001946 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001947 case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301948 case hci_common_cmd_op_pack(HCI_OCF_FM_SET_CALIBRATION):
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301949 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_EVENT_MASK):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 hci_cc_rsp(hdev, skb);
1951 break;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301952
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001953 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
1954 hci_cc_ssbi_peek_rsp(hdev, skb);
1955 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001956 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
1957 hci_cc_sig_threshold_rsp(hdev, skb);
1958 break;
1959
1960 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
1961 hci_cc_station_rsp(hdev, skb);
1962 break;
1963
1964 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
1965 hci_cc_prg_srv_rsp(hdev, skb);
1966 break;
1967
1968 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
1969 hci_cc_rd_txt_rsp(hdev, skb);
1970 break;
1971
1972 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
1973 hci_cc_af_list_rsp(hdev, skb);
1974 break;
1975
1976 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301977 hci_cc_riva_read_default_rsp(hdev, skb);
1978 break;
1979
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001980 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001981 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 break;
1983
1984 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
1985 hci_cc_feature_list_rsp(hdev, skb);
1986 break;
1987
1988 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
1989 hci_cc_dbg_param_rsp(hdev, skb);
1990 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07001991 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_SET_TRANS_CONF_REQ):
1992 hci_cc_fm_trans_set_conf_rsp(hdev, skb);
1993 break;
1994
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301995 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
1996 hci_cc_rds_grp_cntrs_rsp(hdev, skb);
1997 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301998 case hci_common_cmd_op_pack(HCI_OCF_FM_DO_CALIBRATION):
1999 hci_cc_do_calibration_rsp(hdev, skb);
2000 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302001
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302002 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_GET_TRANS_CONF_REQ):
2003 hci_cc_fm_trans_get_conf_rsp(hdev, skb);
2004 break;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05302005 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_CH_DET_THRESHOLD):
2006 hci_cc_get_ch_det_threshold_rsp(hdev, skb);
2007 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 default:
2009 FMDERR("%s opcode 0x%x", hdev->name, opcode);
2010 break;
2011 }
2012
2013}
2014
2015static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
2016 struct sk_buff *skb)
2017{
2018 struct hci_ev_cmd_status *ev = (void *) skb->data;
2019 radio_hci_status_complete(hdev, ev->status);
2020}
2021
2022static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
2023 struct sk_buff *skb)
2024{
2025 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 struct iris_device *radio = video_get_drvdata(video_get_dev());
2027
Venkateshwarlu Domakonda862492d2011-11-29 11:51:24 +05302028 memcpy(&radio->fm_st_rsp.station_rsp, &skb->data[0],
2029 sizeof(struct hci_ev_tune_status));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002030 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
2031
2032 for (i = 0; i < IRIS_BUF_MAX; i++) {
2033 if (i >= IRIS_BUF_RT_RDS)
2034 kfifo_reset(&radio->data_buf[i]);
2035 }
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05302036 if (radio->fm_st_rsp.station_rsp.serv_avble)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2038 else
2039 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2040
2041 if (radio->fm_st_rsp.station_rsp.stereo_prg)
2042 iris_q_event(radio, IRIS_EVT_STEREO);
2043
2044 if (radio->fm_st_rsp.station_rsp.mute_mode)
2045 iris_q_event(radio, IRIS_EVT_MONO);
2046
2047 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
2048 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2049 else
2050 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2051}
2052
2053static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
2054 struct sk_buff *skb)
2055{
2056 struct iris_device *radio = video_get_drvdata(video_get_dev());
2057 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
2058}
2059
2060static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
2061 struct sk_buff *skb)
2062{
2063 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002064 struct hci_ev_srch_list_compl *ev ;
2065 int cnt;
2066 int stn_num;
2067 int rel_freq;
2068 int abs_freq;
2069 int len;
2070
2071 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
2072 if (!ev) {
2073 FMDERR("Memory allocation failed");
2074 return ;
2075 }
2076
2077 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
2078 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
2079
2080 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302081 (cnt < len) && (stn_num < ev->num_stations_found)
2082 && (stn_num < ARRAY_SIZE(ev->rel_freq));
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002083 cnt += PARAMS_PER_STATION, stn_num++) {
2084 abs_freq = *((int *)&skb->data[cnt]);
2085 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
2086 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
2087
2088 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
2089 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
2090 }
2091
2092 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
2093 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
2094 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
2095 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096}
2097
2098static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
2099 struct sk_buff *skb)
2100{
2101 struct iris_device *radio = video_get_drvdata(video_get_dev());
2102 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
2103}
2104
2105static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
2106 struct sk_buff *skb)
2107{
2108 struct iris_device *radio = video_get_drvdata(video_get_dev());
2109 __u8 st_status = *((__u8 *) skb->data);
2110 if (st_status)
2111 iris_q_event(radio, IRIS_EVT_STEREO);
2112 else
2113 iris_q_event(radio, IRIS_EVT_MONO);
2114}
2115
Ayaz Ahmad89265112012-10-05 19:39:11 +05302116static void hci_ev_raw_rds_group_data(struct radio_hci_dev *hdev,
2117 struct sk_buff *skb)
2118{
2119 struct iris_device *radio;
2120 unsigned char blocknum, index;
2121 struct rds_grp_data temp;
2122 unsigned int mask_bit;
2123 unsigned short int aid, agt, gtc;
2124 unsigned short int carrier;
2125
2126 radio = video_get_drvdata(video_get_dev());
2127 index = RDSGRP_DATA_OFFSET;
2128
2129 for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
2130 temp.rdsBlk[blocknum].rdsLsb =
2131 (skb->data[index]);
2132 temp.rdsBlk[blocknum].rdsMsb =
2133 (skb->data[index+1]);
2134 index = index + 2;
2135 }
2136
2137 aid = AID(temp.rdsBlk[3].rdsLsb, temp.rdsBlk[3].rdsMsb);
2138 gtc = GTC(temp.rdsBlk[1].rdsMsb);
2139 agt = AGT(temp.rdsBlk[1].rdsLsb);
2140
2141 if (gtc == GRP_3A) {
2142 switch (aid) {
2143 case ERT_AID:
2144 /* calculate the grp mask for RDS grp
2145 * which will contain actual eRT text
2146 *
2147 * Bit Pos 0 1 2 3 4 5 6 7
2148 * Grp Type 0A 0B 1A 1B 2A 2B 3A 3B
2149 *
2150 * similary for rest grps
2151 */
2152 mask_bit = (((agt >> 1) << 1) + (agt & 1));
2153 oda_agt = (1 << mask_bit);
2154 utf_8_flag = (temp.rdsBlk[2].rdsLsb & 1);
2155 formatting_dir = EXTRACT_BIT(temp.rdsBlk[2].rdsLsb,
2156 ERT_FORMAT_DIR_BIT);
2157 if (ert_carrier != agt)
2158 iris_q_event(radio, IRIS_EVT_NEW_ODA);
2159 ert_carrier = agt;
2160 break;
2161 case RT_PLUS_AID:
2162 /* calculate the grp mask for RDS grp
2163 * which will contain actual eRT text
2164 *
2165 * Bit Pos 0 1 2 3 4 5 6 7
2166 * Grp Type 0A 0B 1A 1B 2A 2B 3A 3B
2167 *
2168 * similary for rest grps
2169 */
2170 mask_bit = (((agt >> 1) << 1) + (agt & 1));
2171 oda_agt = (1 << mask_bit);
2172 /*Extract 5th bit of MSB (b7b6b5b4b3b2b1b0)*/
2173 rt_ert_flag = EXTRACT_BIT(temp.rdsBlk[2].rdsMsb,
2174 RT_ERT_FLAG_BIT);
2175 if (rt_plus_carrier != agt)
2176 iris_q_event(radio, IRIS_EVT_NEW_ODA);
2177 rt_plus_carrier = agt;
2178 break;
2179 default:
2180 oda_agt = 0;
2181 break;
2182 }
2183 } else {
2184 carrier = gtc;
2185 if ((carrier == rt_plus_carrier))
2186 hci_ev_rt_plus(radio, temp);
2187 else if (carrier == ert_carrier)
2188 hci_buff_ert(radio, &temp);
2189 }
2190}
2191
2192static void hci_buff_ert(struct iris_device *radio,
2193 struct rds_grp_data *rds_buf)
2194{
2195 int i;
2196 unsigned short int info_byte = 0;
2197 unsigned short int byte_pair_index;
2198
2199 byte_pair_index = AGT(rds_buf->rdsBlk[1].rdsLsb);
2200 if (byte_pair_index == 0) {
2201 c_byt_pair_index = 0;
2202 ert_len = 0;
2203 }
2204 if (c_byt_pair_index == byte_pair_index) {
2205 c_byt_pair_index++;
2206 for (i = 2; i <= 3; i++) {
2207 info_byte = rds_buf->rdsBlk[i].rdsLsb;
2208 info_byte |= (rds_buf->rdsBlk[i].rdsMsb << 8);
2209 ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsMsb;
2210 ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsLsb;
2211 if ((utf_8_flag == 0)
2212 && (info_byte == CARRIAGE_RETURN)) {
2213 ert_len -= 2;
2214 break;
2215 } else if ((utf_8_flag == 1)
2216 &&
2217 (rds_buf->rdsBlk[i].rdsMsb
2218 == CARRIAGE_RETURN)) {
2219 info_byte = CARRIAGE_RETURN;
2220 ert_len -= 2;
2221 break;
2222 } else if ((utf_8_flag == 1)
2223 &&
2224 (rds_buf->rdsBlk[i].rdsLsb
2225 == CARRIAGE_RETURN)) {
2226 info_byte = CARRIAGE_RETURN;
2227 ert_len--;
2228 break;
2229 }
2230 }
2231 if ((byte_pair_index == MAX_ERT_SEGMENT) ||
2232 (info_byte == CARRIAGE_RETURN)) {
2233 hci_ev_ert(radio);
2234 c_byt_pair_index = 0;
2235 ert_len = 0;
2236 }
2237 } else {
2238 ert_len = 0;
2239 c_byt_pair_index = 0;
2240 }
2241}
2242static void hci_ev_ert(struct iris_device *radio)
2243
2244{
2245 char *data = NULL;
2246
2247 if (ert_len <= 0)
2248 return;
2249 data = kmalloc((ert_len + 3), GFP_ATOMIC);
2250 if (data != NULL) {
2251 data[0] = ert_len;
2252 data[1] = utf_8_flag;
2253 data[2] = formatting_dir;
2254 memcpy((data + 3), ert_buf, ert_len);
2255 iris_q_evt_data(radio, data, (ert_len + 3), IRIS_BUF_ERT);
2256 iris_q_event(radio, IRIS_EVT_NEW_ERT);
2257 kfree(data);
2258 }
2259}
2260
2261static void hci_ev_rt_plus(struct iris_device *radio,
2262 struct rds_grp_data rds_buf)
2263{
2264 char tag_type1, tag_type2;
2265 char *data = NULL;
2266 int len = 0;
2267 unsigned short int agt;
2268
2269 agt = AGT(rds_buf.rdsBlk[1].rdsLsb);
2270 /*right most 3 bits of Lsb of block 2
2271 * and left most 3 bits of Msb of block 3
2272 */
2273 tag_type1 = (((agt & TAG1_MSB_MASK) << TAG1_MSB_OFFSET) |
2274 (rds_buf.rdsBlk[2].rdsMsb >> TAG1_LSB_OFFSET));
2275
2276 /*right most 1 bit of lsb of 3rd block
2277 * and left most 5 bits of Msb of 4th block
2278 */
2279 tag_type2 = (((rds_buf.rdsBlk[2].rdsLsb & TAG2_MSB_MASK)
2280 << TAG2_MSB_OFFSET) |
2281 (rds_buf.rdsBlk[3].rdsMsb >> TAG2_LSB_OFFSET));
2282
2283 if (tag_type1 != DUMMY_CLASS)
2284 len += RT_PLUS_LEN_1_TAG;
2285 if (tag_type2 != DUMMY_CLASS)
2286 len += RT_PLUS_LEN_1_TAG;
2287
2288 if (len != 0) {
2289 len += 2;
2290 data = kmalloc(len, GFP_ATOMIC);
2291 } else {
2292 FMDERR("Len is zero\n");
2293 return ;
2294 }
2295 if (data != NULL) {
2296 data[0] = len;
2297 len = 1;
2298 data[len++] = rt_ert_flag;
2299 if (tag_type1 != DUMMY_CLASS) {
2300 data[len++] = tag_type1;
2301 /*start position of tag1
2302 *right most 5 bits of msb of 3rd block
2303 *and left most bit of lsb of 3rd block
2304 */
2305 data[len++] = (((rds_buf.rdsBlk[2].rdsMsb &
2306 TAG1_POS_MSB_MASK)
2307 << TAG1_POS_MSB_OFFSET)
2308 |
2309 (rds_buf.rdsBlk[2].rdsLsb >>
2310 TAG1_POS_LSB_OFFSET));
2311 /*length of tag1
2312 *left most 6 bits of lsb of 3rd block
2313 */
2314 data[len++] = ((rds_buf.rdsBlk[2].rdsLsb
2315 >> TAG1_LEN_OFFSET)
2316 &
2317 TAG1_LEN_MASK) + 1;
2318 }
2319 if (tag_type2 != DUMMY_CLASS) {
2320 data[len++] = tag_type2;
2321 /*start position of tag2
2322 *right most 3 bit of msb of 4th block
2323 *and left most 3 bits of lsb of 4th block
2324 */
2325 data[len++] = (((rds_buf.rdsBlk[3].rdsMsb
2326 & TAG2_POS_MSB_MASK)
2327 << TAG2_POS_MSB_OFFSET)
2328 |
2329 (rds_buf.rdsBlk[3].rdsLsb
2330 >> TAG2_POS_LSB_OFFSET));
2331 /*length of tag2
2332 *right most 5 bits of lsb of 4th block
2333 */
2334 data[len++] = (rds_buf.rdsBlk[3].rdsLsb
2335 & TAG2_LEN_MASK) + 1;
2336 }
2337 iris_q_evt_data(radio, data, len, IRIS_BUF_RT_PLUS);
2338 iris_q_event(radio, IRIS_EVT_NEW_RT_PLUS);
2339 kfree(data);
2340 } else {
2341 FMDERR("memory allocation failed\n");
2342 }
2343}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002344
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002345static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
2346 struct sk_buff *skb)
2347{
2348 struct iris_device *radio = video_get_drvdata(video_get_dev());
2349 int len;
2350 char *data;
2351
2352 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
2353 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
2354 data = kmalloc(len, GFP_ATOMIC);
2355 if (!data) {
2356 FMDERR("Failed to allocate memory");
2357 return;
2358 }
2359
2360 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
2361 data[1] = skb->data[RDS_PTYPE];
2362 data[2] = skb->data[RDS_PID_LOWER];
2363 data[3] = skb->data[RDS_PID_HIGHER];
2364 data[4] = 0;
2365
2366 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
2367
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002368 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002369
2370 kfree(data);
2371}
2372
2373
2374static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
2375 struct sk_buff *skb)
2376{
2377 struct iris_device *radio = video_get_drvdata(video_get_dev());
2378 int len = 0;
2379 char *data;
2380
2381 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
2382
Srinivasa Rao Uppala69839842012-01-13 18:36:12 +05302383 while ((skb->data[len+RDS_OFFSET] != 0x0d) && (len < RX_RT_DATA_LENGTH))
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002384 len++;
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002385 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
2386 if (!data) {
2387 FMDERR("Failed to allocate memory");
2388 return;
2389 }
2390
2391 data[0] = len;
2392 data[1] = skb->data[RDS_PTYPE];
2393 data[2] = skb->data[RDS_PID_LOWER];
2394 data[3] = skb->data[RDS_PID_HIGHER];
2395 data[4] = 0;
2396
2397 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
2398 data[len+RDS_OFFSET] = 0x00;
2399
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002400 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002401
2402 kfree(data);
2403}
2404
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302405static void hci_ev_af_list(struct radio_hci_dev *hdev,
2406 struct sk_buff *skb)
2407{
2408 struct iris_device *radio = video_get_drvdata(video_get_dev());
2409 struct hci_ev_af_list ev;
2410
2411 ev.tune_freq = *((int *) &skb->data[0]);
2412 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
2413 ev.af_size = skb->data[AF_SIZE_OFFSET];
2414 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
2415 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
2416 iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
2417}
2418
2419static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
2420 struct sk_buff *skb)
2421{
2422 struct iris_device *radio = video_get_drvdata(video_get_dev());
2423 __u8 rds_status = skb->data[0];
2424
2425 if (rds_status)
2426 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2427 else
2428 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2429}
2430
2431static void hci_ev_service_available(struct radio_hci_dev *hdev,
2432 struct sk_buff *skb)
2433{
2434 struct iris_device *radio = video_get_drvdata(video_get_dev());
Venkateshwarlu Domakondad6140eb2012-01-17 16:23:52 +05302435 u8 serv_avble = skb->data[0];
2436 if (serv_avble)
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302437 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2438 else
2439 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2440}
2441
2442static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
2443 struct sk_buff *skb)
2444{
2445 struct iris_device *radio = video_get_drvdata(video_get_dev());
2446 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
2447}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002449void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
2450{
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302451 struct radio_hci_event_hdr *hdr;
2452 u8 event;
2453
2454 if (skb == NULL) {
2455 FMDERR("Socket buffer is NULL");
2456 return;
2457 }
2458
2459 hdr = (void *) skb->data;
2460 event = hdr->evt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461
2462 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
2463
2464 switch (event) {
2465 case HCI_EV_TUNE_STATUS:
2466 hci_ev_tune_status(hdev, skb);
2467 break;
2468 case HCI_EV_SEARCH_PROGRESS:
2469 case HCI_EV_SEARCH_RDS_PROGRESS:
2470 case HCI_EV_SEARCH_LIST_PROGRESS:
2471 hci_ev_search_next(hdev, skb);
2472 break;
2473 case HCI_EV_STEREO_STATUS:
2474 hci_ev_stereo_status(hdev, skb);
2475 break;
2476 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302477 hci_ev_rds_lock_status(hdev, skb);
2478 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302480 hci_ev_service_available(hdev, skb);
2481 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482 case HCI_EV_RDS_RX_DATA:
Ayaz Ahmad89265112012-10-05 19:39:11 +05302483 hci_ev_raw_rds_group_data(hdev, skb);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002484 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002486 hci_ev_program_service(hdev, skb);
2487 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002489 hci_ev_radio_text(hdev, skb);
2490 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302492 hci_ev_af_list(hdev, skb);
2493 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302495 hci_ev_rds_grp_complete(hdev, skb);
2496 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002497 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2498 break;
2499
2500 case HCI_EV_CMD_COMPLETE:
2501 hci_cmd_complete_event(hdev, skb);
2502 break;
2503
2504 case HCI_EV_CMD_STATUS:
2505 hci_cmd_status_event(hdev, skb);
2506 break;
2507
2508 case HCI_EV_SEARCH_COMPLETE:
2509 case HCI_EV_SEARCH_RDS_COMPLETE:
2510 hci_ev_search_compl(hdev, skb);
2511 break;
2512
2513 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002514 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515 break;
2516
2517 default:
2518 break;
2519 }
2520}
2521
2522/*
2523 * fops/IOCTL helper functions
2524 */
2525
2526static int iris_search(struct iris_device *radio, int on, int dir)
2527{
2528 int retval = 0;
2529 enum search_t srch = radio->g_search_mode & SRCH_MODE;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302530 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002531
2532 if (on) {
2533 switch (srch) {
2534 case SCAN_FOR_STRONG:
2535 case SCAN_FOR_WEAK:
2536 radio->srch_st_list.srch_list_dir = dir;
2537 radio->srch_st_list.srch_list_mode = srch;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002538 retval = hci_fm_search_station_list(
2539 &radio->srch_st_list, radio->fm_hdev);
2540 break;
2541 case RDS_SEEK_PTY:
2542 case RDS_SCAN_PTY:
2543 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002544 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545 radio->srch_rds.srch_station.srch_mode = srch;
2546 radio->srch_rds.srch_station.srch_dir = dir;
2547 radio->srch_rds.srch_station.scan_time =
2548 radio->g_scan_time;
2549 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2550 radio->fm_hdev);
2551 break;
2552 default:
2553 radio->srch_st.srch_mode = srch;
2554 radio->srch_st.scan_time = radio->g_scan_time;
2555 radio->srch_st.srch_dir = dir;
2556 retval = hci_fm_search_stations(
2557 &radio->srch_st, radio->fm_hdev);
2558 break;
2559 }
2560
2561 } else {
2562 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2563 }
2564
2565 return retval;
2566}
2567
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302568static int set_low_power_mode(struct iris_device *radio, int power_mode)
2569{
2570
2571 int rds_grps_proc = 0x00;
2572 int retval = 0;
2573 if (radio->power_mode != power_mode) {
2574
2575 if (power_mode) {
2576 radio->event_mask = 0x00;
Srinivasa Rao Uppala1da1a242012-01-11 11:00:10 +05302577 if (radio->af_jump_bit)
2578 rds_grps_proc = 0x00 | AF_JUMP_ENABLE;
2579 else
2580 rds_grps_proc = 0x00;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302581 retval = hci_fm_rds_grps_process(
2582 &rds_grps_proc,
2583 radio->fm_hdev);
2584 if (retval < 0) {
2585 FMDERR("Disable RDS failed");
2586 return retval;
2587 }
2588 retval = hci_conf_event_mask(&radio->event_mask,
2589 radio->fm_hdev);
2590 } else {
2591
2592 radio->event_mask = SIG_LEVEL_INTR |
2593 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2594 retval = hci_conf_event_mask(&radio->event_mask,
2595 radio->fm_hdev);
2596 if (retval < 0) {
2597 FMDERR("Enable Async events failed");
2598 return retval;
2599 }
2600 retval = hci_fm_rds_grps_process(
2601 &radio->g_rds_grp_proc_ps,
2602 radio->fm_hdev);
2603 }
2604 radio->power_mode = power_mode;
2605 }
2606 return retval;
2607}
Ankur Nandwanid928d542011-08-11 13:15:41 -07002608static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002609{
2610 int retval;
2611 radio->region = req_region;
2612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002613 retval = hci_set_fm_recv_conf(
2614 &radio->recv_conf,
2615 radio->fm_hdev);
2616
2617 return retval;
2618}
2619
Ankur Nandwanid928d542011-08-11 13:15:41 -07002620
2621static int iris_trans_set_region(struct iris_device *radio, int req_region)
2622{
2623 int retval;
2624 radio->region = req_region;
2625
Ankur Nandwanid928d542011-08-11 13:15:41 -07002626 retval = hci_set_fm_trans_conf(
2627 &radio->trans_conf,
2628 radio->fm_hdev);
2629 return retval;
2630}
2631
2632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002633static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2634{
2635
2636 int retval;
2637 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2638 if (retval < 0)
2639 FMDERR("Error while setting the frequency : %d\n", retval);
2640 return retval;
2641}
2642
2643
2644static int iris_vidioc_queryctrl(struct file *file, void *priv,
2645 struct v4l2_queryctrl *qc)
2646{
2647 unsigned char i;
2648 int retval = -EINVAL;
2649
2650 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2651 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2652 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2653 retval = 0;
2654 break;
2655 }
2656 }
2657
2658 return retval;
2659}
2660
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302661static int iris_do_calibration(struct iris_device *radio)
2662{
2663 char cal_mode = 0x00;
2664 int retval = 0x00;
2665
2666 cal_mode = PROCS_CALIB_MODE;
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05302667 radio->mode = FM_CALIB;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302668 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2669 radio->fm_hdev);
2670 if (retval < 0) {
2671 FMDERR("Enable failed before calibration %x", retval);
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05302672 radio->mode = FM_OFF;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302673 return retval;
2674 }
2675 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2676 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2677 if (retval < 0) {
2678 FMDERR("Do Process calibration failed %x", retval);
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05302679 radio->mode = FM_RECV;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302680 return retval;
2681 }
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302682 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2683 radio->fm_hdev);
2684 if (retval < 0)
2685 FMDERR("Disable Failed after calibration %d", retval);
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05302686 radio->mode = FM_OFF;
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05302687 return retval;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302688}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2690 struct v4l2_control *ctrl)
2691{
2692 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2693 int retval = 0;
2694
2695 switch (ctrl->id) {
2696 case V4L2_CID_AUDIO_VOLUME:
2697 break;
2698 case V4L2_CID_AUDIO_MUTE:
2699 ctrl->value = radio->mute_mode.hard_mute;
2700 break;
2701 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2702 ctrl->value = radio->g_search_mode;
2703 break;
2704 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2705 ctrl->value = radio->g_scan_time;
2706 break;
2707 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302708 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 break;
2710 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302711 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712 break;
2713 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2714 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2715 if (retval < 0)
2716 return retval;
2717 ctrl->value = radio->st_dbg_param.io_verc;
2718 break;
2719 case V4L2_CID_PRIVATE_IRIS_INTDET:
2720 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2721 if (retval < 0)
2722 return retval;
2723 ctrl->value = radio->st_dbg_param.in_det_out;
2724 break;
2725 case V4L2_CID_PRIVATE_IRIS_REGION:
2726 ctrl->value = radio->region;
2727 break;
2728 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2729 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
Venkateshwarlu Domakonda3d1d6e42011-12-09 15:08:58 +05302730 if (retval < 0) {
2731 FMDERR("Error in get signal threshold %d\n", retval);
2732 return retval;
2733 }
2734 ctrl->value = radio->sig_th.sig_threshold;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002735 break;
2736 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302737 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002738 break;
2739 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302740 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 break;
2742 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302743 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002744 break;
2745 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002746 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002747 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002748 } else if (radio->mode == FM_TRANS) {
2749 ctrl->value = radio->trans_conf.emphasis;
2750 } else {
2751 FMDERR("Error in radio mode"
2752 " %d\n", retval);
2753 return -EINVAL;
2754 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002755 break;
2756 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002757 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002759 } else if (radio->mode == FM_TRANS) {
2760 ctrl->value = radio->trans_conf.rds_std;
2761 } else {
2762 FMDERR("Error in radio mode"
2763 " %d\n", retval);
2764 return -EINVAL;
2765 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766 break;
2767 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002768 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002770 } else {
2771 FMDERR("Error in radio mode"
2772 " %d\n", retval);
2773 return -EINVAL;
2774 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002775 break;
2776 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002777 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002779 } else {
2780 FMDERR("Error in radio mode"
2781 " %d\n", retval);
2782 return -EINVAL;
2783 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002784 break;
2785 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2786 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2787 break;
2788 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002789 case V4L2_CID_PRIVATE_IRIS_PSALL:
2790 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002791 break;
2792 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2793 ctrl->value = radio->rds_grp.rds_buf_size;
2794 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002795 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302796 ctrl->value = radio->power_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797 break;
2798 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2799 ctrl->value = radio->g_antenna;
2800 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002801 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2802 ctrl->value = radio->mute_mode.soft_mute;
2803 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302804 case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
2805 retval = iris_do_calibration(radio);
2806 break;
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05302807 case V4L2_CID_PRIVATE_IRIS_GET_SINR:
2808 if (radio->mode == FM_RECV) {
2809 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD,
2810 radio->fm_hdev);
2811 if (retval < 0) {
2812 FMDERR("Get SINR Failed");
2813 return retval;
2814 }
2815 ctrl->value = radio->fm_st_rsp.station_rsp.sinr;
2816
2817 } else
2818 retval = -EINVAL;
Ayaz Ahmadb69202b2012-02-23 19:24:46 +05302819 break;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05302820 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
2821 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
2822 if (retval < 0) {
2823 FMDERR("Get High det threshold failed %x", retval);
2824 return retval;
2825 }
2826 ctrl->value = radio->ch_det_threshold.high_th;
2827 break;
2828 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
2829 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
2830 if (retval < 0) {
2831 FMDERR("Get Low det threshold failed %x", retval);
2832 return retval;
2833 }
2834 ctrl->value = radio->ch_det_threshold.low_th;
2835 break;
2836 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
2837 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
2838 if (retval < 0) {
2839 FMDERR("Get SINR threshold failed %x", retval);
2840 return retval;
2841 }
2842 ctrl->value = radio->ch_det_threshold.sinr;
2843 break;
2844 case V4L2_CID_PRIVATE_SINR_SAMPLES:
2845 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
2846 if (retval < 0) {
2847 FMDERR("Get SINR samples failed %x", retval);
2848 return retval;
2849 }
2850
2851 ctrl->value = radio->ch_det_threshold.sinr_samples;
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05302852 break;
Ayaz Ahmad37294ba2012-07-10 16:38:11 +05302853 case V4L2_CID_PRIVATE_VALID_CHANNEL:
2854 ctrl->value = radio->is_station_valid;
2855 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002856 default:
2857 retval = -EINVAL;
2858 }
2859 if (retval < 0)
2860 FMDERR("get control failed with %d, id: %d\n",
2861 retval, ctrl->id);
2862 return retval;
2863}
2864
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302865static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
2866 struct v4l2_ext_controls *ctrl)
2867{
2868 int retval = 0;
2869 char *data = NULL;
2870 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2871 struct hci_fm_def_data_rd_req default_data_rd;
2872
2873 switch ((ctrl->controls[0]).id) {
2874 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
2875 data = (ctrl->controls[0]).string;
2876 memset(&default_data_rd, 0, sizeof(default_data_rd));
2877 if (copy_from_user(&default_data_rd.mode, data,
2878 sizeof(default_data_rd)))
2879 return -EFAULT;
2880 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
2881 break;
2882 default:
2883 retval = -EINVAL;
2884 }
2885
2886 return retval;
2887}
2888
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002889static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2890 struct v4l2_ext_controls *ctrl)
2891{
Ankur Nandwanid928d542011-08-11 13:15:41 -07002892 int retval = 0;
2893 int bytes_to_copy;
2894 struct hci_fm_tx_ps tx_ps;
2895 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302896 struct hci_fm_def_data_wr_req default_data;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302897 struct hci_fm_set_cal_req_proc proc_cal_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002898
2899 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2900 char *data = NULL;
2901
2902 switch ((ctrl->controls[0]).id) {
2903 case V4L2_CID_RDS_TX_PS_NAME:
2904 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2905 /*Pass a sample PS string */
2906
2907 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
2908 bytes_to_copy = min((int)(ctrl->controls[0]).size,
2909 MAX_PS_LENGTH);
2910 data = (ctrl->controls[0]).string;
2911
2912 if (copy_from_user(tx_ps.ps_data,
2913 data, bytes_to_copy))
2914 return -EFAULT;
2915 tx_ps.ps_control = 0x01;
2916 tx_ps.pi = radio->pi;
2917 tx_ps.pty = radio->pty;
2918 tx_ps.ps_repeatcount = radio->ps_repeatcount;
Ayaz Ahmad1c0db522012-08-27 17:52:51 +05302919 tx_ps.ps_num = (bytes_to_copy / PS_STRING_LEN);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002920
2921 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2922 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
2923 break;
2924 case V4L2_CID_RDS_TX_RADIO_TEXT:
2925 bytes_to_copy =
2926 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2927 data = (ctrl->controls[0]).string;
2928
2929 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
2930
2931 if (copy_from_user(tx_rt.rt_data,
2932 data, bytes_to_copy))
2933 return -EFAULT;
2934
2935 tx_rt.rt_control = 0x01;
2936 tx_rt.pi = radio->pi;
2937 tx_rt.pty = radio->pty;
Ayaz Ahmad1c0db522012-08-27 17:52:51 +05302938 tx_rt.rt_len = bytes_to_copy;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002939
2940 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2941 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
2942 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302943 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
2944 data = (ctrl->controls[0]).string;
2945 memset(&default_data, 0, sizeof(default_data));
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05302946 /*
2947 * Check if length of the 'FM Default Data' to be sent
2948 * is within the maximum 'FM Default Data' packet limit.
2949 * Max. 'FM Default Data' packet length is 251 bytes:
2950 * 1 byte - XFR Mode
2951 * 1 byte - length of the default data
2952 * 249 bytes - actual data to be configured
2953 */
2954 if (ctrl->controls[0].size > (DEFAULT_DATA_SIZE + 2)) {
2955 pr_err("%s: Default data buffer overflow!\n", __func__);
2956 return -EINVAL;
2957 }
2958
2959 /* copy only 'size' bytes of data as requested by user */
2960 retval = copy_from_user(&default_data, data,
2961 ctrl->controls[0].size);
2962 if (retval > 0) {
2963 pr_err("%s: Failed to copy %d bytes of default data"
2964 " passed by user\n", __func__, retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302965 return -EFAULT;
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05302966 }
2967 FMDBG("%s: XFR Mode\t: 0x%x\n", __func__, default_data.mode);
2968 FMDBG("%s: XFR Data Length\t: %d\n", __func__,
2969 default_data.length);
2970 /*
2971 * Check if the 'length' of the actual XFR data to be configured
2972 * is valid or not. Length of actual XFR data should be always
2973 * 2 bytes less than the total length of the 'FM Default Data'.
2974 * Length of 'FM Default Data' DEF_DATA_LEN: (1+1+XFR Data Size)
2975 * Length of 'Actual XFR Data' XFR_DATA_LEN: (DEF_DATA_LEN - 2)
2976 */
2977 if (default_data.length != (ctrl->controls[0].size - 2)) {
2978 pr_err("%s: Invalid 'length' parameter passed for "
2979 "actual xfr data\n", __func__);
2980 return -EINVAL;
2981 }
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302982 retval = hci_def_data_write(&default_data, radio->fm_hdev);
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05302983 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302984 case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302985 data = (ctrl->controls[0]).string;
2986 bytes_to_copy = (ctrl->controls[0]).size;
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05302987 if (bytes_to_copy < PROCS_CALIB_SIZE) {
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302988 FMDERR("data is less than required size");
2989 return -EFAULT;
2990 }
2991 memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
2992 proc_cal_req.mode = PROCS_CALIB_MODE;
2993 if (copy_from_user(&proc_cal_req.data[0],
2994 data, sizeof(proc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302995 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302996 retval = radio_hci_request(radio->fm_hdev,
2997 hci_fm_set_cal_req_proc,
2998 (unsigned long)&proc_cal_req,
2999 RADIO_HCI_TIMEOUT);
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05303000 if (retval < 0)
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05303001 FMDERR("Set Process calibration failed %d", retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303002 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003003 default:
3004 FMDBG("Shouldn't reach here\n");
3005 retval = -1;
3006 }
3007 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003008}
3009
3010static int iris_vidioc_s_ctrl(struct file *file, void *priv,
3011 struct v4l2_control *ctrl)
3012{
3013 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3014 int retval = 0;
3015 unsigned int rds_grps_proc = 0;
3016 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003017 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303018 struct hci_fm_tx_ps tx_ps = {0};
3019 struct hci_fm_tx_rt tx_rt = {0};
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05303020 struct hci_fm_def_data_rd_req rd_txgain;
3021 struct hci_fm_def_data_wr_req wr_txgain;
Ayaz Ahmad37294ba2012-07-10 16:38:11 +05303022 char sinr_th, sinr;
3023 __u8 intf_det_low_th, intf_det_high_th, intf_det_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003024
3025 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05303026 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003027 radio->tone_freq = ctrl->value;
3028 retval = radio_hci_request(radio->fm_hdev,
3029 hci_fm_tone_generator, arg,
3030 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303031 if (retval < 0)
3032 FMDERR("Error while setting the tone %d", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07003033 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 case V4L2_CID_AUDIO_VOLUME:
3035 break;
3036 case V4L2_CID_AUDIO_MUTE:
3037 radio->mute_mode.hard_mute = ctrl->value;
3038 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
3039 retval = hci_set_fm_mute_mode(
3040 &radio->mute_mode,
3041 radio->fm_hdev);
3042 if (retval < 0)
3043 FMDERR("Error while set FM hard mute"" %d\n",
3044 retval);
3045 break;
3046 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
3047 radio->g_search_mode = ctrl->value;
3048 break;
3049 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
3050 radio->g_scan_time = ctrl->value;
3051 break;
3052 case V4L2_CID_PRIVATE_IRIS_SRCHON:
3053 iris_search(radio, ctrl->value, SRCH_DIR_UP);
3054 break;
3055 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003056 switch (ctrl->value) {
3057 case FM_RECV:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003058 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
3059 radio->fm_hdev);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303060 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003061 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07003062 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303063 return retval;
3064 }
3065 radio->mode = FM_RECV;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003066 radio->mute_mode.soft_mute = CTRL_ON;
3067 retval = hci_set_fm_mute_mode(
3068 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05303070 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003071 FMDERR("Failed to enable Smute\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05303072 return retval;
3073 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07003074 radio->stereo_mode.stereo_mode = CTRL_OFF;
3075 radio->stereo_mode.sig_blend = CTRL_ON;
3076 radio->stereo_mode.intf_blend = CTRL_ON;
3077 radio->stereo_mode.most_switch = CTRL_ON;
3078 retval = hci_set_fm_stereo_mode(
3079 &radio->stereo_mode,
3080 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05303081 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003082 FMDERR("Failed to set stereo mode\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05303083 return retval;
3084 }
Srinivasa Rao Uppalaf1febce2011-11-09 10:30:16 +05303085 radio->event_mask = SIG_LEVEL_INTR |
3086 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
3087 retval = hci_conf_event_mask(&radio->event_mask,
3088 radio->fm_hdev);
3089 if (retval < 0) {
3090 FMDERR("Enable Async events failed");
3091 return retval;
3092 }
Srinivasa Rao Uppalaf0d13742011-09-08 10:13:13 +05303093 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
3094 radio->fm_hdev);
3095 if (retval < 0)
3096 FMDERR("Failed to get the Recv Config\n");
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07003097 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003098 case FM_TRANS:
3099 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
3100 radio->fm_hdev);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303101 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003102 FMDERR("Error while enabling TRANS FM"
3103 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303104 return retval;
3105 }
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05303106 radio->mode = FM_TRANS;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303107 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
3108 if (retval < 0)
3109 FMDERR("get frequency failed %d\n", retval);
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07003110 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003111 case FM_OFF:
Anantha Krishnanf950e322012-06-06 14:25:49 +05303112 radio->spur_table_size = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003113 switch (radio->mode) {
3114 case FM_RECV:
3115 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
3116 radio->fm_hdev);
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05303117 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003118 FMDERR("Err on disable recv FM"
3119 " %d\n", retval);
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05303120 return retval;
3121 }
3122 radio->mode = FM_OFF;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003123 break;
3124 case FM_TRANS:
3125 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
3126 radio->fm_hdev);
3127
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05303128 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003129 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07003130 " %d\n", retval);
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05303131 return retval;
3132 }
3133 radio->mode = FM_OFF;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003134 break;
3135 default:
3136 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05303138 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003139 default:
3140 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003141 }
3142 break;
3143 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003144 if (radio->mode == FM_RECV) {
3145 retval = iris_recv_set_region(radio, ctrl->value);
3146 } else {
3147 if (radio->mode == FM_TRANS)
3148 retval = iris_trans_set_region(radio,
3149 ctrl->value);
3150 else
3151 retval = -EINVAL;
3152 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003153 break;
3154 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
3155 temp_val = ctrl->value;
3156 retval = hci_fm_set_signal_threshold(
3157 &temp_val,
3158 radio->fm_hdev);
3159 if (retval < 0) {
3160 FMDERR("Error while setting signal threshold\n");
3161 break;
3162 }
3163 break;
3164 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
3165 radio->srch_rds.srch_pty = ctrl->value;
3166 radio->srch_st_list.srch_pty = ctrl->value;
3167 break;
3168 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
3169 radio->srch_rds.srch_pi = ctrl->value;
3170 break;
3171 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Ayaz Ahmad7ba5c1c2012-11-20 14:55:15 +05303172 radio->srch_st_list.srch_list_max = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003173 break;
3174 case V4L2_CID_PRIVATE_IRIS_SPACING:
Venkateshwarlu Domakonda45496f12011-11-23 12:51:13 +05303175 if (radio->mode == FM_RECV) {
3176 radio->recv_conf.ch_spacing = ctrl->value;
3177 retval = hci_set_fm_recv_conf(
3178 &radio->recv_conf,
3179 radio->fm_hdev);
3180 if (retval < 0)
3181 FMDERR("Error in setting channel spacing");
3182 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003183 break;
3184 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003185 switch (radio->mode) {
3186 case FM_RECV:
3187 radio->recv_conf.emphasis = ctrl->value;
3188 retval = hci_set_fm_recv_conf(
3189 &radio->recv_conf,
3190 radio->fm_hdev);
3191 if (retval < 0)
3192 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07003193 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003194 case FM_TRANS:
3195 radio->trans_conf.emphasis = ctrl->value;
3196 retval = hci_set_fm_trans_conf(
3197 &radio->trans_conf,
3198 radio->fm_hdev);
3199 if (retval < 0)
3200 FMDERR("Error in setting emphasis");
3201 break;
3202 default:
3203 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003204 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003205 break;
3206 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003207 switch (radio->mode) {
3208 case FM_RECV:
3209 radio->recv_conf.rds_std = ctrl->value;
3210 retval = hci_set_fm_recv_conf(
3211 &radio->recv_conf,
3212 radio->fm_hdev);
3213 if (retval < 0)
3214 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07003215 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003216 case FM_TRANS:
3217 radio->trans_conf.rds_std = ctrl->value;
3218 retval = hci_set_fm_trans_conf(
3219 &radio->trans_conf,
3220 radio->fm_hdev);
3221 if (retval < 0)
3222 FMDERR("Error in rds_Std");
3223 break;
3224 default:
3225 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003226 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003227 break;
3228 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003229 switch (radio->mode) {
3230 case FM_RECV:
3231 radio->recv_conf.rds_std = ctrl->value;
3232 retval = hci_set_fm_recv_conf(
3233 &radio->recv_conf,
3234 radio->fm_hdev);
3235 if (retval < 0)
3236 FMDERR("Error in rds_std");
3237 break;
3238 case FM_TRANS:
3239 radio->trans_conf.rds_std = ctrl->value;
3240 retval = hci_set_fm_trans_conf(
3241 &radio->trans_conf,
3242 radio->fm_hdev);
3243 if (retval < 0)
3244 FMDERR("Error in rds_Std");
3245 break;
3246 default:
3247 retval = -EINVAL;
3248 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003249 break;
3250 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
Ayaz Ahmad89265112012-10-05 19:39:11 +05303251 grp_mask = (grp_mask | oda_agt | ctrl->value);
3252 radio->rds_grp.rds_grp_enable_mask = grp_mask;
3253 radio->rds_grp.rds_buf_size = 1;
3254 radio->rds_grp.en_rds_change_filter = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003255 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
Ayaz Ahmad89265112012-10-05 19:39:11 +05303256 if (retval < 0)
3257 FMDERR("error in setting group mask\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003258 break;
3259 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
3260 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07003261 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003262 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07003263 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003264 radio->fm_hdev);
3265 break;
3266 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
3267 radio->rds_grp.rds_buf_size = ctrl->value;
3268 break;
3269 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07003270 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
3271 radio->g_rds_grp_proc_ps |= rds_grps_proc;
3272 retval = hci_fm_rds_grps_process(
3273 &radio->g_rds_grp_proc_ps,
3274 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003275 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303276 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
Srinivasa Rao Uppala1da1a242012-01-11 11:00:10 +05303277 /*Clear the current AF jump settings*/
3278 radio->g_rds_grp_proc_ps &= ~(1 << RDS_AF_JUMP_OFFSET);
3279 radio->af_jump_bit = ctrl->value;
3280 rds_grps_proc = 0x00;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303281 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_OFFSET);
3282 radio->g_rds_grp_proc_ps |= rds_grps_proc;
3283 retval = hci_fm_rds_grps_process(
3284 &radio->g_rds_grp_proc_ps,
3285 radio->fm_hdev);
3286 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003287 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05303288 set_low_power_mode(radio, ctrl->value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289 break;
3290 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
3291 temp_val = ctrl->value;
3292 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
Srinivasa Rao Uppala2f51a972012-01-23 20:11:13 +05303293 if (retval < 0) {
3294 FMDERR("Set Antenna failed retval = %x", retval);
3295 return retval;
3296 }
3297 radio->g_antenna = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003298 break;
3299 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003300 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301 break;
3302 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003303 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003304 break;
3305 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303306 tx_ps.ps_control = 0x00;
3307 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
3308 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003309 break;
3310 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303311 tx_rt.rt_control = 0x00;
3312 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
3313 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003314 break;
3315 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003316 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003317 break;
3318 case V4L2_CID_TUNE_POWER_LEVEL:
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05303319 if (ctrl->value > FM_TX_PWR_LVL_MAX)
3320 ctrl->value = FM_TX_PWR_LVL_MAX;
3321 if (ctrl->value < FM_TX_PWR_LVL_0)
3322 ctrl->value = FM_TX_PWR_LVL_0;
3323 rd_txgain.mode = FM_TX_PHY_CFG_MODE;
3324 rd_txgain.length = FM_TX_PHY_CFG_LEN;
3325 rd_txgain.param_len = 0x00;
3326 rd_txgain.param = 0x00;
3327
3328 retval = hci_def_data_read(&rd_txgain, radio->fm_hdev);
3329 if (retval < 0) {
3330 FMDERR("Default data read failed for PHY_CFG %d\n",
3331 retval);
3332 break;
3333 }
3334 memset(&wr_txgain, 0, sizeof(wr_txgain));
3335 wr_txgain.mode = FM_TX_PHY_CFG_MODE;
3336 wr_txgain.length = FM_TX_PHY_CFG_LEN;
3337 memcpy(&wr_txgain.data, &radio->default_data.data,
3338 radio->default_data.ret_data_len);
3339 wr_txgain.data[FM_TX_PWR_GAIN_OFFSET] =
3340 (ctrl->value) * FM_TX_PWR_LVL_STEP_SIZE;
3341 retval = hci_def_data_write(&wr_txgain, radio->fm_hdev);
3342 if (retval < 0)
3343 FMDERR("Default write failed for PHY_TXGAIN %d\n",
3344 retval);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003345 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07003346 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
3347 radio->mute_mode.soft_mute = ctrl->value;
3348 retval = hci_set_fm_mute_mode(
3349 &radio->mute_mode,
3350 radio->fm_hdev);
3351 if (retval < 0)
3352 FMDERR("Error while setting FM soft mute"" %d\n",
3353 retval);
3354 break;
3355 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
3356 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
3357 break;
3358 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
3359 radio->riva_data_req.cmd_params.length = ctrl->value;
3360 break;
3361 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
3362 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
3363 radio->riva_data_req.cmd_params.length);
3364 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
3365 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
3366 break;
3367 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
3368 radio->ssbi_data_accs.start_addr = ctrl->value;
3369 break;
3370 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
3371 radio->ssbi_data_accs.data = ctrl->value;
3372 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
3373 radio->fm_hdev);
3374 break;
3375 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
3376 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
3377 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
3378 radio->fm_hdev);
3379 break;
3380 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
3381 radio->ssbi_peek_reg.start_address = ctrl->value;
3382 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
3383 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05303384 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
3385 temp_val = ctrl->value;
3386 hci_read_grp_counters(&temp_val, radio->fm_hdev);
3387 break;
3388 case V4L2_CID_PRIVATE_IRIS_HLSI:
3389 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
3390 radio->fm_hdev);
3391 if (retval)
3392 break;
3393 radio->recv_conf.hlsi = ctrl->value;
3394 retval = hci_set_fm_recv_conf(
3395 &radio->recv_conf,
3396 radio->fm_hdev);
3397 break;
3398 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
3399 temp_val = ctrl->value;
3400 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
3401 break;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05303402 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
3403 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3404 if (retval < 0) {
3405 FMDERR("Failed to get chnl det thresholds %d", retval);
3406 return retval;
3407 }
3408 radio->ch_det_threshold.high_th = ctrl->value;
3409 retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
3410 radio->fm_hdev);
3411 if (retval < 0) {
3412 FMDERR("Failed to set High det threshold %d ", retval);
3413 return retval;
3414 }
3415 break;
3416
3417 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
3418 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3419 if (retval < 0) {
3420 FMDERR("Failed to get chnl det thresholds %d", retval);
3421 return retval;
3422 }
3423 radio->ch_det_threshold.low_th = ctrl->value;
3424 retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
3425 radio->fm_hdev);
3426 if (retval < 0) {
3427 FMDERR("Failed to Set Low det threshold %d", retval);
3428 return retval;
3429 }
3430 break;
3431
3432 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
3433 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3434 if (retval < 0) {
3435 FMDERR("Failed to get chnl det thresholds %d", retval);
3436 return retval;
3437 }
3438 radio->ch_det_threshold.sinr = ctrl->value;
3439 retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
3440 radio->fm_hdev);
3441 if (retval < 0) {
3442 FMDERR("Failed to set SINR threshold %d", retval);
3443 return retval;
3444 }
3445 break;
3446
3447 case V4L2_CID_PRIVATE_SINR_SAMPLES:
3448 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3449 if (retval < 0) {
3450 FMDERR("Failed to get chnl det thresholds %d", retval);
3451 return retval;
3452 }
3453 radio->ch_det_threshold.sinr_samples = ctrl->value;
3454 retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
3455 radio->fm_hdev);
3456 if (retval < 0) {
3457 FMDERR("Failed to set SINR samples %d", retval);
3458 return retval;
3459 }
3460 break;
3461
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05303462 case V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM:
Srinivasa Rao Uppalade0b5d92011-12-27 18:09:10 +05303463 case V4L2_CID_PRIVATE_IRIS_SET_AUDIO_PATH:
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05303464 /*
Srinivasa Rao Uppalade0b5d92011-12-27 18:09:10 +05303465 These private controls are place holders to keep the
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05303466 driver compatible with changes done in the frameworks
3467 which are specific to TAVARUA.
3468 */
3469 retval = 0;
3470 break;
Anantha Krishnanf950e322012-06-06 14:25:49 +05303471 case V4L2_CID_PRIVATE_SPUR_FREQ:
3472 if (radio->spur_table_size >= MAX_SPUR_FREQ_LIMIT) {
3473 FMDERR("%s: Spur Table Full!\n", __func__);
3474 retval = -1;
3475 } else
3476 radio->spur_data.freq[radio->spur_table_size] =
3477 ctrl->value;
3478 break;
3479 case V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI:
3480 if (radio->spur_table_size >= MAX_SPUR_FREQ_LIMIT) {
3481 FMDERR("%s: Spur Table Full!\n", __func__);
3482 retval = -1;
3483 } else
3484 radio->spur_data.rmssi[radio->spur_table_size] =
3485 ctrl->value;
3486 break;
3487 case V4L2_CID_PRIVATE_SPUR_SELECTION:
3488 if (radio->spur_table_size >= MAX_SPUR_FREQ_LIMIT) {
3489 FMDERR("%s: Spur Table Full!\n", __func__);
3490 retval = -1;
3491 } else {
3492 radio->spur_data.enable[radio->spur_table_size] =
3493 ctrl->value;
3494 radio->spur_table_size++;
3495 }
3496 break;
3497 case V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE:
3498 update_spur_table(radio);
3499 break;
Ayaz Ahmad37294ba2012-07-10 16:38:11 +05303500 case V4L2_CID_PRIVATE_VALID_CHANNEL:
3501 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3502 if (retval < 0) {
3503 FMDERR("%s: Failed to determine channel's validity\n",
3504 __func__);
3505 return retval;
3506 } else {
3507 sinr_th = radio->ch_det_threshold.sinr;
3508 intf_det_low_th = radio->ch_det_threshold.low_th;
3509 intf_det_high_th = radio->ch_det_threshold.high_th;
3510 }
3511
3512 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3513 if (retval < 0) {
3514 FMDERR("%s: Failed to determine channel's validity\n",
3515 __func__);
3516 return retval;
3517 } else
3518 sinr = radio->fm_st_rsp.station_rsp.sinr;
3519
3520 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
3521 if (retval < 0) {
3522 FMDERR("%s: Failed to determine channel's validity\n",
3523 __func__);
3524 return retval;
3525 } else
3526 intf_det_out = radio->st_dbg_param.in_det_out;
3527
3528 if ((sinr >= sinr_th) && (intf_det_out >= intf_det_low_th) &&
3529 (intf_det_out <= intf_det_high_th))
3530 radio->is_station_valid = VALID_CHANNEL;
3531 else
3532 radio->is_station_valid = INVALID_CHANNEL;
3533 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003534 default:
3535 retval = -EINVAL;
3536 }
3537 return retval;
3538}
3539
Anantha Krishnanf950e322012-06-06 14:25:49 +05303540static int update_spur_table(struct iris_device *radio)
3541{
3542 struct hci_fm_def_data_wr_req default_data;
3543 int len = 0, index = 0, offset = 0, i = 0;
3544 int retval = 0, temp = 0, cnt = 0;
3545
3546 memset(&default_data, 0, sizeof(default_data));
3547
3548 /* Pass the mode of SPUR_CLK */
3549 default_data.mode = CKK_SPUR;
3550
3551 temp = radio->spur_table_size;
3552 for (cnt = 0; cnt < (temp / 5); cnt++) {
3553 offset = 0;
3554 /*
3555 * Program the spur entries in spur table in following order:
3556 * Spur index
3557 * Length of the spur data
3558 * Spur Data:
3559 * MSB of the spur frequency
3560 * LSB of the spur frequency
3561 * Enable/Disable the spur frequency
3562 * RMSSI value of the spur frequency
3563 */
3564 default_data.data[offset++] = ENTRY_0 + cnt;
3565 for (i = 0; i < SPUR_ENTRIES_PER_ID; i++) {
3566 default_data.data[offset++] = GET_FREQ(COMPUTE_SPUR(
3567 radio->spur_data.freq[index]), 0);
3568 default_data.data[offset++] = GET_FREQ(COMPUTE_SPUR(
3569 radio->spur_data.freq[index]), 1);
3570 default_data.data[offset++] =
3571 radio->spur_data.enable[index];
3572 default_data.data[offset++] =
3573 radio->spur_data.rmssi[index];
3574 index++;
3575 }
3576 len = (SPUR_ENTRIES_PER_ID * SPUR_DATA_SIZE);
3577 default_data.length = (len + 1);
3578 retval = hci_def_data_write(&default_data, radio->fm_hdev);
3579 if (retval < 0) {
3580 FMDBG("%s: Failed to configure entries for ID : %d\n",
3581 __func__, default_data.data[0]);
3582 return retval;
3583 }
3584 }
3585
3586 /* Compute balance SPUR frequencies to be programmed */
3587 temp %= SPUR_ENTRIES_PER_ID;
3588 if (temp > 0) {
3589 offset = 0;
3590 default_data.data[offset++] = (radio->spur_table_size / 5);
3591 for (i = 0; i < temp; i++) {
3592 default_data.data[offset++] = GET_FREQ(COMPUTE_SPUR(
3593 radio->spur_data.freq[index]), 0);
3594 default_data.data[offset++] = GET_FREQ(COMPUTE_SPUR(
3595 radio->spur_data.freq[index]), 1);
3596 default_data.data[offset++] =
3597 radio->spur_data.enable[index];
3598 default_data.data[offset++] =
3599 radio->spur_data.rmssi[index];
3600 index++;
3601 }
3602 len = (temp * SPUR_DATA_SIZE);
3603 default_data.length = (len + 1);
3604 retval = hci_def_data_write(&default_data, radio->fm_hdev);
3605 if (retval < 0) {
3606 FMDERR("%s: Failed to configure entries for ID : %d\n",
3607 __func__, default_data.data[0]);
3608 return retval;
3609 }
3610 }
3611
3612 return retval;
3613}
3614
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003615static int iris_vidioc_g_tuner(struct file *file, void *priv,
3616 struct v4l2_tuner *tuner)
3617{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003618 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003619 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003620
Srinivasa Rao Uppalad2ec4682011-12-12 14:02:15 +05303621 if (tuner->index > 0) {
3622 FMDERR("Invalid Tuner Index");
3623 return -EINVAL;
3624 }
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303625 if (radio->mode == FM_RECV) {
3626 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3627 if (retval < 0) {
3628 FMDERR("Failed to Get station params");
3629 return retval;
3630 }
3631 tuner->type = V4L2_TUNER_RADIO;
3632 tuner->rangelow =
3633 radio->recv_conf.band_low_limit * TUNE_PARAM;
3634 tuner->rangehigh =
3635 radio->recv_conf.band_high_limit * TUNE_PARAM;
3636 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
3637 tuner->capability = V4L2_TUNER_CAP_LOW;
3638 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
3639 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
3640 tuner->afc = 0;
3641 } else if (radio->mode == FM_TRANS) {
3642 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
3643 if (retval < 0) {
3644 FMDERR("get Tx config failed %d\n", retval);
3645 return retval;
3646 } else {
3647 tuner->type = V4L2_TUNER_RADIO;
3648 tuner->rangelow =
3649 radio->trans_conf.band_low_limit * TUNE_PARAM;
3650 tuner->rangehigh =
3651 radio->trans_conf.band_high_limit * TUNE_PARAM;
3652 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003653
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303654 } else
3655 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656 return 0;
3657}
3658
3659static int iris_vidioc_s_tuner(struct file *file, void *priv,
3660 struct v4l2_tuner *tuner)
3661{
3662 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07003663 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003664 if (tuner->index > 0)
3665 return -EINVAL;
3666
Ankur Nandwanid928d542011-08-11 13:15:41 -07003667 if (radio->mode == FM_RECV) {
3668 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
3669 radio->recv_conf.band_high_limit =
3670 tuner->rangehigh / TUNE_PARAM;
3671 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
3672 radio->stereo_mode.stereo_mode = 0x01;
3673 retval = hci_set_fm_stereo_mode(
3674 &radio->stereo_mode,
3675 radio->fm_hdev);
3676 } else {
3677 radio->stereo_mode.stereo_mode = 0x00;
3678 retval = hci_set_fm_stereo_mode(
3679 &radio->stereo_mode,
3680 radio->fm_hdev);
3681 }
3682 if (retval < 0)
3683 FMDERR(": set tuner failed with %d\n", retval);
3684 return retval;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303685 } else if (radio->mode == FM_TRANS) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003686 radio->trans_conf.band_low_limit =
3687 tuner->rangelow / TUNE_PARAM;
3688 radio->trans_conf.band_high_limit =
3689 tuner->rangehigh / TUNE_PARAM;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303690 } else
3691 return -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003692
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003693 return retval;
3694}
3695
3696static int iris_vidioc_g_frequency(struct file *file, void *priv,
3697 struct v4l2_frequency *freq)
3698{
3699 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Srinivasa Rao Uppalad2ec4682011-12-12 14:02:15 +05303700 if ((freq != NULL) && (radio != NULL)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003701 freq->frequency =
3702 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
Srinivasa Rao Uppalad2ec4682011-12-12 14:02:15 +05303703 } else
3704 return -EINVAL;
3705 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003706}
3707
3708static int iris_vidioc_s_frequency(struct file *file, void *priv,
3709 struct v4l2_frequency *freq)
3710{
3711 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3712 int retval = -1;
3713 freq->frequency = freq->frequency / TUNE_PARAM;
3714
3715 if (freq->type != V4L2_TUNER_RADIO)
3716 return -EINVAL;
3717
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003718 /* We turn off RDS prior to tuning to a new station.
3719 because of a bug in SoC which prevents tuning
3720 during RDS transmission.
3721 */
3722 if (radio->mode == FM_TRANS
3723 && (radio->trans_conf.rds_std == 0 ||
3724 radio->trans_conf.rds_std == 1)) {
3725 radio->prev_trans_rds = radio->trans_conf.rds_std;
3726 radio->trans_conf.rds_std = 2;
3727 hci_set_fm_trans_conf(&radio->trans_conf,
3728 radio->fm_hdev);
3729 }
3730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003731 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003732
3733 if (radio->mode == FM_TRANS
3734 && radio->trans_conf.rds_std == 2
3735 && (radio->prev_trans_rds == 1
3736 || radio->prev_trans_rds == 0)) {
3737 radio->trans_conf.rds_std = radio->prev_trans_rds;
3738 hci_set_fm_trans_conf(&radio->trans_conf,
3739 radio->fm_hdev);
3740 }
3741
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003742 if (retval < 0)
3743 FMDERR(" set frequency failed with %d\n", retval);
3744 return retval;
3745}
3746
3747static int iris_vidioc_dqbuf(struct file *file, void *priv,
3748 struct v4l2_buffer *buffer)
3749{
3750 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Venkateshwarlu Domakonda7f095c42012-05-30 15:31:38 +05303751 enum iris_buf_t buf_type = -1;
3752 unsigned char buf_fifo[STD_BUF_SIZE] = {0};
3753 struct kfifo *data_fifo = NULL;
3754 unsigned char *buf = NULL;
3755 unsigned int len = 0, retval = -1;
3756
3757 if ((radio == NULL) || (buffer == NULL)) {
3758 FMDERR("radio/buffer is NULL\n");
3759 return -ENXIO;
3760 }
3761 buf_type = buffer->index;
3762 buf = (unsigned char *)buffer->m.userptr;
3763 len = buffer->length;
3764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003765 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
3766 data_fifo = &radio->data_buf[buf_type];
3767 if (buf_type == IRIS_BUF_EVENTS)
3768 if (wait_event_interruptible(radio->event_queue,
3769 kfifo_len(data_fifo)) < 0)
3770 return -EINTR;
3771 } else {
3772 FMDERR("invalid buffer type\n");
3773 return -EINVAL;
3774 }
Venkateshwarlu Domakonda7f095c42012-05-30 15:31:38 +05303775 if (len <= STD_BUF_SIZE) {
3776 buffer->bytesused = kfifo_out_locked(data_fifo, &buf_fifo[0],
3777 len, &radio->buf_lock[buf_type]);
3778 } else {
3779 FMDERR("kfifo_out_locked can not use len more than 128\n");
3780 return -EINVAL;
3781 }
3782 retval = copy_to_user(buf, &buf_fifo[0], buffer->bytesused);
3783 if (retval > 0) {
3784 FMDERR("Failed to copy %d bytes of data\n", retval);
3785 return -EAGAIN;
3786 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003787
Venkateshwarlu Domakonda7f095c42012-05-30 15:31:38 +05303788 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003789}
3790
3791static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
3792 struct v4l2_format *f)
3793{
3794 return 0;
3795
3796}
3797
3798static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3799 struct v4l2_hw_freq_seek *seek)
3800{
3801 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Anantha Krishnand7b5a772012-04-30 04:21:03 -07003802 int dir;
3803 if (seek->seek_upward)
3804 dir = SRCH_DIR_UP;
3805 else
3806 dir = SRCH_DIR_DOWN;
3807 return iris_search(radio, CTRL_ON, dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003808}
3809
3810static int iris_vidioc_querycap(struct file *file, void *priv,
3811 struct v4l2_capability *capability)
3812{
3813 struct iris_device *radio;
3814 radio = video_get_drvdata(video_devdata(file));
3815 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
3816 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
3817 radio->g_cap = capability;
3818 return 0;
3819}
3820
3821
3822static const struct v4l2_ioctl_ops iris_ioctl_ops = {
3823 .vidioc_querycap = iris_vidioc_querycap,
3824 .vidioc_queryctrl = iris_vidioc_queryctrl,
3825 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
3826 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
3827 .vidioc_g_tuner = iris_vidioc_g_tuner,
3828 .vidioc_s_tuner = iris_vidioc_s_tuner,
3829 .vidioc_g_frequency = iris_vidioc_g_frequency,
3830 .vidioc_s_frequency = iris_vidioc_s_frequency,
3831 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
3832 .vidioc_dqbuf = iris_vidioc_dqbuf,
3833 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
3834 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303835 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003836};
3837
3838static const struct v4l2_file_operations iris_fops = {
3839 .owner = THIS_MODULE,
3840 .unlocked_ioctl = video_ioctl2,
3841};
3842
3843static struct video_device iris_viddev_template = {
3844 .fops = &iris_fops,
3845 .ioctl_ops = &iris_ioctl_ops,
3846 .name = DRIVER_NAME,
3847 .release = video_device_release,
3848};
3849
3850static struct video_device *video_get_dev(void)
3851{
3852 return priv_videodev;
3853}
3854
3855static int __init iris_probe(struct platform_device *pdev)
3856{
3857 struct iris_device *radio;
3858 int retval;
3859 int radio_nr = -1;
3860 int i;
3861
3862 if (!pdev) {
3863 FMDERR(": pdev is null\n");
3864 return -ENOMEM;
3865 }
3866
3867 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
3868 if (!radio) {
3869 FMDERR(": Could not allocate radio device\n");
3870 return -ENOMEM;
3871 }
3872
3873 radio->dev = &pdev->dev;
3874 platform_set_drvdata(pdev, radio);
3875
3876 radio->videodev = video_device_alloc();
3877 if (!radio->videodev) {
3878 FMDERR(": Could not allocate V4L device\n");
3879 kfree(radio);
3880 return -ENOMEM;
3881 }
3882
3883 memcpy(radio->videodev, &iris_viddev_template,
3884 sizeof(iris_viddev_template));
3885
3886 for (i = 0; i < IRIS_BUF_MAX; i++) {
3887 int kfifo_alloc_rc = 0;
3888 spin_lock_init(&radio->buf_lock[i]);
3889
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07003890 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003891 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3892 rds_buf*3, GFP_KERNEL);
Srinivasa Rao Uppala69839842012-01-13 18:36:12 +05303893 else if ((i == IRIS_BUF_CAL_DATA) || (i == IRIS_BUF_RT_RDS))
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05303894 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3895 STD_BUF_SIZE*2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003896 else
3897 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3898 STD_BUF_SIZE, GFP_KERNEL);
3899
3900 if (kfifo_alloc_rc != 0) {
3901 FMDERR("failed allocating buffers %d\n",
3902 kfifo_alloc_rc);
3903 for (; i > -1; i--) {
3904 kfifo_free(&radio->data_buf[i]);
3905 kfree(radio);
3906 return -ENOMEM;
3907 }
3908 }
3909 }
3910
3911 mutex_init(&radio->lock);
3912 init_completion(&radio->sync_xfr_start);
3913 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003914 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003915 init_waitqueue_head(&radio->event_queue);
3916 init_waitqueue_head(&radio->read_queue);
3917
3918 video_set_drvdata(radio->videodev, radio);
3919
3920 if (NULL == video_get_drvdata(radio->videodev))
3921 FMDERR(": video_get_drvdata failed\n");
3922
3923 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
3924 radio_nr);
3925 if (retval) {
3926 FMDERR(": Could not register video device\n");
3927 video_device_release(radio->videodev);
3928 for (; i > -1; i--)
3929 kfifo_free(&radio->data_buf[i]);
3930 kfree(radio);
3931 return retval;
3932 } else {
3933 priv_videodev = kzalloc(sizeof(struct video_device),
3934 GFP_KERNEL);
3935 memcpy(priv_videodev, radio->videodev,
3936 sizeof(struct video_device));
3937 }
3938 return 0;
3939}
3940
3941
3942static int __devexit iris_remove(struct platform_device *pdev)
3943{
3944 int i;
3945 struct iris_device *radio = platform_get_drvdata(pdev);
3946
3947 video_unregister_device(radio->videodev);
3948
3949 for (i = 0; i < IRIS_BUF_MAX; i++)
3950 kfifo_free(&radio->data_buf[i]);
3951
3952 kfree(radio);
3953
3954 platform_set_drvdata(pdev, NULL);
3955
3956 return 0;
3957}
3958
3959static struct platform_driver iris_driver = {
3960 .driver = {
3961 .owner = THIS_MODULE,
3962 .name = "iris_fm",
3963 },
3964 .remove = __devexit_p(iris_remove),
3965};
3966
3967static int __init iris_radio_init(void)
3968{
3969 return platform_driver_probe(&iris_driver, iris_probe);
3970}
3971module_init(iris_radio_init);
3972
3973static void __exit iris_radio_exit(void)
3974{
3975 platform_driver_unregister(&iris_driver);
3976}
3977module_exit(iris_radio_exit);
3978
3979MODULE_LICENSE("GPL v2");
3980MODULE_AUTHOR(DRIVER_AUTHOR);
3981MODULE_DESCRIPTION(DRIVER_DESC);