blob: eb0c828a367bdc73a9de6e2db399b28eb714cff8 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#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 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422};
423
424static void iris_q_event(struct iris_device *radio,
425 enum iris_evt_t event)
426{
427 struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
428 unsigned char evt = event;
429 if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
430 wake_up_interruptible(&radio->event_queue);
431}
432
433static int hci_send_frame(struct sk_buff *skb)
434{
435 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
436
437 if (!hdev) {
438 kfree_skb(skb);
439 return -ENODEV;
440 }
441
442 __net_timestamp(skb);
443
444 skb_orphan(skb);
445 return hdev->send(skb);
446}
447
448static void radio_hci_cmd_task(unsigned long arg)
449{
450 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
451 struct sk_buff *skb;
452 if (!(atomic_read(&hdev->cmd_cnt))
453 && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
454 FMDERR("%s command tx timeout", hdev->name);
455 atomic_set(&hdev->cmd_cnt, 1);
456 }
457
458 skb = skb_dequeue(&hdev->cmd_q);
459 if (atomic_read(&hdev->cmd_cnt) && skb) {
460 kfree_skb(hdev->sent_cmd);
461 hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
462 if (hdev->sent_cmd) {
463 atomic_dec(&hdev->cmd_cnt);
464 hci_send_frame(skb);
465 hdev->cmd_last_tx = jiffies;
466 } else {
467 skb_queue_head(&hdev->cmd_q, skb);
468 tasklet_schedule(&hdev->cmd_task);
469 }
470 }
471
472}
473
474static void radio_hci_rx_task(unsigned long arg)
475{
476 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
477 struct sk_buff *skb;
478
479 read_lock(&hci_task_lock);
480
481 skb = skb_dequeue(&hdev->rx_q);
482 radio_hci_event_packet(hdev, skb);
483
484 read_unlock(&hci_task_lock);
485}
486
487int radio_hci_register_dev(struct radio_hci_dev *hdev)
488{
489 struct iris_device *radio = video_get_drvdata(video_get_dev());
490 if (!radio) {
491 FMDERR(":radio is null");
492 return -EINVAL;
493 }
494
495 if (!hdev) {
496 FMDERR("hdev is null");
497 return -EINVAL;
498 }
499
500 hdev->flags = 0;
501
502 tasklet_init(&hdev->cmd_task, radio_hci_cmd_task, (unsigned long)
503 hdev);
504 tasklet_init(&hdev->rx_task, radio_hci_rx_task, (unsigned long)
505 hdev);
506
507 init_waitqueue_head(&hdev->req_wait_q);
508
509 skb_queue_head_init(&hdev->rx_q);
510 skb_queue_head_init(&hdev->cmd_q);
511 skb_queue_head_init(&hdev->raw_q);
512
513 if (!radio)
514 FMDERR(":radio is null");
515
516 radio->fm_hdev = hdev;
517
518 return 0;
519}
520EXPORT_SYMBOL(radio_hci_register_dev);
521
522int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
523{
524 struct iris_device *radio = video_get_drvdata(video_get_dev());
525 if (!radio) {
526 FMDERR(":radio is null");
527 return -EINVAL;
528 }
529
530 tasklet_kill(&hdev->rx_task);
531 tasklet_kill(&hdev->cmd_task);
532 skb_queue_purge(&hdev->rx_q);
533 skb_queue_purge(&hdev->cmd_q);
534 skb_queue_purge(&hdev->raw_q);
535 kfree(radio->fm_hdev);
536 kfree(radio->videodev);
537
538 return 0;
539}
540EXPORT_SYMBOL(radio_hci_unregister_dev);
541
542int radio_hci_recv_frame(struct sk_buff *skb)
543{
544 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
545 if (!hdev) {
546 FMDERR("%s hdev is null while receiving frame", hdev->name);
547 kfree_skb(skb);
548 return -ENXIO;
549 }
550
551 __net_timestamp(skb);
552
553 radio_hci_event_packet(hdev, skb);
Srinivasa Rao Uppalacf3a8112011-09-22 21:02:02 +0530554 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 return 0;
556}
557EXPORT_SYMBOL(radio_hci_recv_frame);
558
559int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
560 void *param)
561{
562 int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
563 struct radio_hci_command_hdr *hdr;
564 struct sk_buff *skb;
565 int ret = 0;
566
567 skb = alloc_skb(len, GFP_ATOMIC);
568 if (!skb) {
569 FMDERR("%s no memory for command", hdev->name);
570 return -ENOMEM;
571 }
572
573 hdr = (struct radio_hci_command_hdr *) skb_put(skb,
574 RADIO_HCI_COMMAND_HDR_SIZE);
575 hdr->opcode = cpu_to_le16(opcode);
576 hdr->plen = plen;
577
578 if (plen)
579 memcpy(skb_put(skb, plen), param, plen);
580
581 skb->dev = (void *) hdev;
582
583 ret = hci_send_frame(skb);
584
585 return ret;
586}
587EXPORT_SYMBOL(radio_hci_send_cmd);
588
589static int hci_fm_enable_recv_req(struct radio_hci_dev *hdev,
590 unsigned long param)
591{
592 __u16 opcode = 0;
593
594 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
595 HCI_OCF_FM_ENABLE_RECV_REQ);
596 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
597}
598
Ankur Nandwanid928d542011-08-11 13:15:41 -0700599static int hci_fm_tone_generator(struct radio_hci_dev *hdev,
600 unsigned long param)
601{
602 struct iris_device *radio = video_get_drvdata(video_get_dev());
603 __u16 opcode = 0;
604
605 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
606 HCI_FM_SET_INTERNAL_TONE_GENRATOR);
607 return radio_hci_send_cmd(hdev, opcode,
608 sizeof(radio->tone_freq), &radio->tone_freq);
609}
610
611static int hci_fm_enable_trans_req(struct radio_hci_dev *hdev,
612 unsigned long param)
613{
614 __u16 opcode = 0;
615
616 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
617 HCI_OCF_FM_ENABLE_TRANS_REQ);
618 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
619}
620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621static int hci_fm_disable_recv_req(struct radio_hci_dev *hdev,
622 unsigned long param)
623{
624 __u16 opcode = 0;
625
626 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
627 HCI_OCF_FM_DISABLE_RECV_REQ);
628 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
629}
630
Ankur Nandwanid928d542011-08-11 13:15:41 -0700631static int hci_fm_disable_trans_req(struct radio_hci_dev *hdev,
632 unsigned long param)
633{
634 __u16 opcode = 0;
635
636 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
637 HCI_OCF_FM_DISABLE_TRANS_REQ);
638 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
639}
640
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641static int hci_get_fm_recv_conf_req(struct radio_hci_dev *hdev,
642 unsigned long param)
643{
644 __u16 opcode = 0;
645
646 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
647 HCI_OCF_FM_GET_RECV_CONF_REQ);
648 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
649}
650
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +0530651static int hci_get_fm_trans_conf_req(struct radio_hci_dev *hdev,
652 unsigned long param)
653{
654 u16 opcode = 0;
655
656 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
657 HCI_OCF_FM_GET_TRANS_CONF_REQ);
658 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
659}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
661 unsigned long param)
662{
663 __u16 opcode = 0;
664
665 struct hci_fm_recv_conf_req *recv_conf_req =
666 (struct hci_fm_recv_conf_req *) param;
667
668 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
669 HCI_OCF_FM_SET_RECV_CONF_REQ);
670 return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
671 recv_conf_req);
672}
673
Ankur Nandwanid928d542011-08-11 13:15:41 -0700674static int hci_set_fm_trans_conf_req(struct radio_hci_dev *hdev,
675 unsigned long param)
676{
677 __u16 opcode = 0;
678
679 struct hci_fm_trans_conf_req_struct *trans_conf_req =
680 (struct hci_fm_trans_conf_req_struct *) param;
681
682 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
683 HCI_OCF_FM_SET_TRANS_CONF_REQ);
684 return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
685 trans_conf_req);
686}
687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
689 unsigned long param)
690{
691 __u16 opcode = 0;
692
693 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
694 HCI_OCF_FM_GET_STATION_PARAM_REQ);
695 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
696}
697
698static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
699 unsigned long param)
700{
701 __u16 opcode = 0;
702 struct hci_fm_mute_mode_req *mute_mode_req =
703 (struct hci_fm_mute_mode_req *) param;
704
705 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
706 HCI_OCF_FM_SET_MUTE_MODE_REQ);
707 return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
708 mute_mode_req);
709}
710
Ankur Nandwanid928d542011-08-11 13:15:41 -0700711
712static int hci_trans_ps_req(struct radio_hci_dev *hdev,
713 unsigned long param)
714{
715 __u16 opcode = 0;
716 struct hci_fm_tx_ps *tx_ps_req =
717 (struct hci_fm_tx_ps *) param;
718
719 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
720 HCI_OCF_FM_RDS_PS_REQ);
721
722 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_ps_req)),
723 tx_ps_req);
724}
725
726static int hci_trans_rt_req(struct radio_hci_dev *hdev,
727 unsigned long param)
728{
729 __u16 opcode = 0;
730 struct hci_fm_tx_rt *tx_rt_req =
731 (struct hci_fm_tx_rt *) param;
732
733 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
734 HCI_OCF_FM_RDS_RT_REQ);
735
736 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_rt_req)),
737 tx_rt_req);
738}
739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700740static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
741 unsigned long param)
742{
743 __u16 opcode = 0;
744 struct hci_fm_stereo_mode_req *stereo_mode_req =
745 (struct hci_fm_stereo_mode_req *) param;
746 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
747 HCI_OCF_FM_SET_STEREO_MODE_REQ);
748 return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
749 stereo_mode_req);
750}
751
752static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
753 unsigned long param)
754{
755 __u16 opcode = 0;
756
757 __u8 antenna = param;
758
759 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
760 HCI_OCF_FM_SET_ANTENNA);
761 return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
762}
763
764static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
765 unsigned long param)
766{
767 __u16 opcode = 0;
768
769 __u8 sig_threshold = param;
770
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530771 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
773 return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
774 &sig_threshold);
775}
776
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +0530777static int hci_fm_set_event_mask(struct radio_hci_dev *hdev,
778 unsigned long param)
779{
780 u16 opcode = 0;
781 u8 event_mask = param;
782
783 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
784 HCI_OCF_FM_SET_EVENT_MASK);
785 return radio_hci_send_cmd(hdev, opcode, sizeof(event_mask),
786 &event_mask);
787}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
789 unsigned long param)
790{
791 __u16 opcode = 0;
792
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530793 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700794 HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
795 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
796}
797
798static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
799 unsigned long param)
800{
801 __u16 opcode = 0;
802
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530803 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
805 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
806}
807
808static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
809 unsigned long param)
810{
811 __u16 opcode = 0;
812
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530813 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814 HCI_OCF_FM_GET_RADIO_TEXT_REQ);
815 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
816}
817
818static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
819 unsigned long param)
820{
821 __u16 opcode = 0;
822
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530823 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 HCI_OCF_FM_GET_AF_LIST_REQ);
825 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
826}
827
828static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
829 unsigned long param)
830{
831 __u16 opcode = 0;
832 struct hci_fm_search_station_req *srch_stations =
833 (struct hci_fm_search_station_req *) param;
834
835 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
836 HCI_OCF_FM_SEARCH_STATIONS);
837 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
838 srch_stations);
839}
840
841static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
842 unsigned long param)
843{
844 __u16 opcode = 0;
845 struct hci_fm_search_rds_station_req *srch_stations =
846 (struct hci_fm_search_rds_station_req *) param;
847
848 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
849 HCI_OCF_FM_SEARCH_RDS_STATIONS);
850 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
851 srch_stations);
852}
853
854static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
855 unsigned long param)
856{
857 __u16 opcode = 0;
858 struct hci_fm_search_station_list_req *srch_list =
859 (struct hci_fm_search_station_list_req *) param;
860
861 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
862 HCI_OCF_FM_SEARCH_STATIONS_LIST);
863 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
864 srch_list);
865}
866
867static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
868 unsigned long param)
869{
870 __u16 opcode = 0;
871
872 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
873 HCI_OCF_FM_CANCEL_SEARCH);
874 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
875}
876
877static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
878 unsigned long param)
879{
880 __u16 opcode = 0;
881
882 __u32 fm_grps_process = param;
883
884 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
885 HCI_OCF_FM_RDS_GRP_PROCESS);
886 return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
887 &fm_grps_process);
888}
889
890static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
891 unsigned long param)
892{
893 __u16 opcode = 0;
894
895 __u32 tune_freq = param;
896
897 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
898 HCI_OCF_FM_TUNE_STATION_REQ);
899 return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
900}
901
902static int hci_def_data_read_req(struct radio_hci_dev *hdev,
903 unsigned long param)
904{
905 __u16 opcode = 0;
906 struct hci_fm_def_data_rd_req *def_data_rd =
907 (struct hci_fm_def_data_rd_req *) param;
908
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530909 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 HCI_OCF_FM_DEFAULT_DATA_READ);
911 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
912 def_data_rd);
913}
914
915static int hci_def_data_write_req(struct radio_hci_dev *hdev,
916 unsigned long param)
917{
918 __u16 opcode = 0;
919 struct hci_fm_def_data_wr_req *def_data_wr =
920 (struct hci_fm_def_data_wr_req *) param;
921
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530922 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 HCI_OCF_FM_DEFAULT_DATA_WRITE);
924 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
925 def_data_wr);
926}
927
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530928static int hci_set_notch_filter_req(struct radio_hci_dev *hdev,
929 unsigned long param)
930{
931 __u16 opcode = 0;
932 __u8 notch_filter_val = param;
933
934 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
935 HCI_OCF_FM_EN_NOTCH_CTRL);
936 return radio_hci_send_cmd(hdev, opcode, sizeof(notch_filter_val),
937 &notch_filter_val);
938}
939
940
941
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
943{
944 __u16 opcode = 0;
945
946 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
947 HCI_OCF_FM_RESET);
948 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
949}
950
951static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
952 unsigned long param)
953{
954 __u16 opcode = 0;
955
956 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
957 HCI_OCF_FM_GET_FEATURE_LIST);
958 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
959}
960
961static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
962 unsigned long param)
963{
964 __u16 opcode = 0;
965
966 __u8 mode = param;
967
968 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
969 HCI_OCF_FM_DO_CALIBRATION);
970 return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
971}
972
973static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
974 unsigned long param)
975{
976 __u16 opcode = 0;
977
978 __u8 reset_counters = param;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530979 opcode = hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700980 HCI_OCF_FM_READ_GRP_COUNTERS);
981 return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
982 &reset_counters);
983}
984
985static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
986{
987 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700988 struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700990 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991 HCI_OCF_FM_PEEK_DATA);
992 return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
993 peek_data);
994}
995
996static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
997{
998 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700999 struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07001001 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001002 HCI_OCF_FM_POKE_DATA);
1003 return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
1004 poke_data);
1005}
1006
1007static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
1008 unsigned long param)
1009{
1010 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001011 struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001013 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 HCI_OCF_FM_SSBI_PEEK_REG);
1015 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
1016 ssbi_peek);
1017}
1018
1019static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
1020 unsigned long param)
1021{
1022 __u16 opcode = 0;
1023 struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
1024
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001025 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 HCI_OCF_FM_SSBI_POKE_REG);
1027 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
1028 ssbi_poke);
1029}
1030
1031static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
1032 unsigned long param)
1033{
1034 __u16 opcode = 0;
1035
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +05301036 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001037 HCI_OCF_FM_STATION_DBG_PARAM);
1038 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1039}
1040
1041static int radio_hci_err(__u16 code)
1042{
1043 switch (code) {
1044 case 0:
1045 return 0;
1046 case 0x01:
1047 return -EBADRQC;
1048 case 0x02:
1049 return -ENOTCONN;
1050 case 0x03:
1051 return -EIO;
1052 case 0x07:
1053 return -ENOMEM;
1054 case 0x0c:
1055 return -EBUSY;
1056 case 0x11:
1057 return -EOPNOTSUPP;
1058 case 0x12:
1059 return -EINVAL;
1060 default:
1061 return -ENOSYS;
1062 }
1063}
1064
1065static int __radio_hci_request(struct radio_hci_dev *hdev,
1066 int (*req)(struct radio_hci_dev *hdev,
1067 unsigned long param),
1068 unsigned long param, __u32 timeout)
1069{
1070 int err = 0;
1071
1072 DECLARE_WAITQUEUE(wait, current);
1073
1074 hdev->req_status = HCI_REQ_PEND;
1075
1076 add_wait_queue(&hdev->req_wait_q, &wait);
1077 set_current_state(TASK_INTERRUPTIBLE);
1078
1079 err = req(hdev, param);
1080
1081 schedule_timeout(timeout);
1082
1083 remove_wait_queue(&hdev->req_wait_q, &wait);
1084
1085 if (signal_pending(current))
1086 return -EINTR;
1087
1088 switch (hdev->req_status) {
1089 case HCI_REQ_DONE:
1090 case HCI_REQ_STATUS:
1091 err = radio_hci_err(hdev->req_result);
1092 break;
1093
1094 case HCI_REQ_CANCELED:
1095 err = -hdev->req_result;
1096 break;
1097
1098 default:
1099 err = -ETIMEDOUT;
1100 break;
1101 }
1102
1103 hdev->req_status = hdev->req_result = 0;
1104
1105 return err;
1106}
1107
1108static inline int radio_hci_request(struct radio_hci_dev *hdev,
1109 int (*req)(struct
1110 radio_hci_dev * hdev, unsigned long param),
1111 unsigned long param, __u32 timeout)
1112{
1113 int ret = 0;
1114
1115 ret = __radio_hci_request(hdev, req, param, timeout);
1116
1117 return ret;
1118}
1119
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301120static inline int hci_conf_event_mask(__u8 *arg,
1121 struct radio_hci_dev *hdev)
1122{
1123 u8 event_mask = *arg;
1124 return radio_hci_request(hdev, hci_fm_set_event_mask,
1125 event_mask, RADIO_HCI_TIMEOUT);
1126}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
1128 struct radio_hci_dev *hdev)
1129{
1130 int ret = 0;
1131 struct hci_fm_recv_conf_req *set_recv_conf = arg;
1132
1133 ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
1134 long)set_recv_conf, RADIO_HCI_TIMEOUT);
1135
1136 return ret;
1137}
1138
Ankur Nandwanid928d542011-08-11 13:15:41 -07001139static int hci_set_fm_trans_conf(struct hci_fm_trans_conf_req_struct *arg,
1140 struct radio_hci_dev *hdev)
1141{
1142 int ret = 0;
1143 struct hci_fm_trans_conf_req_struct *set_trans_conf = arg;
1144
1145 ret = radio_hci_request(hdev, hci_set_fm_trans_conf_req, (unsigned
1146 long)set_trans_conf, RADIO_HCI_TIMEOUT);
1147
1148 return ret;
1149}
1150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
1152{
1153 int ret = 0;
1154 __u32 tune_freq = *arg;
1155
1156 ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
1157 RADIO_HCI_TIMEOUT);
1158
1159 return ret;
1160}
1161
1162static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
1163 struct radio_hci_dev *hdev)
1164{
1165 int ret = 0;
1166 struct hci_fm_mute_mode_req *set_mute_conf = arg;
1167
1168 ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
1169 long)set_mute_conf, RADIO_HCI_TIMEOUT);
1170
1171 return ret;
1172}
1173
1174static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
1175 struct radio_hci_dev *hdev)
1176{
1177 int ret = 0;
1178 struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
1179
1180 ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
1181 long)set_stereo_conf, RADIO_HCI_TIMEOUT);
1182
1183 return ret;
1184}
1185
1186static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
1187{
1188 int ret = 0;
1189 __u8 antenna = *arg;
1190
1191 ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
1192 RADIO_HCI_TIMEOUT);
1193
1194 return ret;
1195}
1196
1197static int hci_fm_set_signal_threshold(__u8 *arg,
1198 struct radio_hci_dev *hdev)
1199{
1200 int ret = 0;
1201 __u8 sig_threshold = *arg;
1202
1203 ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
1204 sig_threshold, RADIO_HCI_TIMEOUT);
1205
1206 return ret;
1207}
1208
1209static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
1210 struct radio_hci_dev *hdev)
1211{
1212 int ret = 0;
1213 struct hci_fm_search_station_req *srch_stations = arg;
1214
1215 ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
1216 long)srch_stations, RADIO_HCI_TIMEOUT);
1217
1218 return ret;
1219}
1220
1221static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
1222 struct radio_hci_dev *hdev)
1223{
1224 int ret = 0;
1225 struct hci_fm_search_rds_station_req *srch_stations = arg;
1226
1227 ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
1228 long)srch_stations, RADIO_HCI_TIMEOUT);
1229
1230 return ret;
1231}
1232
1233static int hci_fm_search_station_list
1234 (struct hci_fm_search_station_list_req *arg,
1235 struct radio_hci_dev *hdev)
1236{
1237 int ret = 0;
1238 struct hci_fm_search_station_list_req *srch_list = arg;
1239
1240 ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
1241 long)srch_list, RADIO_HCI_TIMEOUT);
1242
1243 return ret;
1244}
1245
1246static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
1247 struct radio_hci_dev *hdev)
1248{
1249 return 0;
1250}
1251
1252static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
1253{
1254 int ret = 0;
1255 __u32 fm_grps_process = *arg;
1256
1257 ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
1258 fm_grps_process, RADIO_HCI_TIMEOUT);
1259
1260 return ret;
1261}
1262
1263int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
1264 struct radio_hci_dev *hdev)
1265{
1266 int ret = 0;
1267 struct hci_fm_def_data_rd_req *def_data_rd = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
1269 long)def_data_rd, RADIO_HCI_TIMEOUT);
1270
1271 return ret;
1272}
1273
1274int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
1275 struct radio_hci_dev *hdev)
1276{
1277 int ret = 0;
1278 struct hci_fm_def_data_wr_req *def_data_wr = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
1280 long)def_data_wr, RADIO_HCI_TIMEOUT);
1281
1282 return ret;
1283}
1284
1285int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
1286{
1287 int ret = 0;
1288 __u8 mode = *arg;
1289
1290 ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
1291 RADIO_HCI_TIMEOUT);
1292
1293 return ret;
1294}
1295
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301296static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297{
1298 int ret = 0;
1299 __u8 reset_counters = *arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 ret = radio_hci_request(hdev, hci_read_grp_counters_req,
1301 reset_counters, RADIO_HCI_TIMEOUT);
1302
1303 return ret;
1304}
1305
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301306static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
1307{
1308 int ret = 0;
1309 __u8 notch_filter = *arg;
1310 ret = radio_hci_request(hdev, hci_set_notch_filter_req,
1311 notch_filter, RADIO_HCI_TIMEOUT);
1312
1313 return ret;
1314}
1315
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001316static int hci_peek_data(struct hci_fm_riva_data *arg,
1317 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318{
1319 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001320 struct hci_fm_riva_data *peek_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321
1322 ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
1323 long)peek_data, RADIO_HCI_TIMEOUT);
1324
1325 return ret;
1326}
1327
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001328static int hci_poke_data(struct hci_fm_riva_poke *arg,
1329 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330{
1331 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001332 struct hci_fm_riva_poke *poke_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333
1334 ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
1335 long)poke_data, RADIO_HCI_TIMEOUT);
1336
1337 return ret;
1338}
1339
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001340static int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *arg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 struct radio_hci_dev *hdev)
1342{
1343 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001344 struct hci_fm_ssbi_peek *ssbi_peek_reg = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345
1346 ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
1347 long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
1348
1349 return ret;
1350}
1351
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001352static int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg,
1353 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354{
1355 int ret = 0;
1356 struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
1357
1358 ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
1359 long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
1360
1361 return ret;
1362}
1363
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301364static int hci_fm_set_cal_req_proc(struct radio_hci_dev *hdev,
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301365 unsigned long param)
1366{
1367 u16 opcode = 0;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301368 struct hci_fm_set_cal_req_proc *cal_req =
1369 (struct hci_fm_set_cal_req_proc *)param;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301370
1371 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1372 HCI_OCF_FM_SET_CALIBRATION);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301373 return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301374 cal_req);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301375}
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301376
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301377static int hci_fm_set_cal_req_dc(struct radio_hci_dev *hdev,
1378 unsigned long param)
1379{
1380 u16 opcode = 0;
1381 struct hci_fm_set_cal_req_dc *cal_req =
1382 (struct hci_fm_set_cal_req_dc *)param;
1383
1384 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1385 HCI_OCF_FM_SET_CALIBRATION);
1386 return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
1387 cal_req);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301388}
1389
1390static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
1391 unsigned long param)
1392{
1393 u16 opcode = 0;
1394 u8 cal_mode = param;
1395
1396 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1397 HCI_OCF_FM_DO_CALIBRATION);
1398 return radio_hci_send_cmd(hdev, opcode, sizeof(cal_mode),
1399 &cal_mode);
1400
1401}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1403{
1404 int ret = 0;
1405 unsigned long arg = 0;
1406
Ankur Nandwanid928d542011-08-11 13:15:41 -07001407 if (!hdev)
1408 return -ENODEV;
1409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410 switch (cmd) {
1411 case HCI_FM_ENABLE_RECV_CMD:
1412 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1413 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1414 break;
1415
1416 case HCI_FM_DISABLE_RECV_CMD:
1417 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1418 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1419 break;
1420
1421 case HCI_FM_GET_RECV_CONF_CMD:
1422 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1423 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1424 break;
1425
1426 case HCI_FM_GET_STATION_PARAM_CMD:
1427 ret = radio_hci_request(hdev,
1428 hci_fm_get_station_param_req, arg,
1429 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1430 break;
1431
1432 case HCI_FM_GET_SIGNAL_TH_CMD:
1433 ret = radio_hci_request(hdev,
1434 hci_fm_get_sig_threshold_req, arg,
1435 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1436 break;
1437
1438 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1439 ret = radio_hci_request(hdev,
1440 hci_fm_get_program_service_req, arg,
1441 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1442 break;
1443
1444 case HCI_FM_GET_RADIO_TEXT_CMD:
1445 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1446 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1447 break;
1448
1449 case HCI_FM_GET_AF_LIST_CMD:
1450 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1451 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1452 break;
1453
1454 case HCI_FM_CANCEL_SEARCH_CMD:
1455 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1456 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1457 break;
1458
1459 case HCI_FM_RESET_CMD:
1460 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1461 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1462 break;
1463
1464 case HCI_FM_GET_FEATURES_CMD:
1465 ret = radio_hci_request(hdev,
1466 hci_fm_get_feature_lists_req, arg,
1467 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1468 break;
1469
1470 case HCI_FM_STATION_DBG_PARAM_CMD:
1471 ret = radio_hci_request(hdev,
1472 hci_fm_get_station_dbg_param_req, arg,
1473 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1474 break;
1475
Ankur Nandwanid928d542011-08-11 13:15:41 -07001476 case HCI_FM_ENABLE_TRANS_CMD:
1477 ret = radio_hci_request(hdev, hci_fm_enable_trans_req, arg,
1478 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1479 break;
1480
1481 case HCI_FM_DISABLE_TRANS_CMD:
1482 ret = radio_hci_request(hdev, hci_fm_disable_trans_req, arg,
1483 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1484 break;
1485
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301486 case HCI_FM_GET_TX_CONFIG:
1487 ret = radio_hci_request(hdev, hci_get_fm_trans_conf_req, arg,
1488 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1489 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490 default:
1491 ret = -EINVAL;
1492 break;
1493 }
1494
1495 return ret;
1496}
1497
1498static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1499{
1500 hdev->req_result = result;
1501 hdev->req_status = HCI_REQ_DONE;
1502 wake_up_interruptible(&hdev->req_wait_q);
1503}
1504
1505static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1506{
1507 hdev->req_result = result;
1508 hdev->req_status = HCI_REQ_STATUS;
1509 wake_up_interruptible(&hdev->req_wait_q);
1510}
1511
1512static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1513{
1514 __u8 status = *((__u8 *) skb->data);
1515
1516 if (status)
1517 return;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519 radio_hci_req_complete(hdev, status);
1520}
1521
1522static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1523 struct sk_buff *skb)
1524{
1525 __u8 status = *((__u8 *) skb->data);
1526 struct iris_device *radio = video_get_drvdata(video_get_dev());
1527
1528 if (status)
1529 return;
1530
1531 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1532
1533 radio_hci_req_complete(hdev, status);
1534}
1535
1536static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1537{
1538 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1539 struct iris_device *radio = video_get_drvdata(video_get_dev());
1540
1541 if (rsp->status)
1542 return;
1543
1544 radio->recv_conf = rsp->recv_conf_rsp;
1545 radio_hci_req_complete(hdev, rsp->status);
1546}
1547
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301548static void hci_cc_fm_trans_get_conf_rsp(struct radio_hci_dev *hdev,
1549 struct sk_buff *skb)
1550{
1551 struct hci_fm_get_trans_conf_rsp *rsp = (void *)skb->data;
1552 struct iris_device *radio = video_get_drvdata(video_get_dev());
1553
1554 if (rsp->status)
1555 return;
1556 memcpy((void *)&radio->trans_conf, (void*)&rsp->trans_conf_rsp,
1557 sizeof(rsp->trans_conf_rsp));
1558 radio_hci_req_complete(hdev, rsp->status);
1559}
1560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1562 struct sk_buff *skb)
1563{
1564 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1565 struct iris_device *radio = video_get_drvdata(video_get_dev());
1566
1567 if (rsp->status)
1568 return;
1569
1570 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1571
1572 radio_hci_req_complete(hdev, rsp->status);
1573}
1574
Ankur Nandwanid928d542011-08-11 13:15:41 -07001575
1576static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
1577 struct sk_buff *skb)
1578{
1579 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1580 struct iris_device *radio = video_get_drvdata(video_get_dev());
1581
1582 if (rsp->status)
1583 return;
1584
1585 iris_q_event(radio, HCI_EV_CMD_COMPLETE);
1586
1587 radio_hci_req_complete(hdev, rsp->status);
1588}
1589
1590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1592 struct sk_buff *skb)
1593{
1594 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1595 struct iris_device *radio = video_get_drvdata(video_get_dev());
1596 struct v4l2_control *v4l_ctl = radio->g_ctl;
1597
1598 if (rsp->status)
1599 return;
1600
1601 v4l_ctl->value = rsp->sig_threshold;
1602
1603 radio_hci_req_complete(hdev, rsp->status);
1604}
1605
1606static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1607{
1608 struct iris_device *radio = video_get_drvdata(video_get_dev());
1609 struct hci_fm_station_rsp *rsp = (void *)skb->data;
1610 radio->fm_st_rsp = *(rsp);
1611
1612 /* Tune is always succesful */
1613 radio_hci_req_complete(hdev, 0);
1614}
1615
1616static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1617{
1618 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1619
1620 if (rsp->status)
1621 return;
1622
1623 radio_hci_req_complete(hdev, rsp->status);
1624}
1625
1626static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1627{
1628 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1629
1630 if (rsp->status)
1631 return;
1632
1633 radio_hci_req_complete(hdev, rsp->status);
1634}
1635
1636static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1637{
1638 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1639
1640 if (rsp->status)
1641 return;
1642
1643 radio_hci_req_complete(hdev, rsp->status);
1644}
1645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1647 struct sk_buff *skb)
1648{
1649 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1650 struct iris_device *radio = video_get_drvdata(video_get_dev());
1651 struct v4l2_capability *v4l_cap = radio->g_cap;
1652
1653 if (rsp->status)
1654 return;
1655 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1656 (rsp->feature_mask & 0x000001);
1657
1658 radio_hci_req_complete(hdev, rsp->status);
1659}
1660
1661static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1662 struct sk_buff *skb)
1663{
1664 struct iris_device *radio = video_get_drvdata(video_get_dev());
1665 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
1666 radio->st_dbg_param = *(rsp);
1667
1668 if (radio->st_dbg_param.status)
1669 return;
1670
1671 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1672}
1673
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001674static void iris_q_evt_data(struct iris_device *radio,
1675 char *data, int len, int event)
1676{
1677 struct kfifo *data_b = &radio->data_buf[event];
1678 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1679 wake_up_interruptible(&radio->event_queue);
1680}
1681
1682static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1683 struct sk_buff *skb)
1684{
1685 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301686 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001687 int len;
1688 char *data;
1689
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301690 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001691 return;
1692 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1693 data = kmalloc(len, GFP_ATOMIC);
1694
1695 if (!data) {
1696 FMDERR("Memory allocation failed");
1697 return;
1698 }
1699
1700 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1701 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301702 radio_hci_req_complete(hdev, status);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301703 kfree(data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001704
1705}
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301706
1707static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
1708 struct sk_buff *skb)
1709{
1710 struct iris_device *radio = video_get_drvdata(video_get_dev());
1711 __u8 status = *((__u8 *) skb->data);
1712 __u8 len;
1713 char *data;
1714
1715 if (status)
1716 return;
1717 len = skb->data[1];
1718 data = kmalloc(len+2, GFP_ATOMIC);
1719 if (!data) {
1720 FMDERR("Memory allocation failed");
1721 return;
1722 }
1723
1724 data[0] = status;
1725 data[1] = len;
1726 memcpy(&data[2], &skb->data[DEFAULT_DATA_OFFSET], len);
1727 iris_q_evt_data(radio, data, len+2, IRIS_BUF_RD_DEFAULT);
1728 radio_hci_req_complete(hdev, status);
1729 kfree(data);
1730}
1731
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001732static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1733 struct sk_buff *skb)
1734{
1735 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301736 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001737 char *data;
1738
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301739 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001740 return;
1741 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1742 if (!data) {
1743 FMDERR("Memory allocation failed");
1744 return;
1745 }
1746
1747 data[0] = skb->data[PEEK_DATA_OFSET];
1748 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301749 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001750 kfree(data);
1751}
1752
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301753static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
1754 struct sk_buff *skb)
1755{
1756 struct iris_device *radio = video_get_drvdata(video_get_dev());
1757 __u8 status = *((__u8 *) skb->data);
1758 char *data;
1759 if (status)
1760 return;
1761 data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
1762 if (!data) {
1763 FMDERR("memory allocation failed");
1764 return;
1765 }
1766 memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
1767 iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
1768 radio_hci_req_complete(hdev, status);
1769 kfree(data);
1770
1771}
1772
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301773static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
1774 struct sk_buff *skb)
1775{
1776 struct iris_device *radio = video_get_drvdata(video_get_dev());
1777 static struct hci_cc_do_calibration_rsp rsp ;
1778 rsp.status = skb->data[0];
1779 rsp.mode = skb->data[CALIB_MODE_OFSET];
1780
1781 if (rsp.status) {
1782 FMDERR("status = %d", rsp.status);
1783 return;
1784 }
1785 if (rsp.mode == PROCS_CALIB_MODE) {
1786 memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
1787 PROCS_CALIB_SIZE);
1788 } else if (rsp.mode == DC_CALIB_MODE) {
1789 memcpy(&rsp.data[PROCS_CALIB_SIZE],
1790 &skb->data[CALIB_DATA_OFSET], DC_CALIB_SIZE);
1791 iris_q_evt_data(radio, rsp.data, (PROCS_CALIB_SIZE +
1792 DC_CALIB_SIZE), IRIS_BUF_CAL_DATA);
1793 }
1794 radio_hci_req_complete(hdev, rsp.status);
1795}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
1797 struct sk_buff *skb)
1798{
1799 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
1800 __u16 opcode;
1801
1802 skb_pull(skb, sizeof(*cmd_compl_ev));
1803
1804 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
1805
1806 switch (opcode) {
1807 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
1808 hci_cc_fm_enable_rsp(hdev, skb);
1809 break;
1810 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
1811 hci_cc_conf_rsp(hdev, skb);
1812 break;
1813
1814 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
1815 hci_cc_fm_disable_rsp(hdev, skb);
1816 break;
1817
1818 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
1819 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
1820 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
1821 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
1822 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
1823 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
1824 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
1825 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
1826 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
1827 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001828 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
1829 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
1830 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
1831 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301833 hci_cc_rsp(hdev, skb);
1834 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001837 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001838 case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301839 case hci_common_cmd_op_pack(HCI_OCF_FM_SET_CALIBRATION):
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301840 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_EVENT_MASK):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841 hci_cc_rsp(hdev, skb);
1842 break;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301843
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001844 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
1845 hci_cc_ssbi_peek_rsp(hdev, skb);
1846 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
1848 hci_cc_sig_threshold_rsp(hdev, skb);
1849 break;
1850
1851 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
1852 hci_cc_station_rsp(hdev, skb);
1853 break;
1854
1855 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
1856 hci_cc_prg_srv_rsp(hdev, skb);
1857 break;
1858
1859 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
1860 hci_cc_rd_txt_rsp(hdev, skb);
1861 break;
1862
1863 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
1864 hci_cc_af_list_rsp(hdev, skb);
1865 break;
1866
1867 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301868 hci_cc_riva_read_default_rsp(hdev, skb);
1869 break;
1870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001872 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873 break;
1874
1875 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
1876 hci_cc_feature_list_rsp(hdev, skb);
1877 break;
1878
1879 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
1880 hci_cc_dbg_param_rsp(hdev, skb);
1881 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07001882 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_SET_TRANS_CONF_REQ):
1883 hci_cc_fm_trans_set_conf_rsp(hdev, skb);
1884 break;
1885
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301886 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
1887 hci_cc_rds_grp_cntrs_rsp(hdev, skb);
1888 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301889 case hci_common_cmd_op_pack(HCI_OCF_FM_DO_CALIBRATION):
1890 hci_cc_do_calibration_rsp(hdev, skb);
1891 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301892
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301893 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_GET_TRANS_CONF_REQ):
1894 hci_cc_fm_trans_get_conf_rsp(hdev, skb);
1895 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896 default:
1897 FMDERR("%s opcode 0x%x", hdev->name, opcode);
1898 break;
1899 }
1900
1901}
1902
1903static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
1904 struct sk_buff *skb)
1905{
1906 struct hci_ev_cmd_status *ev = (void *) skb->data;
1907 radio_hci_status_complete(hdev, ev->status);
1908}
1909
1910static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
1911 struct sk_buff *skb)
1912{
1913 int i;
1914 int len;
1915
1916 struct iris_device *radio = video_get_drvdata(video_get_dev());
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301917 struct hci_fm_station_rsp *rsp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918
1919 len = sizeof(struct hci_fm_station_rsp);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301920 rsp = (struct hci_fm_station_rsp *)skb_pull(skb, len);
1921 if (rsp == NULL)
1922 return;
1923 memcpy(&radio->fm_st_rsp.station_rsp, rsp, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924
1925 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
1926
1927 for (i = 0; i < IRIS_BUF_MAX; i++) {
1928 if (i >= IRIS_BUF_RT_RDS)
1929 kfifo_reset(&radio->data_buf[i]);
1930 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001931 if (radio->fm_st_rsp.station_rsp.rssi)
1932 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1933 else
1934 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1935
1936 if (radio->fm_st_rsp.station_rsp.stereo_prg)
1937 iris_q_event(radio, IRIS_EVT_STEREO);
1938
1939 if (radio->fm_st_rsp.station_rsp.mute_mode)
1940 iris_q_event(radio, IRIS_EVT_MONO);
1941
1942 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
1943 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1944 else
1945 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1946}
1947
1948static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
1949 struct sk_buff *skb)
1950{
1951 struct iris_device *radio = video_get_drvdata(video_get_dev());
1952 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
1953}
1954
1955static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
1956 struct sk_buff *skb)
1957{
1958 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001959 struct hci_ev_srch_list_compl *ev ;
1960 int cnt;
1961 int stn_num;
1962 int rel_freq;
1963 int abs_freq;
1964 int len;
1965
1966 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1967 if (!ev) {
1968 FMDERR("Memory allocation failed");
1969 return ;
1970 }
1971
1972 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
1973 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
1974
1975 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301976 (cnt < len) && (stn_num < ev->num_stations_found)
1977 && (stn_num < ARRAY_SIZE(ev->rel_freq));
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001978 cnt += PARAMS_PER_STATION, stn_num++) {
1979 abs_freq = *((int *)&skb->data[cnt]);
1980 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
1981 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
1982
1983 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
1984 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
1985 }
1986
1987 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
1988 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
1989 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
1990 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991}
1992
1993static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
1994 struct sk_buff *skb)
1995{
1996 struct iris_device *radio = video_get_drvdata(video_get_dev());
1997 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
1998}
1999
2000static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
2001 struct sk_buff *skb)
2002{
2003 struct iris_device *radio = video_get_drvdata(video_get_dev());
2004 __u8 st_status = *((__u8 *) skb->data);
2005 if (st_status)
2006 iris_q_event(radio, IRIS_EVT_STEREO);
2007 else
2008 iris_q_event(radio, IRIS_EVT_MONO);
2009}
2010
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002011
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002012static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
2013 struct sk_buff *skb)
2014{
2015 struct iris_device *radio = video_get_drvdata(video_get_dev());
2016 int len;
2017 char *data;
2018
2019 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
2020 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
2021 data = kmalloc(len, GFP_ATOMIC);
2022 if (!data) {
2023 FMDERR("Failed to allocate memory");
2024 return;
2025 }
2026
2027 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
2028 data[1] = skb->data[RDS_PTYPE];
2029 data[2] = skb->data[RDS_PID_LOWER];
2030 data[3] = skb->data[RDS_PID_HIGHER];
2031 data[4] = 0;
2032
2033 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
2034
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002035 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002036
2037 kfree(data);
2038}
2039
2040
2041static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
2042 struct sk_buff *skb)
2043{
2044 struct iris_device *radio = video_get_drvdata(video_get_dev());
2045 int len = 0;
2046 char *data;
2047
2048 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
2049
2050 while (skb->data[len+RDS_OFFSET] != 0x0d)
2051 len++;
2052 len++;
2053
2054 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
2055 if (!data) {
2056 FMDERR("Failed to allocate memory");
2057 return;
2058 }
2059
2060 data[0] = len;
2061 data[1] = skb->data[RDS_PTYPE];
2062 data[2] = skb->data[RDS_PID_LOWER];
2063 data[3] = skb->data[RDS_PID_HIGHER];
2064 data[4] = 0;
2065
2066 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
2067 data[len+RDS_OFFSET] = 0x00;
2068
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002069 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002070
2071 kfree(data);
2072}
2073
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302074static void hci_ev_af_list(struct radio_hci_dev *hdev,
2075 struct sk_buff *skb)
2076{
2077 struct iris_device *radio = video_get_drvdata(video_get_dev());
2078 struct hci_ev_af_list ev;
2079
2080 ev.tune_freq = *((int *) &skb->data[0]);
2081 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
2082 ev.af_size = skb->data[AF_SIZE_OFFSET];
2083 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
2084 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
2085 iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
2086}
2087
2088static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
2089 struct sk_buff *skb)
2090{
2091 struct iris_device *radio = video_get_drvdata(video_get_dev());
2092 __u8 rds_status = skb->data[0];
2093
2094 if (rds_status)
2095 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2096 else
2097 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2098}
2099
2100static void hci_ev_service_available(struct radio_hci_dev *hdev,
2101 struct sk_buff *skb)
2102{
2103 struct iris_device *radio = video_get_drvdata(video_get_dev());
2104 if (radio->fm_st_rsp.station_rsp.serv_avble)
2105 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2106 else
2107 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2108}
2109
2110static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
2111 struct sk_buff *skb)
2112{
2113 struct iris_device *radio = video_get_drvdata(video_get_dev());
2114 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
2115}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
2118{
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302119 struct radio_hci_event_hdr *hdr;
2120 u8 event;
2121
2122 if (skb == NULL) {
2123 FMDERR("Socket buffer is NULL");
2124 return;
2125 }
2126
2127 hdr = (void *) skb->data;
2128 event = hdr->evt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002129
2130 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
2131
2132 switch (event) {
2133 case HCI_EV_TUNE_STATUS:
2134 hci_ev_tune_status(hdev, skb);
2135 break;
2136 case HCI_EV_SEARCH_PROGRESS:
2137 case HCI_EV_SEARCH_RDS_PROGRESS:
2138 case HCI_EV_SEARCH_LIST_PROGRESS:
2139 hci_ev_search_next(hdev, skb);
2140 break;
2141 case HCI_EV_STEREO_STATUS:
2142 hci_ev_stereo_status(hdev, skb);
2143 break;
2144 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302145 hci_ev_rds_lock_status(hdev, skb);
2146 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002147 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302148 hci_ev_service_available(hdev, skb);
2149 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002150 case HCI_EV_RDS_RX_DATA:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002151 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002152 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002153 hci_ev_program_service(hdev, skb);
2154 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002155 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002156 hci_ev_radio_text(hdev, skb);
2157 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002158 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302159 hci_ev_af_list(hdev, skb);
2160 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302162 hci_ev_rds_grp_complete(hdev, skb);
2163 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002164 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2165 break;
2166
2167 case HCI_EV_CMD_COMPLETE:
2168 hci_cmd_complete_event(hdev, skb);
2169 break;
2170
2171 case HCI_EV_CMD_STATUS:
2172 hci_cmd_status_event(hdev, skb);
2173 break;
2174
2175 case HCI_EV_SEARCH_COMPLETE:
2176 case HCI_EV_SEARCH_RDS_COMPLETE:
2177 hci_ev_search_compl(hdev, skb);
2178 break;
2179
2180 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002181 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002182 break;
2183
2184 default:
2185 break;
2186 }
2187}
2188
2189/*
2190 * fops/IOCTL helper functions
2191 */
2192
2193static int iris_search(struct iris_device *radio, int on, int dir)
2194{
2195 int retval = 0;
2196 enum search_t srch = radio->g_search_mode & SRCH_MODE;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302197 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198
2199 if (on) {
2200 switch (srch) {
2201 case SCAN_FOR_STRONG:
2202 case SCAN_FOR_WEAK:
2203 radio->srch_st_list.srch_list_dir = dir;
2204 radio->srch_st_list.srch_list_mode = srch;
2205 radio->srch_st_list.srch_list_max = 0;
2206 retval = hci_fm_search_station_list(
2207 &radio->srch_st_list, radio->fm_hdev);
2208 break;
2209 case RDS_SEEK_PTY:
2210 case RDS_SCAN_PTY:
2211 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002212 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213 radio->srch_rds.srch_station.srch_mode = srch;
2214 radio->srch_rds.srch_station.srch_dir = dir;
2215 radio->srch_rds.srch_station.scan_time =
2216 radio->g_scan_time;
2217 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2218 radio->fm_hdev);
2219 break;
2220 default:
2221 radio->srch_st.srch_mode = srch;
2222 radio->srch_st.scan_time = radio->g_scan_time;
2223 radio->srch_st.srch_dir = dir;
2224 retval = hci_fm_search_stations(
2225 &radio->srch_st, radio->fm_hdev);
2226 break;
2227 }
2228
2229 } else {
2230 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2231 }
2232
2233 return retval;
2234}
2235
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302236static int set_low_power_mode(struct iris_device *radio, int power_mode)
2237{
2238
2239 int rds_grps_proc = 0x00;
2240 int retval = 0;
2241 if (radio->power_mode != power_mode) {
2242
2243 if (power_mode) {
2244 radio->event_mask = 0x00;
2245 rds_grps_proc = 0x00 | AF_JUMP_ENABLE ;
2246 retval = hci_fm_rds_grps_process(
2247 &rds_grps_proc,
2248 radio->fm_hdev);
2249 if (retval < 0) {
2250 FMDERR("Disable RDS failed");
2251 return retval;
2252 }
2253 retval = hci_conf_event_mask(&radio->event_mask,
2254 radio->fm_hdev);
2255 } else {
2256
2257 radio->event_mask = SIG_LEVEL_INTR |
2258 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2259 retval = hci_conf_event_mask(&radio->event_mask,
2260 radio->fm_hdev);
2261 if (retval < 0) {
2262 FMDERR("Enable Async events failed");
2263 return retval;
2264 }
2265 retval = hci_fm_rds_grps_process(
2266 &radio->g_rds_grp_proc_ps,
2267 radio->fm_hdev);
2268 }
2269 radio->power_mode = power_mode;
2270 }
2271 return retval;
2272}
Ankur Nandwanid928d542011-08-11 13:15:41 -07002273static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274{
2275 int retval;
2276 radio->region = req_region;
2277
2278 switch (radio->region) {
2279 case IRIS_REGION_US:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002280 radio->recv_conf.band_low_limit =
2281 REGION_US_EU_BAND_LOW;
2282 radio->recv_conf.band_high_limit =
2283 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002284 break;
2285 case IRIS_REGION_EU:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002286 radio->recv_conf.band_low_limit =
2287 REGION_US_EU_BAND_LOW;
2288 radio->recv_conf.band_high_limit =
2289 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290 break;
2291 case IRIS_REGION_JAPAN:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002292 radio->recv_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002293 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302294 radio->recv_conf.band_high_limit =
2295 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002296 break;
2297 case IRIS_REGION_JAPAN_WIDE:
2298 radio->recv_conf.band_low_limit =
2299 REGION_JAPAN_WIDE_BAND_LOW;
2300 radio->recv_conf.band_high_limit =
2301 REGION_JAPAN_WIDE_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 break;
2303 default:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002304 /* The user specifies the value.
2305 So nothing needs to be done */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002306 break;
2307 }
2308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002309 retval = hci_set_fm_recv_conf(
2310 &radio->recv_conf,
2311 radio->fm_hdev);
2312
2313 return retval;
2314}
2315
Ankur Nandwanid928d542011-08-11 13:15:41 -07002316
2317static int iris_trans_set_region(struct iris_device *radio, int req_region)
2318{
2319 int retval;
2320 radio->region = req_region;
2321
2322 switch (radio->region) {
2323 case IRIS_REGION_US:
2324 radio->trans_conf.band_low_limit =
2325 REGION_US_EU_BAND_LOW;
2326 radio->trans_conf.band_high_limit =
2327 REGION_US_EU_BAND_HIGH;
2328 break;
2329 case IRIS_REGION_EU:
2330 radio->trans_conf.band_low_limit =
2331 REGION_US_EU_BAND_LOW;
2332 radio->trans_conf.band_high_limit =
2333 REGION_US_EU_BAND_HIGH;
2334 break;
2335 case IRIS_REGION_JAPAN:
2336 radio->trans_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002337 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302338 radio->trans_conf.band_high_limit =
2339 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002340 break;
2341 case IRIS_REGION_JAPAN_WIDE:
2342 radio->recv_conf.band_low_limit =
2343 REGION_JAPAN_WIDE_BAND_LOW;
2344 radio->recv_conf.band_high_limit =
2345 REGION_JAPAN_WIDE_BAND_HIGH;
2346 default:
2347 break;
2348 }
2349
2350 retval = hci_set_fm_trans_conf(
2351 &radio->trans_conf,
2352 radio->fm_hdev);
2353 return retval;
2354}
2355
2356
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2358{
2359
2360 int retval;
2361 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2362 if (retval < 0)
2363 FMDERR("Error while setting the frequency : %d\n", retval);
2364 return retval;
2365}
2366
2367
2368static int iris_vidioc_queryctrl(struct file *file, void *priv,
2369 struct v4l2_queryctrl *qc)
2370{
2371 unsigned char i;
2372 int retval = -EINVAL;
2373
2374 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2375 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2376 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2377 retval = 0;
2378 break;
2379 }
2380 }
2381
2382 return retval;
2383}
2384
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302385static int iris_do_calibration(struct iris_device *radio)
2386{
2387 char cal_mode = 0x00;
2388 int retval = 0x00;
2389
2390 cal_mode = PROCS_CALIB_MODE;
2391 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2392 radio->fm_hdev);
2393 if (retval < 0) {
2394 FMDERR("Enable failed before calibration %x", retval);
2395 return retval;
2396 }
2397 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2398 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2399 if (retval < 0) {
2400 FMDERR("Do Process calibration failed %x", retval);
2401 return retval;
2402 }
2403 cal_mode = DC_CALIB_MODE;
2404 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2405 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2406 if (retval < 0) {
2407 FMDERR("Do DC calibration failed %x", retval);
2408 return retval;
2409 }
2410 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2411 radio->fm_hdev);
2412 if (retval < 0)
2413 FMDERR("Disable Failed after calibration %d", retval);
2414 return retval;
2415}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002416static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2417 struct v4l2_control *ctrl)
2418{
2419 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2420 int retval = 0;
2421
2422 switch (ctrl->id) {
2423 case V4L2_CID_AUDIO_VOLUME:
2424 break;
2425 case V4L2_CID_AUDIO_MUTE:
2426 ctrl->value = radio->mute_mode.hard_mute;
2427 break;
2428 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2429 ctrl->value = radio->g_search_mode;
2430 break;
2431 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2432 ctrl->value = radio->g_scan_time;
2433 break;
2434 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302435 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436 break;
2437 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302438 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439 break;
2440 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2441 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2442 if (retval < 0)
2443 return retval;
2444 ctrl->value = radio->st_dbg_param.io_verc;
2445 break;
2446 case V4L2_CID_PRIVATE_IRIS_INTDET:
2447 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2448 if (retval < 0)
2449 return retval;
2450 ctrl->value = radio->st_dbg_param.in_det_out;
2451 break;
2452 case V4L2_CID_PRIVATE_IRIS_REGION:
2453 ctrl->value = radio->region;
2454 break;
2455 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2456 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
2457 break;
2458 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302459 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460 break;
2461 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302462 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463 break;
2464 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302465 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 break;
2467 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002468 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002469 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002470 } else if (radio->mode == FM_TRANS) {
2471 ctrl->value = radio->trans_conf.emphasis;
2472 } else {
2473 FMDERR("Error in radio mode"
2474 " %d\n", retval);
2475 return -EINVAL;
2476 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002477 break;
2478 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002479 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002481 } else if (radio->mode == FM_TRANS) {
2482 ctrl->value = radio->trans_conf.rds_std;
2483 } else {
2484 FMDERR("Error in radio mode"
2485 " %d\n", retval);
2486 return -EINVAL;
2487 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488 break;
2489 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002490 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002492 } else {
2493 FMDERR("Error in radio mode"
2494 " %d\n", retval);
2495 return -EINVAL;
2496 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002497 break;
2498 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002499 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002500 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002501 } else {
2502 FMDERR("Error in radio mode"
2503 " %d\n", retval);
2504 return -EINVAL;
2505 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506 break;
2507 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2508 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2509 break;
2510 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002511 case V4L2_CID_PRIVATE_IRIS_PSALL:
2512 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513 break;
2514 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2515 ctrl->value = radio->rds_grp.rds_buf_size;
2516 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002517 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302518 ctrl->value = radio->power_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002519 break;
2520 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2521 ctrl->value = radio->g_antenna;
2522 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002523 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2524 ctrl->value = radio->mute_mode.soft_mute;
2525 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302526 case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
2527 retval = iris_do_calibration(radio);
2528 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529 default:
2530 retval = -EINVAL;
2531 }
2532 if (retval < 0)
2533 FMDERR("get control failed with %d, id: %d\n",
2534 retval, ctrl->id);
2535 return retval;
2536}
2537
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302538static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
2539 struct v4l2_ext_controls *ctrl)
2540{
2541 int retval = 0;
2542 char *data = NULL;
2543 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2544 struct hci_fm_def_data_rd_req default_data_rd;
2545
2546 switch ((ctrl->controls[0]).id) {
2547 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
2548 data = (ctrl->controls[0]).string;
2549 memset(&default_data_rd, 0, sizeof(default_data_rd));
2550 if (copy_from_user(&default_data_rd.mode, data,
2551 sizeof(default_data_rd)))
2552 return -EFAULT;
2553 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
2554 break;
2555 default:
2556 retval = -EINVAL;
2557 }
2558
2559 return retval;
2560}
2561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002562static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2563 struct v4l2_ext_controls *ctrl)
2564{
Ankur Nandwanid928d542011-08-11 13:15:41 -07002565 int retval = 0;
2566 int bytes_to_copy;
2567 struct hci_fm_tx_ps tx_ps;
2568 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302569 struct hci_fm_def_data_wr_req default_data;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302570 struct hci_fm_set_cal_req_proc proc_cal_req;
2571 struct hci_fm_set_cal_req_dc dc_cal_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002572
2573 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2574 char *data = NULL;
2575
2576 switch ((ctrl->controls[0]).id) {
2577 case V4L2_CID_RDS_TX_PS_NAME:
2578 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2579 /*Pass a sample PS string */
2580
2581 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
2582 bytes_to_copy = min((int)(ctrl->controls[0]).size,
2583 MAX_PS_LENGTH);
2584 data = (ctrl->controls[0]).string;
2585
2586 if (copy_from_user(tx_ps.ps_data,
2587 data, bytes_to_copy))
2588 return -EFAULT;
2589 tx_ps.ps_control = 0x01;
2590 tx_ps.pi = radio->pi;
2591 tx_ps.pty = radio->pty;
2592 tx_ps.ps_repeatcount = radio->ps_repeatcount;
2593 tx_ps.ps_len = bytes_to_copy;
2594
2595 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2596 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
2597 break;
2598 case V4L2_CID_RDS_TX_RADIO_TEXT:
2599 bytes_to_copy =
2600 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2601 data = (ctrl->controls[0]).string;
2602
2603 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
2604
2605 if (copy_from_user(tx_rt.rt_data,
2606 data, bytes_to_copy))
2607 return -EFAULT;
2608
2609 tx_rt.rt_control = 0x01;
2610 tx_rt.pi = radio->pi;
2611 tx_rt.pty = radio->pty;
2612 tx_rt.ps_len = bytes_to_copy;
2613
2614 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2615 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
2616 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302617 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
2618 data = (ctrl->controls[0]).string;
2619 memset(&default_data, 0, sizeof(default_data));
2620 if (copy_from_user(&default_data, data, sizeof(default_data)))
2621 return -EFAULT;
2622 retval = hci_def_data_write(&default_data, radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302623 break;
2624 case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302625 data = (ctrl->controls[0]).string;
2626 bytes_to_copy = (ctrl->controls[0]).size;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302627 if (bytes_to_copy < (PROCS_CALIB_SIZE + DC_CALIB_SIZE)) {
2628 FMDERR("data is less than required size");
2629 return -EFAULT;
2630 }
2631 memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
2632 proc_cal_req.mode = PROCS_CALIB_MODE;
2633 if (copy_from_user(&proc_cal_req.data[0],
2634 data, sizeof(proc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302635 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302636 retval = radio_hci_request(radio->fm_hdev,
2637 hci_fm_set_cal_req_proc,
2638 (unsigned long)&proc_cal_req,
2639 RADIO_HCI_TIMEOUT);
2640 if (retval < 0) {
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302641 FMDERR("Set Process calibration failed %d", retval);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302642 return retval;
2643 }
2644 memset(dc_cal_req.data, 0, DC_CALIB_SIZE);
2645 if (copy_from_user(&dc_cal_req.data[0], &data[PROCS_CALIB_SIZE],
2646 sizeof(dc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302647 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302648 dc_cal_req.mode = DC_CALIB_MODE;
2649 retval = radio_hci_request(radio->fm_hdev,
2650 hci_fm_set_cal_req_dc,
2651 (unsigned long)&dc_cal_req, RADIO_HCI_TIMEOUT);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302652 if (retval < 0)
2653 FMDERR("Set DC calibration failed %d", retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302654 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002655 default:
2656 FMDBG("Shouldn't reach here\n");
2657 retval = -1;
2658 }
2659 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660}
2661
2662static int iris_vidioc_s_ctrl(struct file *file, void *priv,
2663 struct v4l2_control *ctrl)
2664{
2665 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2666 int retval = 0;
2667 unsigned int rds_grps_proc = 0;
2668 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002669 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302670 struct hci_fm_tx_ps tx_ps = {0};
2671 struct hci_fm_tx_rt tx_rt = {0};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002672
2673 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302674 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002675 radio->tone_freq = ctrl->value;
2676 retval = radio_hci_request(radio->fm_hdev,
2677 hci_fm_tone_generator, arg,
2678 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302679 if (retval < 0)
2680 FMDERR("Error while setting the tone %d", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002681 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002682 case V4L2_CID_AUDIO_VOLUME:
2683 break;
2684 case V4L2_CID_AUDIO_MUTE:
2685 radio->mute_mode.hard_mute = ctrl->value;
2686 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
2687 retval = hci_set_fm_mute_mode(
2688 &radio->mute_mode,
2689 radio->fm_hdev);
2690 if (retval < 0)
2691 FMDERR("Error while set FM hard mute"" %d\n",
2692 retval);
2693 break;
2694 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2695 radio->g_search_mode = ctrl->value;
2696 break;
2697 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2698 radio->g_scan_time = ctrl->value;
2699 break;
2700 case V4L2_CID_PRIVATE_IRIS_SRCHON:
2701 iris_search(radio, ctrl->value, SRCH_DIR_UP);
2702 break;
2703 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002704 switch (ctrl->value) {
2705 case FM_RECV:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002706 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2707 radio->fm_hdev);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302708 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002709 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002710 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302711 return retval;
2712 }
2713 radio->mode = FM_RECV;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002714 radio->mute_mode.soft_mute = CTRL_ON;
2715 retval = hci_set_fm_mute_mode(
2716 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002717 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302718 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002719 FMDERR("Failed to enable Smute\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302720 return retval;
2721 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002722 radio->stereo_mode.stereo_mode = CTRL_OFF;
2723 radio->stereo_mode.sig_blend = CTRL_ON;
2724 radio->stereo_mode.intf_blend = CTRL_ON;
2725 radio->stereo_mode.most_switch = CTRL_ON;
2726 retval = hci_set_fm_stereo_mode(
2727 &radio->stereo_mode,
2728 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302729 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002730 FMDERR("Failed to set stereo mode\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302731 return retval;
2732 }
Srinivasa Rao Uppalaf1febce2011-11-09 10:30:16 +05302733 radio->event_mask = SIG_LEVEL_INTR |
2734 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2735 retval = hci_conf_event_mask(&radio->event_mask,
2736 radio->fm_hdev);
2737 if (retval < 0) {
2738 FMDERR("Enable Async events failed");
2739 return retval;
2740 }
Srinivasa Rao Uppalaf0d13742011-09-08 10:13:13 +05302741 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2742 radio->fm_hdev);
2743 if (retval < 0)
2744 FMDERR("Failed to get the Recv Config\n");
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002745 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002746 case FM_TRANS:
2747 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
2748 radio->fm_hdev);
2749 radio->mode = FM_TRANS;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302750 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002751 FMDERR("Error while enabling TRANS FM"
2752 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302753 return retval;
2754 }
2755 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
2756 if (retval < 0)
2757 FMDERR("get frequency failed %d\n", retval);
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002758 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002759 case FM_OFF:
2760 switch (radio->mode) {
2761 case FM_RECV:
2762 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2763 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002765 FMDERR("Err on disable recv FM"
2766 " %d\n", retval);
2767 break;
2768 case FM_TRANS:
2769 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
2770 radio->fm_hdev);
2771
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002772 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002773 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002774 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002775 break;
2776 default:
2777 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302779 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002780 default:
2781 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002782 }
2783 break;
2784 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002785 if (radio->mode == FM_RECV) {
2786 retval = iris_recv_set_region(radio, ctrl->value);
2787 } else {
2788 if (radio->mode == FM_TRANS)
2789 retval = iris_trans_set_region(radio,
2790 ctrl->value);
2791 else
2792 retval = -EINVAL;
2793 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794 break;
2795 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2796 temp_val = ctrl->value;
2797 retval = hci_fm_set_signal_threshold(
2798 &temp_val,
2799 radio->fm_hdev);
2800 if (retval < 0) {
2801 FMDERR("Error while setting signal threshold\n");
2802 break;
2803 }
2804 break;
2805 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
2806 radio->srch_rds.srch_pty = ctrl->value;
2807 radio->srch_st_list.srch_pty = ctrl->value;
2808 break;
2809 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
2810 radio->srch_rds.srch_pi = ctrl->value;
2811 break;
2812 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
2813 break;
2814 case V4L2_CID_PRIVATE_IRIS_SPACING:
Venkateshwarlu Domakonda45496f12011-11-23 12:51:13 +05302815 if (radio->mode == FM_RECV) {
2816 radio->recv_conf.ch_spacing = ctrl->value;
2817 retval = hci_set_fm_recv_conf(
2818 &radio->recv_conf,
2819 radio->fm_hdev);
2820 if (retval < 0)
2821 FMDERR("Error in setting channel spacing");
2822 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002823 break;
2824 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002825 switch (radio->mode) {
2826 case FM_RECV:
2827 radio->recv_conf.emphasis = ctrl->value;
2828 retval = hci_set_fm_recv_conf(
2829 &radio->recv_conf,
2830 radio->fm_hdev);
2831 if (retval < 0)
2832 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002833 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002834 case FM_TRANS:
2835 radio->trans_conf.emphasis = ctrl->value;
2836 retval = hci_set_fm_trans_conf(
2837 &radio->trans_conf,
2838 radio->fm_hdev);
2839 if (retval < 0)
2840 FMDERR("Error in setting emphasis");
2841 break;
2842 default:
2843 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002844 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002845 break;
2846 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002847 switch (radio->mode) {
2848 case FM_RECV:
2849 radio->recv_conf.rds_std = ctrl->value;
2850 retval = hci_set_fm_recv_conf(
2851 &radio->recv_conf,
2852 radio->fm_hdev);
2853 if (retval < 0)
2854 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002855 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002856 case FM_TRANS:
2857 radio->trans_conf.rds_std = ctrl->value;
2858 retval = hci_set_fm_trans_conf(
2859 &radio->trans_conf,
2860 radio->fm_hdev);
2861 if (retval < 0)
2862 FMDERR("Error in rds_Std");
2863 break;
2864 default:
2865 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002866 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867 break;
2868 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002869 switch (radio->mode) {
2870 case FM_RECV:
2871 radio->recv_conf.rds_std = ctrl->value;
2872 retval = hci_set_fm_recv_conf(
2873 &radio->recv_conf,
2874 radio->fm_hdev);
2875 if (retval < 0)
2876 FMDERR("Error in rds_std");
2877 break;
2878 case FM_TRANS:
2879 radio->trans_conf.rds_std = ctrl->value;
2880 retval = hci_set_fm_trans_conf(
2881 &radio->trans_conf,
2882 radio->fm_hdev);
2883 if (retval < 0)
2884 FMDERR("Error in rds_Std");
2885 break;
2886 default:
2887 retval = -EINVAL;
2888 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002889 break;
2890 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2891 radio->rds_grp.rds_grp_enable_mask = ctrl->value;
2892 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
2893 break;
2894 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
2895 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002896 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002897 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002898 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002899 radio->fm_hdev);
2900 break;
2901 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2902 radio->rds_grp.rds_buf_size = ctrl->value;
2903 break;
2904 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002905 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
2906 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2907 retval = hci_fm_rds_grps_process(
2908 &radio->g_rds_grp_proc_ps,
2909 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002910 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302911 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
2912 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_OFFSET);
2913 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2914 retval = hci_fm_rds_grps_process(
2915 &radio->g_rds_grp_proc_ps,
2916 radio->fm_hdev);
2917 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002918 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302919 set_low_power_mode(radio, ctrl->value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920 break;
2921 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2922 temp_val = ctrl->value;
2923 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
2924 break;
2925 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002926 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002927 break;
2928 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002929 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002930 break;
2931 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302932 tx_ps.ps_control = 0x00;
2933 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2934 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002935 break;
2936 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302937 tx_rt.rt_control = 0x00;
2938 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2939 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002940 break;
2941 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002942 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002943 break;
2944 case V4L2_CID_TUNE_POWER_LEVEL:
2945 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002946 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2947 radio->mute_mode.soft_mute = ctrl->value;
2948 retval = hci_set_fm_mute_mode(
2949 &radio->mute_mode,
2950 radio->fm_hdev);
2951 if (retval < 0)
2952 FMDERR("Error while setting FM soft mute"" %d\n",
2953 retval);
2954 break;
2955 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
2956 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
2957 break;
2958 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
2959 radio->riva_data_req.cmd_params.length = ctrl->value;
2960 break;
2961 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
2962 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
2963 radio->riva_data_req.cmd_params.length);
2964 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
2965 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
2966 break;
2967 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
2968 radio->ssbi_data_accs.start_addr = ctrl->value;
2969 break;
2970 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
2971 radio->ssbi_data_accs.data = ctrl->value;
2972 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
2973 radio->fm_hdev);
2974 break;
2975 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
2976 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
2977 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
2978 radio->fm_hdev);
2979 break;
2980 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
2981 radio->ssbi_peek_reg.start_address = ctrl->value;
2982 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
2983 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302984 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
2985 temp_val = ctrl->value;
2986 hci_read_grp_counters(&temp_val, radio->fm_hdev);
2987 break;
2988 case V4L2_CID_PRIVATE_IRIS_HLSI:
2989 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2990 radio->fm_hdev);
2991 if (retval)
2992 break;
2993 radio->recv_conf.hlsi = ctrl->value;
2994 retval = hci_set_fm_recv_conf(
2995 &radio->recv_conf,
2996 radio->fm_hdev);
2997 break;
2998 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
2999 temp_val = ctrl->value;
3000 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
3001 break;
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05303002 case V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM:
3003 /*
3004 This private control is a place holder to keep the
3005 driver compatible with changes done in the frameworks
3006 which are specific to TAVARUA.
3007 */
3008 retval = 0;
3009 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003010 default:
3011 retval = -EINVAL;
3012 }
3013 return retval;
3014}
3015
3016static int iris_vidioc_g_tuner(struct file *file, void *priv,
3017 struct v4l2_tuner *tuner)
3018{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003019 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003020 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003021 if (tuner->index > 0)
3022 return -EINVAL;
3023
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303024 if (radio->mode == FM_RECV) {
3025 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3026 if (retval < 0) {
3027 FMDERR("Failed to Get station params");
3028 return retval;
3029 }
3030 tuner->type = V4L2_TUNER_RADIO;
3031 tuner->rangelow =
3032 radio->recv_conf.band_low_limit * TUNE_PARAM;
3033 tuner->rangehigh =
3034 radio->recv_conf.band_high_limit * TUNE_PARAM;
3035 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
3036 tuner->capability = V4L2_TUNER_CAP_LOW;
3037 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
3038 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
3039 tuner->afc = 0;
3040 } else if (radio->mode == FM_TRANS) {
3041 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
3042 if (retval < 0) {
3043 FMDERR("get Tx config failed %d\n", retval);
3044 return retval;
3045 } else {
3046 tuner->type = V4L2_TUNER_RADIO;
3047 tuner->rangelow =
3048 radio->trans_conf.band_low_limit * TUNE_PARAM;
3049 tuner->rangehigh =
3050 radio->trans_conf.band_high_limit * TUNE_PARAM;
3051 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303053 } else
3054 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003055 return 0;
3056}
3057
3058static int iris_vidioc_s_tuner(struct file *file, void *priv,
3059 struct v4l2_tuner *tuner)
3060{
3061 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07003062 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003063 if (tuner->index > 0)
3064 return -EINVAL;
3065
Ankur Nandwanid928d542011-08-11 13:15:41 -07003066 if (radio->mode == FM_RECV) {
3067 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
3068 radio->recv_conf.band_high_limit =
3069 tuner->rangehigh / TUNE_PARAM;
3070 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
3071 radio->stereo_mode.stereo_mode = 0x01;
3072 retval = hci_set_fm_stereo_mode(
3073 &radio->stereo_mode,
3074 radio->fm_hdev);
3075 } else {
3076 radio->stereo_mode.stereo_mode = 0x00;
3077 retval = hci_set_fm_stereo_mode(
3078 &radio->stereo_mode,
3079 radio->fm_hdev);
3080 }
3081 if (retval < 0)
3082 FMDERR(": set tuner failed with %d\n", retval);
3083 return retval;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303084 } else if (radio->mode == FM_TRANS) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003085 radio->trans_conf.band_low_limit =
3086 tuner->rangelow / TUNE_PARAM;
3087 radio->trans_conf.band_high_limit =
3088 tuner->rangehigh / TUNE_PARAM;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303089 } else
3090 return -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003092 return retval;
3093}
3094
3095static int iris_vidioc_g_frequency(struct file *file, void *priv,
3096 struct v4l2_frequency *freq)
3097{
3098 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3099 int retval;
3100
3101 freq->type = V4L2_TUNER_RADIO;
3102 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3103 if (retval < 0)
3104 FMDERR("get frequency failed %d\n", retval);
3105 else
3106 freq->frequency =
3107 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
3108 return retval;
3109}
3110
3111static int iris_vidioc_s_frequency(struct file *file, void *priv,
3112 struct v4l2_frequency *freq)
3113{
3114 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3115 int retval = -1;
3116 freq->frequency = freq->frequency / TUNE_PARAM;
3117
3118 if (freq->type != V4L2_TUNER_RADIO)
3119 return -EINVAL;
3120
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003121 /* We turn off RDS prior to tuning to a new station.
3122 because of a bug in SoC which prevents tuning
3123 during RDS transmission.
3124 */
3125 if (radio->mode == FM_TRANS
3126 && (radio->trans_conf.rds_std == 0 ||
3127 radio->trans_conf.rds_std == 1)) {
3128 radio->prev_trans_rds = radio->trans_conf.rds_std;
3129 radio->trans_conf.rds_std = 2;
3130 hci_set_fm_trans_conf(&radio->trans_conf,
3131 radio->fm_hdev);
3132 }
3133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003134 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003135
3136 if (radio->mode == FM_TRANS
3137 && radio->trans_conf.rds_std == 2
3138 && (radio->prev_trans_rds == 1
3139 || radio->prev_trans_rds == 0)) {
3140 radio->trans_conf.rds_std = radio->prev_trans_rds;
3141 hci_set_fm_trans_conf(&radio->trans_conf,
3142 radio->fm_hdev);
3143 }
3144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003145 if (retval < 0)
3146 FMDERR(" set frequency failed with %d\n", retval);
3147 return retval;
3148}
3149
3150static int iris_vidioc_dqbuf(struct file *file, void *priv,
3151 struct v4l2_buffer *buffer)
3152{
3153 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3154 enum iris_buf_t buf_type = buffer->index;
3155 struct kfifo *data_fifo;
3156 unsigned char *buf = (unsigned char *)buffer->m.userptr;
3157 unsigned int len = buffer->length;
3158 if (!access_ok(VERIFY_WRITE, buf, len))
3159 return -EFAULT;
3160 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
3161 data_fifo = &radio->data_buf[buf_type];
3162 if (buf_type == IRIS_BUF_EVENTS)
3163 if (wait_event_interruptible(radio->event_queue,
3164 kfifo_len(data_fifo)) < 0)
3165 return -EINTR;
3166 } else {
3167 FMDERR("invalid buffer type\n");
3168 return -EINVAL;
3169 }
3170 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3171 &radio->buf_lock[buf_type]);
3172
3173 return 0;
3174}
3175
3176static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
3177 struct v4l2_format *f)
3178{
3179 return 0;
3180
3181}
3182
3183static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3184 struct v4l2_hw_freq_seek *seek)
3185{
3186 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3187 int dir;
3188 if (seek->seek_upward)
3189 dir = SRCH_DIR_UP;
3190 else
3191 dir = SRCH_DIR_DOWN;
3192 return iris_search(radio, CTRL_ON, dir);
3193}
3194
3195static int iris_vidioc_querycap(struct file *file, void *priv,
3196 struct v4l2_capability *capability)
3197{
3198 struct iris_device *radio;
3199 radio = video_get_drvdata(video_devdata(file));
3200 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
3201 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
3202 radio->g_cap = capability;
3203 return 0;
3204}
3205
3206
3207static const struct v4l2_ioctl_ops iris_ioctl_ops = {
3208 .vidioc_querycap = iris_vidioc_querycap,
3209 .vidioc_queryctrl = iris_vidioc_queryctrl,
3210 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
3211 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
3212 .vidioc_g_tuner = iris_vidioc_g_tuner,
3213 .vidioc_s_tuner = iris_vidioc_s_tuner,
3214 .vidioc_g_frequency = iris_vidioc_g_frequency,
3215 .vidioc_s_frequency = iris_vidioc_s_frequency,
3216 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
3217 .vidioc_dqbuf = iris_vidioc_dqbuf,
3218 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
3219 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303220 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003221};
3222
3223static const struct v4l2_file_operations iris_fops = {
3224 .owner = THIS_MODULE,
3225 .unlocked_ioctl = video_ioctl2,
3226};
3227
3228static struct video_device iris_viddev_template = {
3229 .fops = &iris_fops,
3230 .ioctl_ops = &iris_ioctl_ops,
3231 .name = DRIVER_NAME,
3232 .release = video_device_release,
3233};
3234
3235static struct video_device *video_get_dev(void)
3236{
3237 return priv_videodev;
3238}
3239
3240static int __init iris_probe(struct platform_device *pdev)
3241{
3242 struct iris_device *radio;
3243 int retval;
3244 int radio_nr = -1;
3245 int i;
3246
3247 if (!pdev) {
3248 FMDERR(": pdev is null\n");
3249 return -ENOMEM;
3250 }
3251
3252 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
3253 if (!radio) {
3254 FMDERR(": Could not allocate radio device\n");
3255 return -ENOMEM;
3256 }
3257
3258 radio->dev = &pdev->dev;
3259 platform_set_drvdata(pdev, radio);
3260
3261 radio->videodev = video_device_alloc();
3262 if (!radio->videodev) {
3263 FMDERR(": Could not allocate V4L device\n");
3264 kfree(radio);
3265 return -ENOMEM;
3266 }
3267
3268 memcpy(radio->videodev, &iris_viddev_template,
3269 sizeof(iris_viddev_template));
3270
3271 for (i = 0; i < IRIS_BUF_MAX; i++) {
3272 int kfifo_alloc_rc = 0;
3273 spin_lock_init(&radio->buf_lock[i]);
3274
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07003275 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003276 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3277 rds_buf*3, GFP_KERNEL);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05303278 else if (i == IRIS_BUF_CAL_DATA)
3279 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3280 STD_BUF_SIZE*2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003281 else
3282 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3283 STD_BUF_SIZE, GFP_KERNEL);
3284
3285 if (kfifo_alloc_rc != 0) {
3286 FMDERR("failed allocating buffers %d\n",
3287 kfifo_alloc_rc);
3288 for (; i > -1; i--) {
3289 kfifo_free(&radio->data_buf[i]);
3290 kfree(radio);
3291 return -ENOMEM;
3292 }
3293 }
3294 }
3295
3296 mutex_init(&radio->lock);
3297 init_completion(&radio->sync_xfr_start);
3298 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003299 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003300 init_waitqueue_head(&radio->event_queue);
3301 init_waitqueue_head(&radio->read_queue);
3302
3303 video_set_drvdata(radio->videodev, radio);
3304
3305 if (NULL == video_get_drvdata(radio->videodev))
3306 FMDERR(": video_get_drvdata failed\n");
3307
3308 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
3309 radio_nr);
3310 if (retval) {
3311 FMDERR(": Could not register video device\n");
3312 video_device_release(radio->videodev);
3313 for (; i > -1; i--)
3314 kfifo_free(&radio->data_buf[i]);
3315 kfree(radio);
3316 return retval;
3317 } else {
3318 priv_videodev = kzalloc(sizeof(struct video_device),
3319 GFP_KERNEL);
3320 memcpy(priv_videodev, radio->videodev,
3321 sizeof(struct video_device));
3322 }
3323 return 0;
3324}
3325
3326
3327static int __devexit iris_remove(struct platform_device *pdev)
3328{
3329 int i;
3330 struct iris_device *radio = platform_get_drvdata(pdev);
3331
3332 video_unregister_device(radio->videodev);
3333
3334 for (i = 0; i < IRIS_BUF_MAX; i++)
3335 kfifo_free(&radio->data_buf[i]);
3336
3337 kfree(radio);
3338
3339 platform_set_drvdata(pdev, NULL);
3340
3341 return 0;
3342}
3343
3344static struct platform_driver iris_driver = {
3345 .driver = {
3346 .owner = THIS_MODULE,
3347 .name = "iris_fm",
3348 },
3349 .remove = __devexit_p(iris_remove),
3350};
3351
3352static int __init iris_radio_init(void)
3353{
3354 return platform_driver_probe(&iris_driver, iris_probe);
3355}
3356module_init(iris_radio_init);
3357
3358static void __exit iris_radio_exit(void)
3359{
3360 platform_driver_unregister(&iris_driver);
3361}
3362module_exit(iris_radio_exit);
3363
3364MODULE_LICENSE("GPL v2");
3365MODULE_AUTHOR(DRIVER_AUTHOR);
3366MODULE_DESCRIPTION(DRIVER_DESC);