blob: 5ed2ad7fb651714f00e004118496d6c51328a7fc [file] [log] [blame]
Srinivasa Rao Uppala69839842012-01-13 18:36:12 +05301/* Copyright (c) 2011-2012, Code Aurora Forum. 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>
27#include <linux/version.h>
28#include <linux/videodev2.h>
29#include <linux/mutex.h>
30#include <linux/unistd.h>
31#include <linux/atomic.h>
32#include <linux/platform_device.h>
33#include <linux/workqueue.h>
34#include <linux/slab.h>
35#include <media/v4l2-common.h>
36#include <media/v4l2-ioctl.h>
37#include <media/radio-iris.h>
38#include <asm/unaligned.h>
39
40static unsigned int rds_buf = 100;
41module_param(rds_buf, uint, 0);
42MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
43
44static void radio_hci_cmd_task(unsigned long arg);
45static void radio_hci_rx_task(unsigned long arg);
46static struct video_device *video_get_dev(void);
47static DEFINE_RWLOCK(hci_task_lock);
48
49struct iris_device {
50 struct device *dev;
51 struct kfifo data_buf[IRIS_BUF_MAX];
52
53 int pending_xfrs[IRIS_XFR_MAX];
54 int xfr_bytes_left;
55 int xfr_in_progress;
56 struct completion sync_xfr_start;
57 int tune_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -070058 unsigned int mode;
59
60 __u16 pi;
61 __u8 pty;
62 __u8 ps_repeatcount;
Ankur Nandwani8f972e52011-08-24 11:48:32 -070063 __u8 prev_trans_rds;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064
65 struct video_device *videodev;
66
67 struct mutex lock;
68 spinlock_t buf_lock[IRIS_BUF_MAX];
69 wait_queue_head_t event_queue;
70 wait_queue_head_t read_queue;
71
72 struct radio_hci_dev *fm_hdev;
73
74 struct v4l2_capability *g_cap;
75 struct v4l2_control *g_ctl;
76
77 struct hci_fm_mute_mode_req mute_mode;
78 struct hci_fm_stereo_mode_req stereo_mode;
79 struct hci_fm_station_rsp fm_st_rsp;
80 struct hci_fm_search_station_req srch_st;
81 struct hci_fm_search_rds_station_req srch_rds;
82 struct hci_fm_search_station_list_req srch_st_list;
83 struct hci_fm_recv_conf_req recv_conf;
Ankur Nandwanid928d542011-08-11 13:15:41 -070084 struct hci_fm_trans_conf_req_struct trans_conf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085 struct hci_fm_rds_grp_req rds_grp;
86 unsigned char g_search_mode;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +053087 unsigned char power_mode;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +053088 int search_on;
Ankur Nandwanid928d542011-08-11 13:15:41 -070089 unsigned int tone_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070090 unsigned char g_scan_time;
91 unsigned int g_antenna;
92 unsigned int g_rds_grp_proc_ps;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +053093 unsigned char event_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 enum iris_region_t region;
95 struct hci_fm_dbg_param_rsp st_dbg_param;
96 struct hci_ev_srch_list_compl srch_st_result;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -070097 struct hci_fm_riva_poke riva_data_req;
98 struct hci_fm_ssbi_req ssbi_data_accs;
99 struct hci_fm_ssbi_peek ssbi_peek_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100};
101
102static struct video_device *priv_videodev;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530103static int iris_do_calibration(struct iris_device *radio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700104
105static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
106 {
107 .id = V4L2_CID_AUDIO_VOLUME,
108 .type = V4L2_CTRL_TYPE_INTEGER,
109 .name = "Volume",
110 .minimum = 0,
111 .maximum = 15,
112 .step = 1,
113 .default_value = 15,
114 },
115 {
116 .id = V4L2_CID_AUDIO_BALANCE,
117 .flags = V4L2_CTRL_FLAG_DISABLED,
118 },
119 {
120 .id = V4L2_CID_AUDIO_BASS,
121 .flags = V4L2_CTRL_FLAG_DISABLED,
122 },
123 {
124 .id = V4L2_CID_AUDIO_TREBLE,
125 .flags = V4L2_CTRL_FLAG_DISABLED,
126 },
127 {
128 .id = V4L2_CID_AUDIO_MUTE,
129 .type = V4L2_CTRL_TYPE_BOOLEAN,
130 .name = "Mute",
131 .minimum = 0,
132 .maximum = 1,
133 .step = 1,
134 .default_value = 1,
135 },
136 {
137 .id = V4L2_CID_AUDIO_LOUDNESS,
138 .flags = V4L2_CTRL_FLAG_DISABLED,
139 },
140 {
141 .id = V4L2_CID_PRIVATE_IRIS_SRCHMODE,
142 .type = V4L2_CTRL_TYPE_INTEGER,
143 .name = "Search mode",
144 .minimum = 0,
145 .maximum = 7,
146 .step = 1,
147 .default_value = 0,
148 },
149 {
150 .id = V4L2_CID_PRIVATE_IRIS_SCANDWELL,
151 .type = V4L2_CTRL_TYPE_INTEGER,
152 .name = "Search dwell time",
153 .minimum = 0,
154 .maximum = 7,
155 .step = 1,
156 .default_value = 0,
157 },
158 {
159 .id = V4L2_CID_PRIVATE_IRIS_SRCHON,
160 .type = V4L2_CTRL_TYPE_BOOLEAN,
161 .name = "Search on/off",
162 .minimum = 0,
163 .maximum = 1,
164 .step = 1,
165 .default_value = 1,
166
167 },
168 {
169 .id = V4L2_CID_PRIVATE_IRIS_STATE,
170 .type = V4L2_CTRL_TYPE_INTEGER,
171 .name = "radio 0ff/rx/tx/reset",
172 .minimum = 0,
173 .maximum = 3,
174 .step = 1,
175 .default_value = 1,
176
177 },
178 {
179 .id = V4L2_CID_PRIVATE_IRIS_REGION,
180 .type = V4L2_CTRL_TYPE_INTEGER,
181 .name = "radio standard",
182 .minimum = 0,
183 .maximum = 2,
184 .step = 1,
185 .default_value = 0,
186 },
187 {
188 .id = V4L2_CID_PRIVATE_IRIS_SIGNAL_TH,
189 .type = V4L2_CTRL_TYPE_INTEGER,
190 .name = "Signal Threshold",
191 .minimum = 0x80,
192 .maximum = 0x7F,
193 .step = 1,
194 .default_value = 0,
195 },
196 {
197 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PTY,
198 .type = V4L2_CTRL_TYPE_INTEGER,
199 .name = "Search PTY",
200 .minimum = 0,
201 .maximum = 31,
202 .default_value = 0,
203 },
204 {
205 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PI,
206 .type = V4L2_CTRL_TYPE_INTEGER,
207 .name = "Search PI",
208 .minimum = 0,
209 .maximum = 0xFF,
210 .default_value = 0,
211 },
212 {
213 .id = V4L2_CID_PRIVATE_IRIS_SRCH_CNT,
214 .type = V4L2_CTRL_TYPE_INTEGER,
215 .name = "Preset num",
216 .minimum = 0,
217 .maximum = 12,
218 .default_value = 0,
219 },
220 {
221 .id = V4L2_CID_PRIVATE_IRIS_EMPHASIS,
222 .type = V4L2_CTRL_TYPE_BOOLEAN,
223 .name = "Emphasis",
224 .minimum = 0,
225 .maximum = 1,
226 .default_value = 0,
227 },
228 {
229 .id = V4L2_CID_PRIVATE_IRIS_RDS_STD,
230 .type = V4L2_CTRL_TYPE_BOOLEAN,
231 .name = "RDS standard",
232 .minimum = 0,
233 .maximum = 1,
234 .default_value = 0,
235 },
236 {
237 .id = V4L2_CID_PRIVATE_IRIS_SPACING,
238 .type = V4L2_CTRL_TYPE_INTEGER,
239 .name = "Channel spacing",
240 .minimum = 0,
241 .maximum = 2,
242 .default_value = 0,
243 },
244 {
245 .id = V4L2_CID_PRIVATE_IRIS_RDSON,
246 .type = V4L2_CTRL_TYPE_BOOLEAN,
247 .name = "RDS on/off",
248 .minimum = 0,
249 .maximum = 1,
250 .default_value = 0,
251 },
252 {
253 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK,
254 .type = V4L2_CTRL_TYPE_INTEGER,
255 .name = "RDS group mask",
256 .minimum = 0,
257 .maximum = 0xFFFFFFFF,
258 .default_value = 0,
259 },
260 {
261 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC,
262 .type = V4L2_CTRL_TYPE_INTEGER,
263 .name = "RDS processing",
264 .minimum = 0,
265 .maximum = 0xFF,
266 .default_value = 0,
267 },
268 {
269 .id = V4L2_CID_PRIVATE_IRIS_RDSD_BUF,
270 .type = V4L2_CTRL_TYPE_INTEGER,
271 .name = "RDS data groups to buffer",
272 .minimum = 1,
273 .maximum = 21,
274 .default_value = 0,
275 },
276 {
277 .id = V4L2_CID_PRIVATE_IRIS_PSALL,
278 .type = V4L2_CTRL_TYPE_BOOLEAN,
279 .name = "pass all ps strings",
280 .minimum = 0,
281 .maximum = 1,
282 .default_value = 0,
283 },
284 {
285 .id = V4L2_CID_PRIVATE_IRIS_LP_MODE,
286 .type = V4L2_CTRL_TYPE_BOOLEAN,
287 .name = "Low power mode",
288 .minimum = 0,
289 .maximum = 1,
290 .default_value = 0,
291 },
292 {
293 .id = V4L2_CID_PRIVATE_IRIS_ANTENNA,
294 .type = V4L2_CTRL_TYPE_BOOLEAN,
295 .name = "headset/internal",
296 .minimum = 0,
297 .maximum = 1,
298 .default_value = 0,
299 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 {
301 .id = V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT,
302 .type = V4L2_CTRL_TYPE_INTEGER,
303 .name = "Set PS REPEATCOUNT",
304 .minimum = 0,
305 .maximum = 15,
306 },
307 {
308 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME,
309 .type = V4L2_CTRL_TYPE_BOOLEAN,
310 .name = "Stop PS NAME",
311 .minimum = 0,
312 .maximum = 1,
313 },
314 {
315 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT,
316 .type = V4L2_CTRL_TYPE_BOOLEAN,
317 .name = "Stop RT",
318 .minimum = 0,
319 .maximum = 1,
320 },
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700321 {
322 .id = V4L2_CID_PRIVATE_IRIS_SOFT_MUTE,
323 .type = V4L2_CTRL_TYPE_BOOLEAN,
324 .name = "Soft Mute",
325 .minimum = 0,
326 .maximum = 1,
327 },
328 {
329 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR,
330 .type = V4L2_CTRL_TYPE_BOOLEAN,
331 .name = "Riva addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530332 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700333 .maximum = 0x31E0004,
334 },
335 {
336 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN,
337 .type = V4L2_CTRL_TYPE_INTEGER,
338 .name = "Data len",
339 .minimum = 0,
340 .maximum = 0xFF,
341 },
342 {
343 .id = V4L2_CID_PRIVATE_IRIS_RIVA_PEEK,
344 .type = V4L2_CTRL_TYPE_BOOLEAN,
345 .name = "Riva peek",
346 .minimum = 0,
347 .maximum = 1,
348 },
349 {
350 .id = V4L2_CID_PRIVATE_IRIS_RIVA_POKE,
351 .type = V4L2_CTRL_TYPE_INTEGER,
352 .name = "Riva poke",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530353 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700354 .maximum = 0x31E0004,
355 },
356 {
357 .id = V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR,
358 .type = V4L2_CTRL_TYPE_INTEGER,
359 .name = "Ssbi addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530360 .minimum = 0x280,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700361 .maximum = 0x37F,
362 },
363 {
364 .id = V4L2_CID_PRIVATE_IRIS_SSBI_PEEK,
365 .type = V4L2_CTRL_TYPE_INTEGER,
366 .name = "Ssbi peek",
367 .minimum = 0,
368 .maximum = 0x37F,
369 },
370 {
371 .id = V4L2_CID_PRIVATE_IRIS_SSBI_POKE,
372 .type = V4L2_CTRL_TYPE_INTEGER,
373 .name = "ssbi poke",
374 .minimum = 0x01,
375 .maximum = 0xFF,
376 },
377 {
378 .id = V4L2_CID_PRIVATE_IRIS_HLSI,
379 .type = V4L2_CTRL_TYPE_INTEGER,
380 .name = "set hlsi",
381 .minimum = 0,
382 .maximum = 2,
383 },
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530384 {
385 .id = V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS,
386 .type = V4L2_CTRL_TYPE_BOOLEAN,
387 .name = "RDS grp",
388 .minimum = 0,
389 .maximum = 1,
390 },
391 {
392 .id = V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER,
393 .type = V4L2_CTRL_TYPE_INTEGER,
394 .name = "Notch filter",
395 .minimum = 0,
396 .maximum = 2,
397 },
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530398 {
399 .id = V4L2_CID_PRIVATE_IRIS_READ_DEFAULT,
400 .type = V4L2_CTRL_TYPE_INTEGER,
401 .name = "Read default",
402 },
403 {
404 .id = V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT,
405 .type = V4L2_CTRL_TYPE_INTEGER,
406 .name = "Write default",
407 },
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530408 {
409 .id = V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION,
410 .type = V4L2_CTRL_TYPE_BOOLEAN,
411 .name = "SET Calibration",
412 .minimum = 0,
413 .maximum = 1,
414 },
415 {
416 .id = V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION,
417 .type = V4L2_CTRL_TYPE_BOOLEAN,
418 .name = "SET Calibration",
419 .minimum = 0,
420 .maximum = 1,
421 },
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +0530422 {
423 .id = V4L2_CID_PRIVATE_IRIS_GET_SINR,
424 .type = V4L2_CTRL_TYPE_INTEGER,
425 .name = "GET SINR",
426 .minimum = -128,
427 .maximum = 127,
428 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429};
430
431static void iris_q_event(struct iris_device *radio,
432 enum iris_evt_t event)
433{
434 struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
435 unsigned char evt = event;
436 if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
437 wake_up_interruptible(&radio->event_queue);
438}
439
440static int hci_send_frame(struct sk_buff *skb)
441{
442 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
443
444 if (!hdev) {
445 kfree_skb(skb);
446 return -ENODEV;
447 }
448
449 __net_timestamp(skb);
450
451 skb_orphan(skb);
452 return hdev->send(skb);
453}
454
455static void radio_hci_cmd_task(unsigned long arg)
456{
457 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
458 struct sk_buff *skb;
459 if (!(atomic_read(&hdev->cmd_cnt))
460 && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
461 FMDERR("%s command tx timeout", hdev->name);
462 atomic_set(&hdev->cmd_cnt, 1);
463 }
464
465 skb = skb_dequeue(&hdev->cmd_q);
466 if (atomic_read(&hdev->cmd_cnt) && skb) {
467 kfree_skb(hdev->sent_cmd);
468 hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
469 if (hdev->sent_cmd) {
470 atomic_dec(&hdev->cmd_cnt);
471 hci_send_frame(skb);
472 hdev->cmd_last_tx = jiffies;
473 } else {
474 skb_queue_head(&hdev->cmd_q, skb);
475 tasklet_schedule(&hdev->cmd_task);
476 }
477 }
478
479}
480
481static void radio_hci_rx_task(unsigned long arg)
482{
483 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
484 struct sk_buff *skb;
485
486 read_lock(&hci_task_lock);
487
488 skb = skb_dequeue(&hdev->rx_q);
489 radio_hci_event_packet(hdev, skb);
490
491 read_unlock(&hci_task_lock);
492}
493
494int radio_hci_register_dev(struct radio_hci_dev *hdev)
495{
496 struct iris_device *radio = video_get_drvdata(video_get_dev());
497 if (!radio) {
498 FMDERR(":radio is null");
499 return -EINVAL;
500 }
501
502 if (!hdev) {
503 FMDERR("hdev is null");
504 return -EINVAL;
505 }
506
507 hdev->flags = 0;
508
509 tasklet_init(&hdev->cmd_task, radio_hci_cmd_task, (unsigned long)
510 hdev);
511 tasklet_init(&hdev->rx_task, radio_hci_rx_task, (unsigned long)
512 hdev);
513
514 init_waitqueue_head(&hdev->req_wait_q);
515
516 skb_queue_head_init(&hdev->rx_q);
517 skb_queue_head_init(&hdev->cmd_q);
518 skb_queue_head_init(&hdev->raw_q);
519
520 if (!radio)
521 FMDERR(":radio is null");
522
523 radio->fm_hdev = hdev;
524
525 return 0;
526}
527EXPORT_SYMBOL(radio_hci_register_dev);
528
529int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
530{
531 struct iris_device *radio = video_get_drvdata(video_get_dev());
532 if (!radio) {
533 FMDERR(":radio is null");
534 return -EINVAL;
535 }
536
537 tasklet_kill(&hdev->rx_task);
538 tasklet_kill(&hdev->cmd_task);
539 skb_queue_purge(&hdev->rx_q);
540 skb_queue_purge(&hdev->cmd_q);
541 skb_queue_purge(&hdev->raw_q);
542 kfree(radio->fm_hdev);
543 kfree(radio->videodev);
544
545 return 0;
546}
547EXPORT_SYMBOL(radio_hci_unregister_dev);
548
549int radio_hci_recv_frame(struct sk_buff *skb)
550{
551 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
552 if (!hdev) {
553 FMDERR("%s hdev is null while receiving frame", hdev->name);
554 kfree_skb(skb);
555 return -ENXIO;
556 }
557
558 __net_timestamp(skb);
559
560 radio_hci_event_packet(hdev, skb);
Srinivasa Rao Uppalacf3a8112011-09-22 21:02:02 +0530561 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562 return 0;
563}
564EXPORT_SYMBOL(radio_hci_recv_frame);
565
566int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
567 void *param)
568{
569 int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
570 struct radio_hci_command_hdr *hdr;
571 struct sk_buff *skb;
572 int ret = 0;
573
574 skb = alloc_skb(len, GFP_ATOMIC);
575 if (!skb) {
576 FMDERR("%s no memory for command", hdev->name);
577 return -ENOMEM;
578 }
579
580 hdr = (struct radio_hci_command_hdr *) skb_put(skb,
581 RADIO_HCI_COMMAND_HDR_SIZE);
582 hdr->opcode = cpu_to_le16(opcode);
583 hdr->plen = plen;
584
585 if (plen)
586 memcpy(skb_put(skb, plen), param, plen);
587
588 skb->dev = (void *) hdev;
589
590 ret = hci_send_frame(skb);
591
592 return ret;
593}
594EXPORT_SYMBOL(radio_hci_send_cmd);
595
596static int hci_fm_enable_recv_req(struct radio_hci_dev *hdev,
597 unsigned long param)
598{
599 __u16 opcode = 0;
600
601 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
602 HCI_OCF_FM_ENABLE_RECV_REQ);
603 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
604}
605
Ankur Nandwanid928d542011-08-11 13:15:41 -0700606static int hci_fm_tone_generator(struct radio_hci_dev *hdev,
607 unsigned long param)
608{
609 struct iris_device *radio = video_get_drvdata(video_get_dev());
610 __u16 opcode = 0;
611
612 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
613 HCI_FM_SET_INTERNAL_TONE_GENRATOR);
614 return radio_hci_send_cmd(hdev, opcode,
615 sizeof(radio->tone_freq), &radio->tone_freq);
616}
617
618static int hci_fm_enable_trans_req(struct radio_hci_dev *hdev,
619 unsigned long param)
620{
621 __u16 opcode = 0;
622
623 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
624 HCI_OCF_FM_ENABLE_TRANS_REQ);
625 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
626}
627
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628static int hci_fm_disable_recv_req(struct radio_hci_dev *hdev,
629 unsigned long param)
630{
631 __u16 opcode = 0;
632
633 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
634 HCI_OCF_FM_DISABLE_RECV_REQ);
635 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
636}
637
Ankur Nandwanid928d542011-08-11 13:15:41 -0700638static int hci_fm_disable_trans_req(struct radio_hci_dev *hdev,
639 unsigned long param)
640{
641 __u16 opcode = 0;
642
643 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
644 HCI_OCF_FM_DISABLE_TRANS_REQ);
645 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
646}
647
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700648static int hci_get_fm_recv_conf_req(struct radio_hci_dev *hdev,
649 unsigned long param)
650{
651 __u16 opcode = 0;
652
653 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
654 HCI_OCF_FM_GET_RECV_CONF_REQ);
655 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
656}
657
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +0530658static int hci_get_fm_trans_conf_req(struct radio_hci_dev *hdev,
659 unsigned long param)
660{
661 u16 opcode = 0;
662
663 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
664 HCI_OCF_FM_GET_TRANS_CONF_REQ);
665 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
666}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700667static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
668 unsigned long param)
669{
670 __u16 opcode = 0;
671
672 struct hci_fm_recv_conf_req *recv_conf_req =
673 (struct hci_fm_recv_conf_req *) param;
674
675 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
676 HCI_OCF_FM_SET_RECV_CONF_REQ);
677 return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
678 recv_conf_req);
679}
680
Ankur Nandwanid928d542011-08-11 13:15:41 -0700681static int hci_set_fm_trans_conf_req(struct radio_hci_dev *hdev,
682 unsigned long param)
683{
684 __u16 opcode = 0;
685
686 struct hci_fm_trans_conf_req_struct *trans_conf_req =
687 (struct hci_fm_trans_conf_req_struct *) param;
688
689 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
690 HCI_OCF_FM_SET_TRANS_CONF_REQ);
691 return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
692 trans_conf_req);
693}
694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700695static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
696 unsigned long param)
697{
698 __u16 opcode = 0;
699
700 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
701 HCI_OCF_FM_GET_STATION_PARAM_REQ);
702 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
703}
704
705static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
706 unsigned long param)
707{
708 __u16 opcode = 0;
709 struct hci_fm_mute_mode_req *mute_mode_req =
710 (struct hci_fm_mute_mode_req *) param;
711
712 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
713 HCI_OCF_FM_SET_MUTE_MODE_REQ);
714 return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
715 mute_mode_req);
716}
717
Ankur Nandwanid928d542011-08-11 13:15:41 -0700718
719static int hci_trans_ps_req(struct radio_hci_dev *hdev,
720 unsigned long param)
721{
722 __u16 opcode = 0;
723 struct hci_fm_tx_ps *tx_ps_req =
724 (struct hci_fm_tx_ps *) param;
725
726 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
727 HCI_OCF_FM_RDS_PS_REQ);
728
729 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_ps_req)),
730 tx_ps_req);
731}
732
733static int hci_trans_rt_req(struct radio_hci_dev *hdev,
734 unsigned long param)
735{
736 __u16 opcode = 0;
737 struct hci_fm_tx_rt *tx_rt_req =
738 (struct hci_fm_tx_rt *) param;
739
740 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
741 HCI_OCF_FM_RDS_RT_REQ);
742
743 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_rt_req)),
744 tx_rt_req);
745}
746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700747static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
748 unsigned long param)
749{
750 __u16 opcode = 0;
751 struct hci_fm_stereo_mode_req *stereo_mode_req =
752 (struct hci_fm_stereo_mode_req *) param;
753 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
754 HCI_OCF_FM_SET_STEREO_MODE_REQ);
755 return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
756 stereo_mode_req);
757}
758
759static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
760 unsigned long param)
761{
762 __u16 opcode = 0;
763
764 __u8 antenna = param;
765
766 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
767 HCI_OCF_FM_SET_ANTENNA);
768 return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
769}
770
771static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
772 unsigned long param)
773{
774 __u16 opcode = 0;
775
776 __u8 sig_threshold = param;
777
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530778 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779 HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
780 return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
781 &sig_threshold);
782}
783
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +0530784static int hci_fm_set_event_mask(struct radio_hci_dev *hdev,
785 unsigned long param)
786{
787 u16 opcode = 0;
788 u8 event_mask = param;
789
790 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
791 HCI_OCF_FM_SET_EVENT_MASK);
792 return radio_hci_send_cmd(hdev, opcode, sizeof(event_mask),
793 &event_mask);
794}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
796 unsigned long param)
797{
798 __u16 opcode = 0;
799
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530800 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
802 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
803}
804
805static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
806 unsigned long param)
807{
808 __u16 opcode = 0;
809
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530810 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700811 HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
812 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
813}
814
815static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
816 unsigned long param)
817{
818 __u16 opcode = 0;
819
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530820 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 HCI_OCF_FM_GET_RADIO_TEXT_REQ);
822 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
823}
824
825static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
826 unsigned long param)
827{
828 __u16 opcode = 0;
829
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530830 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831 HCI_OCF_FM_GET_AF_LIST_REQ);
832 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
833}
834
835static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
836 unsigned long param)
837{
838 __u16 opcode = 0;
839 struct hci_fm_search_station_req *srch_stations =
840 (struct hci_fm_search_station_req *) param;
841
842 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
843 HCI_OCF_FM_SEARCH_STATIONS);
844 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
845 srch_stations);
846}
847
848static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
849 unsigned long param)
850{
851 __u16 opcode = 0;
852 struct hci_fm_search_rds_station_req *srch_stations =
853 (struct hci_fm_search_rds_station_req *) param;
854
855 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
856 HCI_OCF_FM_SEARCH_RDS_STATIONS);
857 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
858 srch_stations);
859}
860
861static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
862 unsigned long param)
863{
864 __u16 opcode = 0;
865 struct hci_fm_search_station_list_req *srch_list =
866 (struct hci_fm_search_station_list_req *) param;
867
868 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
869 HCI_OCF_FM_SEARCH_STATIONS_LIST);
870 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
871 srch_list);
872}
873
874static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
875 unsigned long param)
876{
877 __u16 opcode = 0;
878
879 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
880 HCI_OCF_FM_CANCEL_SEARCH);
881 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
882}
883
884static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
885 unsigned long param)
886{
887 __u16 opcode = 0;
888
889 __u32 fm_grps_process = param;
890
891 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
892 HCI_OCF_FM_RDS_GRP_PROCESS);
893 return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
894 &fm_grps_process);
895}
896
897static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
898 unsigned long param)
899{
900 __u16 opcode = 0;
901
902 __u32 tune_freq = param;
903
904 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
905 HCI_OCF_FM_TUNE_STATION_REQ);
906 return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
907}
908
909static int hci_def_data_read_req(struct radio_hci_dev *hdev,
910 unsigned long param)
911{
912 __u16 opcode = 0;
913 struct hci_fm_def_data_rd_req *def_data_rd =
914 (struct hci_fm_def_data_rd_req *) param;
915
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530916 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917 HCI_OCF_FM_DEFAULT_DATA_READ);
918 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
919 def_data_rd);
920}
921
922static int hci_def_data_write_req(struct radio_hci_dev *hdev,
923 unsigned long param)
924{
925 __u16 opcode = 0;
926 struct hci_fm_def_data_wr_req *def_data_wr =
927 (struct hci_fm_def_data_wr_req *) param;
928
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530929 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930 HCI_OCF_FM_DEFAULT_DATA_WRITE);
931 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
932 def_data_wr);
933}
934
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530935static int hci_set_notch_filter_req(struct radio_hci_dev *hdev,
936 unsigned long param)
937{
938 __u16 opcode = 0;
939 __u8 notch_filter_val = param;
940
941 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
942 HCI_OCF_FM_EN_NOTCH_CTRL);
943 return radio_hci_send_cmd(hdev, opcode, sizeof(notch_filter_val),
944 &notch_filter_val);
945}
946
947
948
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700949static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
950{
951 __u16 opcode = 0;
952
953 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
954 HCI_OCF_FM_RESET);
955 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
956}
957
958static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
959 unsigned long param)
960{
961 __u16 opcode = 0;
962
963 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
964 HCI_OCF_FM_GET_FEATURE_LIST);
965 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
966}
967
968static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
969 unsigned long param)
970{
971 __u16 opcode = 0;
972
973 __u8 mode = param;
974
975 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
976 HCI_OCF_FM_DO_CALIBRATION);
977 return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
978}
979
980static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
981 unsigned long param)
982{
983 __u16 opcode = 0;
984
985 __u8 reset_counters = param;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530986 opcode = hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987 HCI_OCF_FM_READ_GRP_COUNTERS);
988 return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
989 &reset_counters);
990}
991
992static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
993{
994 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700995 struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700997 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 HCI_OCF_FM_PEEK_DATA);
999 return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
1000 peek_data);
1001}
1002
1003static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
1004{
1005 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001006 struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07001008 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 HCI_OCF_FM_POKE_DATA);
1010 return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
1011 poke_data);
1012}
1013
1014static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
1015 unsigned long param)
1016{
1017 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001018 struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001020 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 HCI_OCF_FM_SSBI_PEEK_REG);
1022 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
1023 ssbi_peek);
1024}
1025
1026static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
1027 unsigned long param)
1028{
1029 __u16 opcode = 0;
1030 struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
1031
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001032 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 HCI_OCF_FM_SSBI_POKE_REG);
1034 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
1035 ssbi_poke);
1036}
1037
1038static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
1039 unsigned long param)
1040{
1041 __u16 opcode = 0;
1042
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +05301043 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 HCI_OCF_FM_STATION_DBG_PARAM);
1045 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1046}
1047
1048static int radio_hci_err(__u16 code)
1049{
1050 switch (code) {
1051 case 0:
1052 return 0;
1053 case 0x01:
1054 return -EBADRQC;
1055 case 0x02:
1056 return -ENOTCONN;
1057 case 0x03:
1058 return -EIO;
1059 case 0x07:
1060 return -ENOMEM;
1061 case 0x0c:
1062 return -EBUSY;
1063 case 0x11:
1064 return -EOPNOTSUPP;
1065 case 0x12:
1066 return -EINVAL;
1067 default:
1068 return -ENOSYS;
1069 }
1070}
1071
1072static int __radio_hci_request(struct radio_hci_dev *hdev,
1073 int (*req)(struct radio_hci_dev *hdev,
1074 unsigned long param),
1075 unsigned long param, __u32 timeout)
1076{
1077 int err = 0;
1078
1079 DECLARE_WAITQUEUE(wait, current);
1080
1081 hdev->req_status = HCI_REQ_PEND;
1082
1083 add_wait_queue(&hdev->req_wait_q, &wait);
1084 set_current_state(TASK_INTERRUPTIBLE);
1085
1086 err = req(hdev, param);
1087
1088 schedule_timeout(timeout);
1089
1090 remove_wait_queue(&hdev->req_wait_q, &wait);
1091
1092 if (signal_pending(current))
1093 return -EINTR;
1094
1095 switch (hdev->req_status) {
1096 case HCI_REQ_DONE:
1097 case HCI_REQ_STATUS:
1098 err = radio_hci_err(hdev->req_result);
1099 break;
1100
1101 case HCI_REQ_CANCELED:
1102 err = -hdev->req_result;
1103 break;
1104
1105 default:
1106 err = -ETIMEDOUT;
1107 break;
1108 }
1109
1110 hdev->req_status = hdev->req_result = 0;
1111
1112 return err;
1113}
1114
1115static inline int radio_hci_request(struct radio_hci_dev *hdev,
1116 int (*req)(struct
1117 radio_hci_dev * hdev, unsigned long param),
1118 unsigned long param, __u32 timeout)
1119{
1120 int ret = 0;
1121
1122 ret = __radio_hci_request(hdev, req, param, timeout);
1123
1124 return ret;
1125}
1126
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301127static inline int hci_conf_event_mask(__u8 *arg,
1128 struct radio_hci_dev *hdev)
1129{
1130 u8 event_mask = *arg;
1131 return radio_hci_request(hdev, hci_fm_set_event_mask,
1132 event_mask, RADIO_HCI_TIMEOUT);
1133}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
1135 struct radio_hci_dev *hdev)
1136{
1137 int ret = 0;
1138 struct hci_fm_recv_conf_req *set_recv_conf = arg;
1139
1140 ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
1141 long)set_recv_conf, RADIO_HCI_TIMEOUT);
1142
1143 return ret;
1144}
1145
Ankur Nandwanid928d542011-08-11 13:15:41 -07001146static int hci_set_fm_trans_conf(struct hci_fm_trans_conf_req_struct *arg,
1147 struct radio_hci_dev *hdev)
1148{
1149 int ret = 0;
1150 struct hci_fm_trans_conf_req_struct *set_trans_conf = arg;
1151
1152 ret = radio_hci_request(hdev, hci_set_fm_trans_conf_req, (unsigned
1153 long)set_trans_conf, RADIO_HCI_TIMEOUT);
1154
1155 return ret;
1156}
1157
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
1159{
1160 int ret = 0;
1161 __u32 tune_freq = *arg;
1162
1163 ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
1164 RADIO_HCI_TIMEOUT);
1165
1166 return ret;
1167}
1168
1169static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
1170 struct radio_hci_dev *hdev)
1171{
1172 int ret = 0;
1173 struct hci_fm_mute_mode_req *set_mute_conf = arg;
1174
1175 ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
1176 long)set_mute_conf, RADIO_HCI_TIMEOUT);
1177
1178 return ret;
1179}
1180
1181static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
1182 struct radio_hci_dev *hdev)
1183{
1184 int ret = 0;
1185 struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
1186
1187 ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
1188 long)set_stereo_conf, RADIO_HCI_TIMEOUT);
1189
1190 return ret;
1191}
1192
1193static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
1194{
1195 int ret = 0;
1196 __u8 antenna = *arg;
1197
1198 ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
1199 RADIO_HCI_TIMEOUT);
1200
1201 return ret;
1202}
1203
1204static int hci_fm_set_signal_threshold(__u8 *arg,
1205 struct radio_hci_dev *hdev)
1206{
1207 int ret = 0;
1208 __u8 sig_threshold = *arg;
1209
1210 ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
1211 sig_threshold, RADIO_HCI_TIMEOUT);
1212
1213 return ret;
1214}
1215
1216static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
1217 struct radio_hci_dev *hdev)
1218{
1219 int ret = 0;
1220 struct hci_fm_search_station_req *srch_stations = arg;
1221
1222 ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
1223 long)srch_stations, RADIO_HCI_TIMEOUT);
1224
1225 return ret;
1226}
1227
1228static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
1229 struct radio_hci_dev *hdev)
1230{
1231 int ret = 0;
1232 struct hci_fm_search_rds_station_req *srch_stations = arg;
1233
1234 ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
1235 long)srch_stations, RADIO_HCI_TIMEOUT);
1236
1237 return ret;
1238}
1239
1240static int hci_fm_search_station_list
1241 (struct hci_fm_search_station_list_req *arg,
1242 struct radio_hci_dev *hdev)
1243{
1244 int ret = 0;
1245 struct hci_fm_search_station_list_req *srch_list = arg;
1246
1247 ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
1248 long)srch_list, RADIO_HCI_TIMEOUT);
1249
1250 return ret;
1251}
1252
1253static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
1254 struct radio_hci_dev *hdev)
1255{
1256 return 0;
1257}
1258
1259static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
1260{
1261 int ret = 0;
1262 __u32 fm_grps_process = *arg;
1263
1264 ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
1265 fm_grps_process, RADIO_HCI_TIMEOUT);
1266
1267 return ret;
1268}
1269
1270int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
1271 struct radio_hci_dev *hdev)
1272{
1273 int ret = 0;
1274 struct hci_fm_def_data_rd_req *def_data_rd = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275 ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
1276 long)def_data_rd, RADIO_HCI_TIMEOUT);
1277
1278 return ret;
1279}
1280
1281int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
1282 struct radio_hci_dev *hdev)
1283{
1284 int ret = 0;
1285 struct hci_fm_def_data_wr_req *def_data_wr = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
1287 long)def_data_wr, RADIO_HCI_TIMEOUT);
1288
1289 return ret;
1290}
1291
1292int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
1293{
1294 int ret = 0;
1295 __u8 mode = *arg;
1296
1297 ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
1298 RADIO_HCI_TIMEOUT);
1299
1300 return ret;
1301}
1302
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301303static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304{
1305 int ret = 0;
1306 __u8 reset_counters = *arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 ret = radio_hci_request(hdev, hci_read_grp_counters_req,
1308 reset_counters, RADIO_HCI_TIMEOUT);
1309
1310 return ret;
1311}
1312
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301313static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
1314{
1315 int ret = 0;
1316 __u8 notch_filter = *arg;
1317 ret = radio_hci_request(hdev, hci_set_notch_filter_req,
1318 notch_filter, RADIO_HCI_TIMEOUT);
1319
1320 return ret;
1321}
1322
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001323static int hci_peek_data(struct hci_fm_riva_data *arg,
1324 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325{
1326 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001327 struct hci_fm_riva_data *peek_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328
1329 ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
1330 long)peek_data, RADIO_HCI_TIMEOUT);
1331
1332 return ret;
1333}
1334
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001335static int hci_poke_data(struct hci_fm_riva_poke *arg,
1336 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337{
1338 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001339 struct hci_fm_riva_poke *poke_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340
1341 ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
1342 long)poke_data, RADIO_HCI_TIMEOUT);
1343
1344 return ret;
1345}
1346
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001347static int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *arg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348 struct radio_hci_dev *hdev)
1349{
1350 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001351 struct hci_fm_ssbi_peek *ssbi_peek_reg = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352
1353 ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
1354 long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
1355
1356 return ret;
1357}
1358
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001359static int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg,
1360 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361{
1362 int ret = 0;
1363 struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
1364
1365 ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
1366 long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
1367
1368 return ret;
1369}
1370
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301371static int hci_fm_set_cal_req_proc(struct radio_hci_dev *hdev,
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301372 unsigned long param)
1373{
1374 u16 opcode = 0;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301375 struct hci_fm_set_cal_req_proc *cal_req =
1376 (struct hci_fm_set_cal_req_proc *)param;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301377
1378 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1379 HCI_OCF_FM_SET_CALIBRATION);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301380 return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301381 cal_req);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301382}
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301383
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301384static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
1385 unsigned long param)
1386{
1387 u16 opcode = 0;
1388 u8 cal_mode = param;
1389
1390 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1391 HCI_OCF_FM_DO_CALIBRATION);
1392 return radio_hci_send_cmd(hdev, opcode, sizeof(cal_mode),
1393 &cal_mode);
1394
1395}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1397{
1398 int ret = 0;
1399 unsigned long arg = 0;
1400
Ankur Nandwanid928d542011-08-11 13:15:41 -07001401 if (!hdev)
1402 return -ENODEV;
1403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 switch (cmd) {
1405 case HCI_FM_ENABLE_RECV_CMD:
1406 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1407 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1408 break;
1409
1410 case HCI_FM_DISABLE_RECV_CMD:
1411 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1412 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1413 break;
1414
1415 case HCI_FM_GET_RECV_CONF_CMD:
1416 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1417 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1418 break;
1419
1420 case HCI_FM_GET_STATION_PARAM_CMD:
1421 ret = radio_hci_request(hdev,
1422 hci_fm_get_station_param_req, arg,
1423 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1424 break;
1425
1426 case HCI_FM_GET_SIGNAL_TH_CMD:
1427 ret = radio_hci_request(hdev,
1428 hci_fm_get_sig_threshold_req, arg,
1429 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1430 break;
1431
1432 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1433 ret = radio_hci_request(hdev,
1434 hci_fm_get_program_service_req, arg,
1435 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1436 break;
1437
1438 case HCI_FM_GET_RADIO_TEXT_CMD:
1439 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1440 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1441 break;
1442
1443 case HCI_FM_GET_AF_LIST_CMD:
1444 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1445 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1446 break;
1447
1448 case HCI_FM_CANCEL_SEARCH_CMD:
1449 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1450 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1451 break;
1452
1453 case HCI_FM_RESET_CMD:
1454 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1455 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1456 break;
1457
1458 case HCI_FM_GET_FEATURES_CMD:
1459 ret = radio_hci_request(hdev,
1460 hci_fm_get_feature_lists_req, arg,
1461 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1462 break;
1463
1464 case HCI_FM_STATION_DBG_PARAM_CMD:
1465 ret = radio_hci_request(hdev,
1466 hci_fm_get_station_dbg_param_req, arg,
1467 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1468 break;
1469
Ankur Nandwanid928d542011-08-11 13:15:41 -07001470 case HCI_FM_ENABLE_TRANS_CMD:
1471 ret = radio_hci_request(hdev, hci_fm_enable_trans_req, arg,
1472 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1473 break;
1474
1475 case HCI_FM_DISABLE_TRANS_CMD:
1476 ret = radio_hci_request(hdev, hci_fm_disable_trans_req, arg,
1477 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1478 break;
1479
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301480 case HCI_FM_GET_TX_CONFIG:
1481 ret = radio_hci_request(hdev, hci_get_fm_trans_conf_req, arg,
1482 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1483 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 default:
1485 ret = -EINVAL;
1486 break;
1487 }
1488
1489 return ret;
1490}
1491
1492static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1493{
1494 hdev->req_result = result;
1495 hdev->req_status = HCI_REQ_DONE;
1496 wake_up_interruptible(&hdev->req_wait_q);
1497}
1498
1499static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1500{
1501 hdev->req_result = result;
1502 hdev->req_status = HCI_REQ_STATUS;
1503 wake_up_interruptible(&hdev->req_wait_q);
1504}
1505
1506static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1507{
1508 __u8 status = *((__u8 *) skb->data);
1509
1510 if (status)
1511 return;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 radio_hci_req_complete(hdev, status);
1514}
1515
1516static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1517 struct sk_buff *skb)
1518{
1519 __u8 status = *((__u8 *) skb->data);
1520 struct iris_device *radio = video_get_drvdata(video_get_dev());
1521
1522 if (status)
1523 return;
1524
1525 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1526
1527 radio_hci_req_complete(hdev, status);
1528}
1529
1530static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1531{
1532 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1533 struct iris_device *radio = video_get_drvdata(video_get_dev());
1534
1535 if (rsp->status)
1536 return;
1537
1538 radio->recv_conf = rsp->recv_conf_rsp;
1539 radio_hci_req_complete(hdev, rsp->status);
1540}
1541
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301542static void hci_cc_fm_trans_get_conf_rsp(struct radio_hci_dev *hdev,
1543 struct sk_buff *skb)
1544{
1545 struct hci_fm_get_trans_conf_rsp *rsp = (void *)skb->data;
1546 struct iris_device *radio = video_get_drvdata(video_get_dev());
1547
1548 if (rsp->status)
1549 return;
1550 memcpy((void *)&radio->trans_conf, (void*)&rsp->trans_conf_rsp,
1551 sizeof(rsp->trans_conf_rsp));
1552 radio_hci_req_complete(hdev, rsp->status);
1553}
1554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1556 struct sk_buff *skb)
1557{
1558 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1559 struct iris_device *radio = video_get_drvdata(video_get_dev());
1560
1561 if (rsp->status)
1562 return;
1563
1564 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1565
1566 radio_hci_req_complete(hdev, rsp->status);
1567}
1568
Ankur Nandwanid928d542011-08-11 13:15:41 -07001569
1570static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
1571 struct sk_buff *skb)
1572{
1573 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1574 struct iris_device *radio = video_get_drvdata(video_get_dev());
1575
1576 if (rsp->status)
1577 return;
1578
1579 iris_q_event(radio, HCI_EV_CMD_COMPLETE);
1580
1581 radio_hci_req_complete(hdev, rsp->status);
1582}
1583
1584
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1586 struct sk_buff *skb)
1587{
1588 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1589 struct iris_device *radio = video_get_drvdata(video_get_dev());
1590 struct v4l2_control *v4l_ctl = radio->g_ctl;
1591
1592 if (rsp->status)
1593 return;
1594
1595 v4l_ctl->value = rsp->sig_threshold;
1596
1597 radio_hci_req_complete(hdev, rsp->status);
1598}
1599
1600static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1601{
1602 struct iris_device *radio = video_get_drvdata(video_get_dev());
1603 struct hci_fm_station_rsp *rsp = (void *)skb->data;
1604 radio->fm_st_rsp = *(rsp);
1605
1606 /* Tune is always succesful */
1607 radio_hci_req_complete(hdev, 0);
1608}
1609
1610static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1611{
1612 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1613
1614 if (rsp->status)
1615 return;
1616
1617 radio_hci_req_complete(hdev, rsp->status);
1618}
1619
1620static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1621{
1622 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1623
1624 if (rsp->status)
1625 return;
1626
1627 radio_hci_req_complete(hdev, rsp->status);
1628}
1629
1630static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1631{
1632 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1633
1634 if (rsp->status)
1635 return;
1636
1637 radio_hci_req_complete(hdev, rsp->status);
1638}
1639
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1641 struct sk_buff *skb)
1642{
1643 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1644 struct iris_device *radio = video_get_drvdata(video_get_dev());
1645 struct v4l2_capability *v4l_cap = radio->g_cap;
1646
1647 if (rsp->status)
1648 return;
1649 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1650 (rsp->feature_mask & 0x000001);
1651
1652 radio_hci_req_complete(hdev, rsp->status);
1653}
1654
1655static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1656 struct sk_buff *skb)
1657{
1658 struct iris_device *radio = video_get_drvdata(video_get_dev());
1659 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
1660 radio->st_dbg_param = *(rsp);
1661
1662 if (radio->st_dbg_param.status)
1663 return;
1664
1665 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1666}
1667
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001668static void iris_q_evt_data(struct iris_device *radio,
1669 char *data, int len, int event)
1670{
1671 struct kfifo *data_b = &radio->data_buf[event];
1672 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1673 wake_up_interruptible(&radio->event_queue);
1674}
1675
1676static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1677 struct sk_buff *skb)
1678{
1679 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301680 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001681 int len;
1682 char *data;
1683
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301684 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001685 return;
1686 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1687 data = kmalloc(len, GFP_ATOMIC);
1688
1689 if (!data) {
1690 FMDERR("Memory allocation failed");
1691 return;
1692 }
1693
1694 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1695 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301696 radio_hci_req_complete(hdev, status);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301697 kfree(data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001698
1699}
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301700
1701static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
1702 struct sk_buff *skb)
1703{
1704 struct iris_device *radio = video_get_drvdata(video_get_dev());
1705 __u8 status = *((__u8 *) skb->data);
1706 __u8 len;
1707 char *data;
1708
1709 if (status)
1710 return;
1711 len = skb->data[1];
1712 data = kmalloc(len+2, GFP_ATOMIC);
1713 if (!data) {
1714 FMDERR("Memory allocation failed");
1715 return;
1716 }
1717
1718 data[0] = status;
1719 data[1] = len;
1720 memcpy(&data[2], &skb->data[DEFAULT_DATA_OFFSET], len);
1721 iris_q_evt_data(radio, data, len+2, IRIS_BUF_RD_DEFAULT);
1722 radio_hci_req_complete(hdev, status);
1723 kfree(data);
1724}
1725
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001726static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1727 struct sk_buff *skb)
1728{
1729 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301730 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001731 char *data;
1732
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301733 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001734 return;
1735 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1736 if (!data) {
1737 FMDERR("Memory allocation failed");
1738 return;
1739 }
1740
1741 data[0] = skb->data[PEEK_DATA_OFSET];
1742 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301743 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001744 kfree(data);
1745}
1746
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301747static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
1748 struct sk_buff *skb)
1749{
1750 struct iris_device *radio = video_get_drvdata(video_get_dev());
1751 __u8 status = *((__u8 *) skb->data);
1752 char *data;
1753 if (status)
1754 return;
1755 data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
1756 if (!data) {
1757 FMDERR("memory allocation failed");
1758 return;
1759 }
1760 memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
1761 iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
1762 radio_hci_req_complete(hdev, status);
1763 kfree(data);
1764
1765}
1766
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301767static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
1768 struct sk_buff *skb)
1769{
1770 struct iris_device *radio = video_get_drvdata(video_get_dev());
1771 static struct hci_cc_do_calibration_rsp rsp ;
1772 rsp.status = skb->data[0];
1773 rsp.mode = skb->data[CALIB_MODE_OFSET];
1774
1775 if (rsp.status) {
1776 FMDERR("status = %d", rsp.status);
1777 return;
1778 }
1779 if (rsp.mode == PROCS_CALIB_MODE) {
1780 memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
1781 PROCS_CALIB_SIZE);
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05301782 iris_q_evt_data(radio, rsp.data, PROCS_CALIB_SIZE,
1783 IRIS_BUF_CAL_DATA);
1784 } else {
1785 return;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301786 }
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05301787
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301788 radio_hci_req_complete(hdev, rsp.status);
1789}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
1791 struct sk_buff *skb)
1792{
1793 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
1794 __u16 opcode;
1795
1796 skb_pull(skb, sizeof(*cmd_compl_ev));
1797
1798 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
1799
1800 switch (opcode) {
1801 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
1802 hci_cc_fm_enable_rsp(hdev, skb);
1803 break;
1804 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
1805 hci_cc_conf_rsp(hdev, skb);
1806 break;
1807
1808 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
1809 hci_cc_fm_disable_rsp(hdev, skb);
1810 break;
1811
1812 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
1813 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
1814 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
1815 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
1816 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
1817 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
1818 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
1819 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
1820 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
1821 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001822 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
1823 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
1824 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
1825 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301827 hci_cc_rsp(hdev, skb);
1828 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001829 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001831 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001832 case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301833 case hci_common_cmd_op_pack(HCI_OCF_FM_SET_CALIBRATION):
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301834 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_EVENT_MASK):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835 hci_cc_rsp(hdev, skb);
1836 break;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301837
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001838 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
1839 hci_cc_ssbi_peek_rsp(hdev, skb);
1840 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
1842 hci_cc_sig_threshold_rsp(hdev, skb);
1843 break;
1844
1845 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
1846 hci_cc_station_rsp(hdev, skb);
1847 break;
1848
1849 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
1850 hci_cc_prg_srv_rsp(hdev, skb);
1851 break;
1852
1853 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
1854 hci_cc_rd_txt_rsp(hdev, skb);
1855 break;
1856
1857 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
1858 hci_cc_af_list_rsp(hdev, skb);
1859 break;
1860
1861 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301862 hci_cc_riva_read_default_rsp(hdev, skb);
1863 break;
1864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001865 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001866 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 break;
1868
1869 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
1870 hci_cc_feature_list_rsp(hdev, skb);
1871 break;
1872
1873 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
1874 hci_cc_dbg_param_rsp(hdev, skb);
1875 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07001876 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_SET_TRANS_CONF_REQ):
1877 hci_cc_fm_trans_set_conf_rsp(hdev, skb);
1878 break;
1879
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301880 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
1881 hci_cc_rds_grp_cntrs_rsp(hdev, skb);
1882 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301883 case hci_common_cmd_op_pack(HCI_OCF_FM_DO_CALIBRATION):
1884 hci_cc_do_calibration_rsp(hdev, skb);
1885 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301886
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301887 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_GET_TRANS_CONF_REQ):
1888 hci_cc_fm_trans_get_conf_rsp(hdev, skb);
1889 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001890 default:
1891 FMDERR("%s opcode 0x%x", hdev->name, opcode);
1892 break;
1893 }
1894
1895}
1896
1897static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
1898 struct sk_buff *skb)
1899{
1900 struct hci_ev_cmd_status *ev = (void *) skb->data;
1901 radio_hci_status_complete(hdev, ev->status);
1902}
1903
1904static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
1905 struct sk_buff *skb)
1906{
1907 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908 struct iris_device *radio = video_get_drvdata(video_get_dev());
1909
Venkateshwarlu Domakonda862492d2011-11-29 11:51:24 +05301910 memcpy(&radio->fm_st_rsp.station_rsp, &skb->data[0],
1911 sizeof(struct hci_ev_tune_status));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
1913
1914 for (i = 0; i < IRIS_BUF_MAX; i++) {
1915 if (i >= IRIS_BUF_RT_RDS)
1916 kfifo_reset(&radio->data_buf[i]);
1917 }
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05301918 if (radio->fm_st_rsp.station_rsp.serv_avble)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001919 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1920 else
1921 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1922
1923 if (radio->fm_st_rsp.station_rsp.stereo_prg)
1924 iris_q_event(radio, IRIS_EVT_STEREO);
1925
1926 if (radio->fm_st_rsp.station_rsp.mute_mode)
1927 iris_q_event(radio, IRIS_EVT_MONO);
1928
1929 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
1930 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1931 else
1932 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1933}
1934
1935static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
1936 struct sk_buff *skb)
1937{
1938 struct iris_device *radio = video_get_drvdata(video_get_dev());
1939 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
1940}
1941
1942static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
1943 struct sk_buff *skb)
1944{
1945 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001946 struct hci_ev_srch_list_compl *ev ;
1947 int cnt;
1948 int stn_num;
1949 int rel_freq;
1950 int abs_freq;
1951 int len;
1952
1953 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1954 if (!ev) {
1955 FMDERR("Memory allocation failed");
1956 return ;
1957 }
1958
1959 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
1960 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
1961
1962 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301963 (cnt < len) && (stn_num < ev->num_stations_found)
1964 && (stn_num < ARRAY_SIZE(ev->rel_freq));
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001965 cnt += PARAMS_PER_STATION, stn_num++) {
1966 abs_freq = *((int *)&skb->data[cnt]);
1967 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
1968 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
1969
1970 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
1971 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
1972 }
1973
1974 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
1975 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
1976 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
1977 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001978}
1979
1980static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
1981 struct sk_buff *skb)
1982{
1983 struct iris_device *radio = video_get_drvdata(video_get_dev());
1984 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
1985}
1986
1987static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
1988 struct sk_buff *skb)
1989{
1990 struct iris_device *radio = video_get_drvdata(video_get_dev());
1991 __u8 st_status = *((__u8 *) skb->data);
1992 if (st_status)
1993 iris_q_event(radio, IRIS_EVT_STEREO);
1994 else
1995 iris_q_event(radio, IRIS_EVT_MONO);
1996}
1997
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001998
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001999static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
2000 struct sk_buff *skb)
2001{
2002 struct iris_device *radio = video_get_drvdata(video_get_dev());
2003 int len;
2004 char *data;
2005
2006 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
2007 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
2008 data = kmalloc(len, GFP_ATOMIC);
2009 if (!data) {
2010 FMDERR("Failed to allocate memory");
2011 return;
2012 }
2013
2014 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
2015 data[1] = skb->data[RDS_PTYPE];
2016 data[2] = skb->data[RDS_PID_LOWER];
2017 data[3] = skb->data[RDS_PID_HIGHER];
2018 data[4] = 0;
2019
2020 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
2021
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002022 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002023
2024 kfree(data);
2025}
2026
2027
2028static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
2029 struct sk_buff *skb)
2030{
2031 struct iris_device *radio = video_get_drvdata(video_get_dev());
2032 int len = 0;
2033 char *data;
2034
2035 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
2036
Srinivasa Rao Uppala69839842012-01-13 18:36:12 +05302037 while ((skb->data[len+RDS_OFFSET] != 0x0d) && (len < RX_RT_DATA_LENGTH))
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002038 len++;
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002039 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
2040 if (!data) {
2041 FMDERR("Failed to allocate memory");
2042 return;
2043 }
2044
2045 data[0] = len;
2046 data[1] = skb->data[RDS_PTYPE];
2047 data[2] = skb->data[RDS_PID_LOWER];
2048 data[3] = skb->data[RDS_PID_HIGHER];
2049 data[4] = 0;
2050
2051 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
2052 data[len+RDS_OFFSET] = 0x00;
2053
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002054 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002055
2056 kfree(data);
2057}
2058
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302059static void hci_ev_af_list(struct radio_hci_dev *hdev,
2060 struct sk_buff *skb)
2061{
2062 struct iris_device *radio = video_get_drvdata(video_get_dev());
2063 struct hci_ev_af_list ev;
2064
2065 ev.tune_freq = *((int *) &skb->data[0]);
2066 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
2067 ev.af_size = skb->data[AF_SIZE_OFFSET];
2068 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
2069 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
2070 iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
2071}
2072
2073static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
2074 struct sk_buff *skb)
2075{
2076 struct iris_device *radio = video_get_drvdata(video_get_dev());
2077 __u8 rds_status = skb->data[0];
2078
2079 if (rds_status)
2080 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2081 else
2082 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2083}
2084
2085static void hci_ev_service_available(struct radio_hci_dev *hdev,
2086 struct sk_buff *skb)
2087{
2088 struct iris_device *radio = video_get_drvdata(video_get_dev());
Venkateshwarlu Domakondad6140eb2012-01-17 16:23:52 +05302089 u8 serv_avble = skb->data[0];
2090 if (serv_avble)
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302091 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2092 else
2093 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2094}
2095
2096static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
2097 struct sk_buff *skb)
2098{
2099 struct iris_device *radio = video_get_drvdata(video_get_dev());
2100 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
2101}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
2104{
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302105 struct radio_hci_event_hdr *hdr;
2106 u8 event;
2107
2108 if (skb == NULL) {
2109 FMDERR("Socket buffer is NULL");
2110 return;
2111 }
2112
2113 hdr = (void *) skb->data;
2114 event = hdr->evt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002115
2116 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
2117
2118 switch (event) {
2119 case HCI_EV_TUNE_STATUS:
2120 hci_ev_tune_status(hdev, skb);
2121 break;
2122 case HCI_EV_SEARCH_PROGRESS:
2123 case HCI_EV_SEARCH_RDS_PROGRESS:
2124 case HCI_EV_SEARCH_LIST_PROGRESS:
2125 hci_ev_search_next(hdev, skb);
2126 break;
2127 case HCI_EV_STEREO_STATUS:
2128 hci_ev_stereo_status(hdev, skb);
2129 break;
2130 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302131 hci_ev_rds_lock_status(hdev, skb);
2132 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302134 hci_ev_service_available(hdev, skb);
2135 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 case HCI_EV_RDS_RX_DATA:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002137 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002138 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002139 hci_ev_program_service(hdev, skb);
2140 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002142 hci_ev_radio_text(hdev, skb);
2143 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302145 hci_ev_af_list(hdev, skb);
2146 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002147 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302148 hci_ev_rds_grp_complete(hdev, skb);
2149 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002150 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2151 break;
2152
2153 case HCI_EV_CMD_COMPLETE:
2154 hci_cmd_complete_event(hdev, skb);
2155 break;
2156
2157 case HCI_EV_CMD_STATUS:
2158 hci_cmd_status_event(hdev, skb);
2159 break;
2160
2161 case HCI_EV_SEARCH_COMPLETE:
2162 case HCI_EV_SEARCH_RDS_COMPLETE:
2163 hci_ev_search_compl(hdev, skb);
2164 break;
2165
2166 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002167 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168 break;
2169
2170 default:
2171 break;
2172 }
2173}
2174
2175/*
2176 * fops/IOCTL helper functions
2177 */
2178
2179static int iris_search(struct iris_device *radio, int on, int dir)
2180{
2181 int retval = 0;
2182 enum search_t srch = radio->g_search_mode & SRCH_MODE;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302183 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002184
2185 if (on) {
2186 switch (srch) {
2187 case SCAN_FOR_STRONG:
2188 case SCAN_FOR_WEAK:
2189 radio->srch_st_list.srch_list_dir = dir;
2190 radio->srch_st_list.srch_list_mode = srch;
2191 radio->srch_st_list.srch_list_max = 0;
2192 retval = hci_fm_search_station_list(
2193 &radio->srch_st_list, radio->fm_hdev);
2194 break;
2195 case RDS_SEEK_PTY:
2196 case RDS_SCAN_PTY:
2197 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002198 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002199 radio->srch_rds.srch_station.srch_mode = srch;
2200 radio->srch_rds.srch_station.srch_dir = dir;
2201 radio->srch_rds.srch_station.scan_time =
2202 radio->g_scan_time;
2203 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2204 radio->fm_hdev);
2205 break;
2206 default:
2207 radio->srch_st.srch_mode = srch;
2208 radio->srch_st.scan_time = radio->g_scan_time;
2209 radio->srch_st.srch_dir = dir;
2210 retval = hci_fm_search_stations(
2211 &radio->srch_st, radio->fm_hdev);
2212 break;
2213 }
2214
2215 } else {
2216 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2217 }
2218
2219 return retval;
2220}
2221
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302222static int set_low_power_mode(struct iris_device *radio, int power_mode)
2223{
2224
2225 int rds_grps_proc = 0x00;
2226 int retval = 0;
2227 if (radio->power_mode != power_mode) {
2228
2229 if (power_mode) {
2230 radio->event_mask = 0x00;
2231 rds_grps_proc = 0x00 | AF_JUMP_ENABLE ;
2232 retval = hci_fm_rds_grps_process(
2233 &rds_grps_proc,
2234 radio->fm_hdev);
2235 if (retval < 0) {
2236 FMDERR("Disable RDS failed");
2237 return retval;
2238 }
2239 retval = hci_conf_event_mask(&radio->event_mask,
2240 radio->fm_hdev);
2241 } else {
2242
2243 radio->event_mask = SIG_LEVEL_INTR |
2244 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2245 retval = hci_conf_event_mask(&radio->event_mask,
2246 radio->fm_hdev);
2247 if (retval < 0) {
2248 FMDERR("Enable Async events failed");
2249 return retval;
2250 }
2251 retval = hci_fm_rds_grps_process(
2252 &radio->g_rds_grp_proc_ps,
2253 radio->fm_hdev);
2254 }
2255 radio->power_mode = power_mode;
2256 }
2257 return retval;
2258}
Ankur Nandwanid928d542011-08-11 13:15:41 -07002259static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260{
2261 int retval;
2262 radio->region = req_region;
2263
2264 switch (radio->region) {
2265 case IRIS_REGION_US:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002266 radio->recv_conf.band_low_limit =
2267 REGION_US_EU_BAND_LOW;
2268 radio->recv_conf.band_high_limit =
2269 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 break;
2271 case IRIS_REGION_EU:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002272 radio->recv_conf.band_low_limit =
2273 REGION_US_EU_BAND_LOW;
2274 radio->recv_conf.band_high_limit =
2275 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 break;
2277 case IRIS_REGION_JAPAN:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002278 radio->recv_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002279 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302280 radio->recv_conf.band_high_limit =
2281 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002282 break;
2283 case IRIS_REGION_JAPAN_WIDE:
2284 radio->recv_conf.band_low_limit =
2285 REGION_JAPAN_WIDE_BAND_LOW;
2286 radio->recv_conf.band_high_limit =
2287 REGION_JAPAN_WIDE_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002288 break;
2289 default:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002290 /* The user specifies the value.
2291 So nothing needs to be done */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002292 break;
2293 }
2294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002295 retval = hci_set_fm_recv_conf(
2296 &radio->recv_conf,
2297 radio->fm_hdev);
2298
2299 return retval;
2300}
2301
Ankur Nandwanid928d542011-08-11 13:15:41 -07002302
2303static int iris_trans_set_region(struct iris_device *radio, int req_region)
2304{
2305 int retval;
2306 radio->region = req_region;
2307
2308 switch (radio->region) {
2309 case IRIS_REGION_US:
2310 radio->trans_conf.band_low_limit =
2311 REGION_US_EU_BAND_LOW;
2312 radio->trans_conf.band_high_limit =
2313 REGION_US_EU_BAND_HIGH;
2314 break;
2315 case IRIS_REGION_EU:
2316 radio->trans_conf.band_low_limit =
2317 REGION_US_EU_BAND_LOW;
2318 radio->trans_conf.band_high_limit =
2319 REGION_US_EU_BAND_HIGH;
2320 break;
2321 case IRIS_REGION_JAPAN:
2322 radio->trans_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002323 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302324 radio->trans_conf.band_high_limit =
2325 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002326 break;
2327 case IRIS_REGION_JAPAN_WIDE:
2328 radio->recv_conf.band_low_limit =
2329 REGION_JAPAN_WIDE_BAND_LOW;
2330 radio->recv_conf.band_high_limit =
2331 REGION_JAPAN_WIDE_BAND_HIGH;
2332 default:
2333 break;
2334 }
2335
2336 retval = hci_set_fm_trans_conf(
2337 &radio->trans_conf,
2338 radio->fm_hdev);
2339 return retval;
2340}
2341
2342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2344{
2345
2346 int retval;
2347 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2348 if (retval < 0)
2349 FMDERR("Error while setting the frequency : %d\n", retval);
2350 return retval;
2351}
2352
2353
2354static int iris_vidioc_queryctrl(struct file *file, void *priv,
2355 struct v4l2_queryctrl *qc)
2356{
2357 unsigned char i;
2358 int retval = -EINVAL;
2359
2360 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2361 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2362 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2363 retval = 0;
2364 break;
2365 }
2366 }
2367
2368 return retval;
2369}
2370
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302371static int iris_do_calibration(struct iris_device *radio)
2372{
2373 char cal_mode = 0x00;
2374 int retval = 0x00;
2375
2376 cal_mode = PROCS_CALIB_MODE;
2377 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2378 radio->fm_hdev);
2379 if (retval < 0) {
2380 FMDERR("Enable failed before calibration %x", retval);
2381 return retval;
2382 }
2383 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2384 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2385 if (retval < 0) {
2386 FMDERR("Do Process calibration failed %x", retval);
2387 return retval;
2388 }
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302389 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2390 radio->fm_hdev);
2391 if (retval < 0)
2392 FMDERR("Disable Failed after calibration %d", retval);
2393 return retval;
2394}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002395static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2396 struct v4l2_control *ctrl)
2397{
2398 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2399 int retval = 0;
2400
2401 switch (ctrl->id) {
2402 case V4L2_CID_AUDIO_VOLUME:
2403 break;
2404 case V4L2_CID_AUDIO_MUTE:
2405 ctrl->value = radio->mute_mode.hard_mute;
2406 break;
2407 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2408 ctrl->value = radio->g_search_mode;
2409 break;
2410 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2411 ctrl->value = radio->g_scan_time;
2412 break;
2413 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302414 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002415 break;
2416 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302417 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418 break;
2419 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2420 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2421 if (retval < 0)
2422 return retval;
2423 ctrl->value = radio->st_dbg_param.io_verc;
2424 break;
2425 case V4L2_CID_PRIVATE_IRIS_INTDET:
2426 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2427 if (retval < 0)
2428 return retval;
2429 ctrl->value = radio->st_dbg_param.in_det_out;
2430 break;
2431 case V4L2_CID_PRIVATE_IRIS_REGION:
2432 ctrl->value = radio->region;
2433 break;
2434 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2435 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
2436 break;
2437 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302438 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439 break;
2440 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302441 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 break;
2443 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302444 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002445 break;
2446 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002447 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002449 } else if (radio->mode == FM_TRANS) {
2450 ctrl->value = radio->trans_conf.emphasis;
2451 } else {
2452 FMDERR("Error in radio mode"
2453 " %d\n", retval);
2454 return -EINVAL;
2455 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 break;
2457 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002458 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002460 } else if (radio->mode == FM_TRANS) {
2461 ctrl->value = radio->trans_conf.rds_std;
2462 } else {
2463 FMDERR("Error in radio mode"
2464 " %d\n", retval);
2465 return -EINVAL;
2466 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467 break;
2468 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002469 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002471 } else {
2472 FMDERR("Error in radio mode"
2473 " %d\n", retval);
2474 return -EINVAL;
2475 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476 break;
2477 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002478 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002480 } else {
2481 FMDERR("Error in radio mode"
2482 " %d\n", retval);
2483 return -EINVAL;
2484 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 break;
2486 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2487 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2488 break;
2489 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002490 case V4L2_CID_PRIVATE_IRIS_PSALL:
2491 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492 break;
2493 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2494 ctrl->value = radio->rds_grp.rds_buf_size;
2495 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302497 ctrl->value = radio->power_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002498 break;
2499 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2500 ctrl->value = radio->g_antenna;
2501 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002502 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2503 ctrl->value = radio->mute_mode.soft_mute;
2504 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302505 case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
2506 retval = iris_do_calibration(radio);
2507 break;
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05302508 case V4L2_CID_PRIVATE_IRIS_GET_SINR:
2509 if (radio->mode == FM_RECV) {
2510 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD,
2511 radio->fm_hdev);
2512 if (retval < 0) {
2513 FMDERR("Get SINR Failed");
2514 return retval;
2515 }
2516 ctrl->value = radio->fm_st_rsp.station_rsp.sinr;
2517
2518 } else
2519 retval = -EINVAL;
2520
2521 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002522 default:
2523 retval = -EINVAL;
2524 }
2525 if (retval < 0)
2526 FMDERR("get control failed with %d, id: %d\n",
2527 retval, ctrl->id);
2528 return retval;
2529}
2530
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302531static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
2532 struct v4l2_ext_controls *ctrl)
2533{
2534 int retval = 0;
2535 char *data = NULL;
2536 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2537 struct hci_fm_def_data_rd_req default_data_rd;
2538
2539 switch ((ctrl->controls[0]).id) {
2540 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
2541 data = (ctrl->controls[0]).string;
2542 memset(&default_data_rd, 0, sizeof(default_data_rd));
2543 if (copy_from_user(&default_data_rd.mode, data,
2544 sizeof(default_data_rd)))
2545 return -EFAULT;
2546 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
2547 break;
2548 default:
2549 retval = -EINVAL;
2550 }
2551
2552 return retval;
2553}
2554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002555static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2556 struct v4l2_ext_controls *ctrl)
2557{
Ankur Nandwanid928d542011-08-11 13:15:41 -07002558 int retval = 0;
2559 int bytes_to_copy;
2560 struct hci_fm_tx_ps tx_ps;
2561 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302562 struct hci_fm_def_data_wr_req default_data;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302563 struct hci_fm_set_cal_req_proc proc_cal_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002564
2565 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2566 char *data = NULL;
2567
2568 switch ((ctrl->controls[0]).id) {
2569 case V4L2_CID_RDS_TX_PS_NAME:
2570 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2571 /*Pass a sample PS string */
2572
2573 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
2574 bytes_to_copy = min((int)(ctrl->controls[0]).size,
2575 MAX_PS_LENGTH);
2576 data = (ctrl->controls[0]).string;
2577
2578 if (copy_from_user(tx_ps.ps_data,
2579 data, bytes_to_copy))
2580 return -EFAULT;
2581 tx_ps.ps_control = 0x01;
2582 tx_ps.pi = radio->pi;
2583 tx_ps.pty = radio->pty;
2584 tx_ps.ps_repeatcount = radio->ps_repeatcount;
2585 tx_ps.ps_len = bytes_to_copy;
2586
2587 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2588 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
2589 break;
2590 case V4L2_CID_RDS_TX_RADIO_TEXT:
2591 bytes_to_copy =
2592 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2593 data = (ctrl->controls[0]).string;
2594
2595 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
2596
2597 if (copy_from_user(tx_rt.rt_data,
2598 data, bytes_to_copy))
2599 return -EFAULT;
2600
2601 tx_rt.rt_control = 0x01;
2602 tx_rt.pi = radio->pi;
2603 tx_rt.pty = radio->pty;
2604 tx_rt.ps_len = bytes_to_copy;
2605
2606 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2607 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
2608 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302609 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
2610 data = (ctrl->controls[0]).string;
2611 memset(&default_data, 0, sizeof(default_data));
2612 if (copy_from_user(&default_data, data, sizeof(default_data)))
2613 return -EFAULT;
2614 retval = hci_def_data_write(&default_data, radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302615 break;
2616 case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302617 data = (ctrl->controls[0]).string;
2618 bytes_to_copy = (ctrl->controls[0]).size;
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05302619 if (bytes_to_copy < PROCS_CALIB_SIZE) {
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302620 FMDERR("data is less than required size");
2621 return -EFAULT;
2622 }
2623 memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
2624 proc_cal_req.mode = PROCS_CALIB_MODE;
2625 if (copy_from_user(&proc_cal_req.data[0],
2626 data, sizeof(proc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302627 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302628 retval = radio_hci_request(radio->fm_hdev,
2629 hci_fm_set_cal_req_proc,
2630 (unsigned long)&proc_cal_req,
2631 RADIO_HCI_TIMEOUT);
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05302632 if (retval < 0)
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302633 FMDERR("Set Process calibration failed %d", retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302634 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002635 default:
2636 FMDBG("Shouldn't reach here\n");
2637 retval = -1;
2638 }
2639 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002640}
2641
2642static int iris_vidioc_s_ctrl(struct file *file, void *priv,
2643 struct v4l2_control *ctrl)
2644{
2645 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2646 int retval = 0;
2647 unsigned int rds_grps_proc = 0;
2648 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002649 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302650 struct hci_fm_tx_ps tx_ps = {0};
2651 struct hci_fm_tx_rt tx_rt = {0};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652
2653 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302654 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002655 radio->tone_freq = ctrl->value;
2656 retval = radio_hci_request(radio->fm_hdev,
2657 hci_fm_tone_generator, arg,
2658 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302659 if (retval < 0)
2660 FMDERR("Error while setting the tone %d", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002661 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662 case V4L2_CID_AUDIO_VOLUME:
2663 break;
2664 case V4L2_CID_AUDIO_MUTE:
2665 radio->mute_mode.hard_mute = ctrl->value;
2666 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
2667 retval = hci_set_fm_mute_mode(
2668 &radio->mute_mode,
2669 radio->fm_hdev);
2670 if (retval < 0)
2671 FMDERR("Error while set FM hard mute"" %d\n",
2672 retval);
2673 break;
2674 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2675 radio->g_search_mode = ctrl->value;
2676 break;
2677 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2678 radio->g_scan_time = ctrl->value;
2679 break;
2680 case V4L2_CID_PRIVATE_IRIS_SRCHON:
2681 iris_search(radio, ctrl->value, SRCH_DIR_UP);
2682 break;
2683 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002684 switch (ctrl->value) {
2685 case FM_RECV:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2687 radio->fm_hdev);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302688 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002689 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002690 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302691 return retval;
2692 }
2693 radio->mode = FM_RECV;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002694 radio->mute_mode.soft_mute = CTRL_ON;
2695 retval = hci_set_fm_mute_mode(
2696 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302698 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002699 FMDERR("Failed to enable Smute\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302700 return retval;
2701 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002702 radio->stereo_mode.stereo_mode = CTRL_OFF;
2703 radio->stereo_mode.sig_blend = CTRL_ON;
2704 radio->stereo_mode.intf_blend = CTRL_ON;
2705 radio->stereo_mode.most_switch = CTRL_ON;
2706 retval = hci_set_fm_stereo_mode(
2707 &radio->stereo_mode,
2708 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302709 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002710 FMDERR("Failed to set stereo mode\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302711 return retval;
2712 }
Srinivasa Rao Uppalaf1febce2011-11-09 10:30:16 +05302713 radio->event_mask = SIG_LEVEL_INTR |
2714 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2715 retval = hci_conf_event_mask(&radio->event_mask,
2716 radio->fm_hdev);
2717 if (retval < 0) {
2718 FMDERR("Enable Async events failed");
2719 return retval;
2720 }
Srinivasa Rao Uppalaf0d13742011-09-08 10:13:13 +05302721 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2722 radio->fm_hdev);
2723 if (retval < 0)
2724 FMDERR("Failed to get the Recv Config\n");
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002725 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002726 case FM_TRANS:
2727 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
2728 radio->fm_hdev);
2729 radio->mode = FM_TRANS;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302730 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002731 FMDERR("Error while enabling TRANS FM"
2732 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302733 return retval;
2734 }
2735 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
2736 if (retval < 0)
2737 FMDERR("get frequency failed %d\n", retval);
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002738 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002739 case FM_OFF:
2740 switch (radio->mode) {
2741 case FM_RECV:
2742 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2743 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002744 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002745 FMDERR("Err on disable recv FM"
2746 " %d\n", retval);
2747 break;
2748 case FM_TRANS:
2749 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
2750 radio->fm_hdev);
2751
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002752 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002753 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002754 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002755 break;
2756 default:
2757 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302759 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002760 default:
2761 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002762 }
2763 break;
2764 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002765 if (radio->mode == FM_RECV) {
2766 retval = iris_recv_set_region(radio, ctrl->value);
2767 } else {
2768 if (radio->mode == FM_TRANS)
2769 retval = iris_trans_set_region(radio,
2770 ctrl->value);
2771 else
2772 retval = -EINVAL;
2773 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002774 break;
2775 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2776 temp_val = ctrl->value;
2777 retval = hci_fm_set_signal_threshold(
2778 &temp_val,
2779 radio->fm_hdev);
2780 if (retval < 0) {
2781 FMDERR("Error while setting signal threshold\n");
2782 break;
2783 }
2784 break;
2785 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
2786 radio->srch_rds.srch_pty = ctrl->value;
2787 radio->srch_st_list.srch_pty = ctrl->value;
2788 break;
2789 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
2790 radio->srch_rds.srch_pi = ctrl->value;
2791 break;
2792 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
2793 break;
2794 case V4L2_CID_PRIVATE_IRIS_SPACING:
Venkateshwarlu Domakonda45496f12011-11-23 12:51:13 +05302795 if (radio->mode == FM_RECV) {
2796 radio->recv_conf.ch_spacing = ctrl->value;
2797 retval = hci_set_fm_recv_conf(
2798 &radio->recv_conf,
2799 radio->fm_hdev);
2800 if (retval < 0)
2801 FMDERR("Error in setting channel spacing");
2802 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002803 break;
2804 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002805 switch (radio->mode) {
2806 case FM_RECV:
2807 radio->recv_conf.emphasis = ctrl->value;
2808 retval = hci_set_fm_recv_conf(
2809 &radio->recv_conf,
2810 radio->fm_hdev);
2811 if (retval < 0)
2812 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002813 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002814 case FM_TRANS:
2815 radio->trans_conf.emphasis = ctrl->value;
2816 retval = hci_set_fm_trans_conf(
2817 &radio->trans_conf,
2818 radio->fm_hdev);
2819 if (retval < 0)
2820 FMDERR("Error in setting emphasis");
2821 break;
2822 default:
2823 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002824 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002825 break;
2826 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002827 switch (radio->mode) {
2828 case FM_RECV:
2829 radio->recv_conf.rds_std = ctrl->value;
2830 retval = hci_set_fm_recv_conf(
2831 &radio->recv_conf,
2832 radio->fm_hdev);
2833 if (retval < 0)
2834 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002835 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002836 case FM_TRANS:
2837 radio->trans_conf.rds_std = ctrl->value;
2838 retval = hci_set_fm_trans_conf(
2839 &radio->trans_conf,
2840 radio->fm_hdev);
2841 if (retval < 0)
2842 FMDERR("Error in rds_Std");
2843 break;
2844 default:
2845 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002846 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002847 break;
2848 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002849 switch (radio->mode) {
2850 case FM_RECV:
2851 radio->recv_conf.rds_std = ctrl->value;
2852 retval = hci_set_fm_recv_conf(
2853 &radio->recv_conf,
2854 radio->fm_hdev);
2855 if (retval < 0)
2856 FMDERR("Error in rds_std");
2857 break;
2858 case FM_TRANS:
2859 radio->trans_conf.rds_std = ctrl->value;
2860 retval = hci_set_fm_trans_conf(
2861 &radio->trans_conf,
2862 radio->fm_hdev);
2863 if (retval < 0)
2864 FMDERR("Error in rds_Std");
2865 break;
2866 default:
2867 retval = -EINVAL;
2868 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869 break;
2870 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2871 radio->rds_grp.rds_grp_enable_mask = ctrl->value;
2872 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
2873 break;
2874 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
2875 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002876 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002877 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002878 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879 radio->fm_hdev);
2880 break;
2881 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2882 radio->rds_grp.rds_buf_size = ctrl->value;
2883 break;
2884 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002885 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
2886 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2887 retval = hci_fm_rds_grps_process(
2888 &radio->g_rds_grp_proc_ps,
2889 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002890 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302891 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
2892 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_OFFSET);
2893 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2894 retval = hci_fm_rds_grps_process(
2895 &radio->g_rds_grp_proc_ps,
2896 radio->fm_hdev);
2897 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302899 set_low_power_mode(radio, ctrl->value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002900 break;
2901 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2902 temp_val = ctrl->value;
2903 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
2904 break;
2905 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002906 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002907 break;
2908 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002909 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002910 break;
2911 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302912 tx_ps.ps_control = 0x00;
2913 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2914 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002915 break;
2916 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302917 tx_rt.rt_control = 0x00;
2918 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2919 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920 break;
2921 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002922 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923 break;
2924 case V4L2_CID_TUNE_POWER_LEVEL:
2925 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002926 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2927 radio->mute_mode.soft_mute = ctrl->value;
2928 retval = hci_set_fm_mute_mode(
2929 &radio->mute_mode,
2930 radio->fm_hdev);
2931 if (retval < 0)
2932 FMDERR("Error while setting FM soft mute"" %d\n",
2933 retval);
2934 break;
2935 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
2936 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
2937 break;
2938 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
2939 radio->riva_data_req.cmd_params.length = ctrl->value;
2940 break;
2941 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
2942 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
2943 radio->riva_data_req.cmd_params.length);
2944 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
2945 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
2946 break;
2947 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
2948 radio->ssbi_data_accs.start_addr = ctrl->value;
2949 break;
2950 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
2951 radio->ssbi_data_accs.data = ctrl->value;
2952 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
2953 radio->fm_hdev);
2954 break;
2955 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
2956 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
2957 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
2958 radio->fm_hdev);
2959 break;
2960 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
2961 radio->ssbi_peek_reg.start_address = ctrl->value;
2962 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
2963 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302964 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
2965 temp_val = ctrl->value;
2966 hci_read_grp_counters(&temp_val, radio->fm_hdev);
2967 break;
2968 case V4L2_CID_PRIVATE_IRIS_HLSI:
2969 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2970 radio->fm_hdev);
2971 if (retval)
2972 break;
2973 radio->recv_conf.hlsi = ctrl->value;
2974 retval = hci_set_fm_recv_conf(
2975 &radio->recv_conf,
2976 radio->fm_hdev);
2977 break;
2978 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
2979 temp_val = ctrl->value;
2980 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
2981 break;
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05302982 case V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM:
Srinivasa Rao Uppalade0b5d92011-12-27 18:09:10 +05302983 case V4L2_CID_PRIVATE_IRIS_SET_AUDIO_PATH:
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05302984 /*
Srinivasa Rao Uppalade0b5d92011-12-27 18:09:10 +05302985 These private controls are place holders to keep the
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05302986 driver compatible with changes done in the frameworks
2987 which are specific to TAVARUA.
2988 */
2989 retval = 0;
2990 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002991 default:
2992 retval = -EINVAL;
2993 }
2994 return retval;
2995}
2996
2997static int iris_vidioc_g_tuner(struct file *file, void *priv,
2998 struct v4l2_tuner *tuner)
2999{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003001 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003002
Srinivasa Rao Uppalad2ec4682011-12-12 14:02:15 +05303003 if (tuner->index > 0) {
3004 FMDERR("Invalid Tuner Index");
3005 return -EINVAL;
3006 }
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303007 if (radio->mode == FM_RECV) {
3008 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3009 if (retval < 0) {
3010 FMDERR("Failed to Get station params");
3011 return retval;
3012 }
3013 tuner->type = V4L2_TUNER_RADIO;
3014 tuner->rangelow =
3015 radio->recv_conf.band_low_limit * TUNE_PARAM;
3016 tuner->rangehigh =
3017 radio->recv_conf.band_high_limit * TUNE_PARAM;
3018 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
3019 tuner->capability = V4L2_TUNER_CAP_LOW;
3020 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
3021 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
3022 tuner->afc = 0;
3023 } else if (radio->mode == FM_TRANS) {
3024 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
3025 if (retval < 0) {
3026 FMDERR("get Tx config failed %d\n", retval);
3027 return retval;
3028 } else {
3029 tuner->type = V4L2_TUNER_RADIO;
3030 tuner->rangelow =
3031 radio->trans_conf.band_low_limit * TUNE_PARAM;
3032 tuner->rangehigh =
3033 radio->trans_conf.band_high_limit * TUNE_PARAM;
3034 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003035
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303036 } else
3037 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003038 return 0;
3039}
3040
3041static int iris_vidioc_s_tuner(struct file *file, void *priv,
3042 struct v4l2_tuner *tuner)
3043{
3044 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07003045 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003046 if (tuner->index > 0)
3047 return -EINVAL;
3048
Ankur Nandwanid928d542011-08-11 13:15:41 -07003049 if (radio->mode == FM_RECV) {
3050 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
3051 radio->recv_conf.band_high_limit =
3052 tuner->rangehigh / TUNE_PARAM;
3053 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
3054 radio->stereo_mode.stereo_mode = 0x01;
3055 retval = hci_set_fm_stereo_mode(
3056 &radio->stereo_mode,
3057 radio->fm_hdev);
3058 } else {
3059 radio->stereo_mode.stereo_mode = 0x00;
3060 retval = hci_set_fm_stereo_mode(
3061 &radio->stereo_mode,
3062 radio->fm_hdev);
3063 }
3064 if (retval < 0)
3065 FMDERR(": set tuner failed with %d\n", retval);
3066 return retval;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303067 } else if (radio->mode == FM_TRANS) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003068 radio->trans_conf.band_low_limit =
3069 tuner->rangelow / TUNE_PARAM;
3070 radio->trans_conf.band_high_limit =
3071 tuner->rangehigh / TUNE_PARAM;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303072 } else
3073 return -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003074
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003075 return retval;
3076}
3077
3078static int iris_vidioc_g_frequency(struct file *file, void *priv,
3079 struct v4l2_frequency *freq)
3080{
3081 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Srinivasa Rao Uppalad2ec4682011-12-12 14:02:15 +05303082 if ((freq != NULL) && (radio != NULL)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083 freq->frequency =
3084 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
Srinivasa Rao Uppalad2ec4682011-12-12 14:02:15 +05303085 } else
3086 return -EINVAL;
3087 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088}
3089
3090static int iris_vidioc_s_frequency(struct file *file, void *priv,
3091 struct v4l2_frequency *freq)
3092{
3093 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3094 int retval = -1;
3095 freq->frequency = freq->frequency / TUNE_PARAM;
3096
3097 if (freq->type != V4L2_TUNER_RADIO)
3098 return -EINVAL;
3099
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003100 /* We turn off RDS prior to tuning to a new station.
3101 because of a bug in SoC which prevents tuning
3102 during RDS transmission.
3103 */
3104 if (radio->mode == FM_TRANS
3105 && (radio->trans_conf.rds_std == 0 ||
3106 radio->trans_conf.rds_std == 1)) {
3107 radio->prev_trans_rds = radio->trans_conf.rds_std;
3108 radio->trans_conf.rds_std = 2;
3109 hci_set_fm_trans_conf(&radio->trans_conf,
3110 radio->fm_hdev);
3111 }
3112
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003113 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003114
3115 if (radio->mode == FM_TRANS
3116 && radio->trans_conf.rds_std == 2
3117 && (radio->prev_trans_rds == 1
3118 || radio->prev_trans_rds == 0)) {
3119 radio->trans_conf.rds_std = radio->prev_trans_rds;
3120 hci_set_fm_trans_conf(&radio->trans_conf,
3121 radio->fm_hdev);
3122 }
3123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124 if (retval < 0)
3125 FMDERR(" set frequency failed with %d\n", retval);
3126 return retval;
3127}
3128
3129static int iris_vidioc_dqbuf(struct file *file, void *priv,
3130 struct v4l2_buffer *buffer)
3131{
3132 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3133 enum iris_buf_t buf_type = buffer->index;
3134 struct kfifo *data_fifo;
3135 unsigned char *buf = (unsigned char *)buffer->m.userptr;
3136 unsigned int len = buffer->length;
3137 if (!access_ok(VERIFY_WRITE, buf, len))
3138 return -EFAULT;
3139 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
3140 data_fifo = &radio->data_buf[buf_type];
3141 if (buf_type == IRIS_BUF_EVENTS)
3142 if (wait_event_interruptible(radio->event_queue,
3143 kfifo_len(data_fifo)) < 0)
3144 return -EINTR;
3145 } else {
3146 FMDERR("invalid buffer type\n");
3147 return -EINVAL;
3148 }
3149 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3150 &radio->buf_lock[buf_type]);
3151
3152 return 0;
3153}
3154
3155static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
3156 struct v4l2_format *f)
3157{
3158 return 0;
3159
3160}
3161
3162static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3163 struct v4l2_hw_freq_seek *seek)
3164{
3165 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3166 int dir;
3167 if (seek->seek_upward)
3168 dir = SRCH_DIR_UP;
3169 else
3170 dir = SRCH_DIR_DOWN;
3171 return iris_search(radio, CTRL_ON, dir);
3172}
3173
3174static int iris_vidioc_querycap(struct file *file, void *priv,
3175 struct v4l2_capability *capability)
3176{
3177 struct iris_device *radio;
3178 radio = video_get_drvdata(video_devdata(file));
3179 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
3180 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
3181 radio->g_cap = capability;
3182 return 0;
3183}
3184
3185
3186static const struct v4l2_ioctl_ops iris_ioctl_ops = {
3187 .vidioc_querycap = iris_vidioc_querycap,
3188 .vidioc_queryctrl = iris_vidioc_queryctrl,
3189 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
3190 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
3191 .vidioc_g_tuner = iris_vidioc_g_tuner,
3192 .vidioc_s_tuner = iris_vidioc_s_tuner,
3193 .vidioc_g_frequency = iris_vidioc_g_frequency,
3194 .vidioc_s_frequency = iris_vidioc_s_frequency,
3195 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
3196 .vidioc_dqbuf = iris_vidioc_dqbuf,
3197 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
3198 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303199 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200};
3201
3202static const struct v4l2_file_operations iris_fops = {
3203 .owner = THIS_MODULE,
3204 .unlocked_ioctl = video_ioctl2,
3205};
3206
3207static struct video_device iris_viddev_template = {
3208 .fops = &iris_fops,
3209 .ioctl_ops = &iris_ioctl_ops,
3210 .name = DRIVER_NAME,
3211 .release = video_device_release,
3212};
3213
3214static struct video_device *video_get_dev(void)
3215{
3216 return priv_videodev;
3217}
3218
3219static int __init iris_probe(struct platform_device *pdev)
3220{
3221 struct iris_device *radio;
3222 int retval;
3223 int radio_nr = -1;
3224 int i;
3225
3226 if (!pdev) {
3227 FMDERR(": pdev is null\n");
3228 return -ENOMEM;
3229 }
3230
3231 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
3232 if (!radio) {
3233 FMDERR(": Could not allocate radio device\n");
3234 return -ENOMEM;
3235 }
3236
3237 radio->dev = &pdev->dev;
3238 platform_set_drvdata(pdev, radio);
3239
3240 radio->videodev = video_device_alloc();
3241 if (!radio->videodev) {
3242 FMDERR(": Could not allocate V4L device\n");
3243 kfree(radio);
3244 return -ENOMEM;
3245 }
3246
3247 memcpy(radio->videodev, &iris_viddev_template,
3248 sizeof(iris_viddev_template));
3249
3250 for (i = 0; i < IRIS_BUF_MAX; i++) {
3251 int kfifo_alloc_rc = 0;
3252 spin_lock_init(&radio->buf_lock[i]);
3253
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07003254 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003255 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3256 rds_buf*3, GFP_KERNEL);
Srinivasa Rao Uppala69839842012-01-13 18:36:12 +05303257 else if ((i == IRIS_BUF_CAL_DATA) || (i == IRIS_BUF_RT_RDS))
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05303258 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3259 STD_BUF_SIZE*2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003260 else
3261 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3262 STD_BUF_SIZE, GFP_KERNEL);
3263
3264 if (kfifo_alloc_rc != 0) {
3265 FMDERR("failed allocating buffers %d\n",
3266 kfifo_alloc_rc);
3267 for (; i > -1; i--) {
3268 kfifo_free(&radio->data_buf[i]);
3269 kfree(radio);
3270 return -ENOMEM;
3271 }
3272 }
3273 }
3274
3275 mutex_init(&radio->lock);
3276 init_completion(&radio->sync_xfr_start);
3277 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003278 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003279 init_waitqueue_head(&radio->event_queue);
3280 init_waitqueue_head(&radio->read_queue);
3281
3282 video_set_drvdata(radio->videodev, radio);
3283
3284 if (NULL == video_get_drvdata(radio->videodev))
3285 FMDERR(": video_get_drvdata failed\n");
3286
3287 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
3288 radio_nr);
3289 if (retval) {
3290 FMDERR(": Could not register video device\n");
3291 video_device_release(radio->videodev);
3292 for (; i > -1; i--)
3293 kfifo_free(&radio->data_buf[i]);
3294 kfree(radio);
3295 return retval;
3296 } else {
3297 priv_videodev = kzalloc(sizeof(struct video_device),
3298 GFP_KERNEL);
3299 memcpy(priv_videodev, radio->videodev,
3300 sizeof(struct video_device));
3301 }
3302 return 0;
3303}
3304
3305
3306static int __devexit iris_remove(struct platform_device *pdev)
3307{
3308 int i;
3309 struct iris_device *radio = platform_get_drvdata(pdev);
3310
3311 video_unregister_device(radio->videodev);
3312
3313 for (i = 0; i < IRIS_BUF_MAX; i++)
3314 kfifo_free(&radio->data_buf[i]);
3315
3316 kfree(radio);
3317
3318 platform_set_drvdata(pdev, NULL);
3319
3320 return 0;
3321}
3322
3323static struct platform_driver iris_driver = {
3324 .driver = {
3325 .owner = THIS_MODULE,
3326 .name = "iris_fm",
3327 },
3328 .remove = __devexit_p(iris_remove),
3329};
3330
3331static int __init iris_radio_init(void)
3332{
3333 return platform_driver_probe(&iris_driver, iris_probe);
3334}
3335module_init(iris_radio_init);
3336
3337static void __exit iris_radio_exit(void)
3338{
3339 platform_driver_unregister(&iris_driver);
3340}
3341module_exit(iris_radio_exit);
3342
3343MODULE_LICENSE("GPL v2");
3344MODULE_AUTHOR(DRIVER_AUTHOR);
3345MODULE_DESCRIPTION(DRIVER_DESC);