blob: 8b983d08162bda0eee48d6664e2b5401293e6c61 [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;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914 struct iris_device *radio = video_get_drvdata(video_get_dev());
1915
Venkateshwarlu Domakonda862492d2011-11-29 11:51:24 +05301916 memcpy(&radio->fm_st_rsp.station_rsp, &skb->data[0],
1917 sizeof(struct hci_ev_tune_status));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
1919
1920 for (i = 0; i < IRIS_BUF_MAX; i++) {
1921 if (i >= IRIS_BUF_RT_RDS)
1922 kfifo_reset(&radio->data_buf[i]);
1923 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924 if (radio->fm_st_rsp.station_rsp.rssi)
1925 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1926 else
1927 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1928
1929 if (radio->fm_st_rsp.station_rsp.stereo_prg)
1930 iris_q_event(radio, IRIS_EVT_STEREO);
1931
1932 if (radio->fm_st_rsp.station_rsp.mute_mode)
1933 iris_q_event(radio, IRIS_EVT_MONO);
1934
1935 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
1936 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1937 else
1938 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1939}
1940
1941static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
1942 struct sk_buff *skb)
1943{
1944 struct iris_device *radio = video_get_drvdata(video_get_dev());
1945 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
1946}
1947
1948static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
1949 struct sk_buff *skb)
1950{
1951 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001952 struct hci_ev_srch_list_compl *ev ;
1953 int cnt;
1954 int stn_num;
1955 int rel_freq;
1956 int abs_freq;
1957 int len;
1958
1959 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1960 if (!ev) {
1961 FMDERR("Memory allocation failed");
1962 return ;
1963 }
1964
1965 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
1966 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
1967
1968 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301969 (cnt < len) && (stn_num < ev->num_stations_found)
1970 && (stn_num < ARRAY_SIZE(ev->rel_freq));
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001971 cnt += PARAMS_PER_STATION, stn_num++) {
1972 abs_freq = *((int *)&skb->data[cnt]);
1973 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
1974 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
1975
1976 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
1977 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
1978 }
1979
1980 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
1981 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
1982 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
1983 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001984}
1985
1986static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
1987 struct sk_buff *skb)
1988{
1989 struct iris_device *radio = video_get_drvdata(video_get_dev());
1990 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
1991}
1992
1993static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
1994 struct sk_buff *skb)
1995{
1996 struct iris_device *radio = video_get_drvdata(video_get_dev());
1997 __u8 st_status = *((__u8 *) skb->data);
1998 if (st_status)
1999 iris_q_event(radio, IRIS_EVT_STEREO);
2000 else
2001 iris_q_event(radio, IRIS_EVT_MONO);
2002}
2003
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002004
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002005static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
2006 struct sk_buff *skb)
2007{
2008 struct iris_device *radio = video_get_drvdata(video_get_dev());
2009 int len;
2010 char *data;
2011
2012 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
2013 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
2014 data = kmalloc(len, GFP_ATOMIC);
2015 if (!data) {
2016 FMDERR("Failed to allocate memory");
2017 return;
2018 }
2019
2020 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
2021 data[1] = skb->data[RDS_PTYPE];
2022 data[2] = skb->data[RDS_PID_LOWER];
2023 data[3] = skb->data[RDS_PID_HIGHER];
2024 data[4] = 0;
2025
2026 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
2027
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002028 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002029
2030 kfree(data);
2031}
2032
2033
2034static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
2035 struct sk_buff *skb)
2036{
2037 struct iris_device *radio = video_get_drvdata(video_get_dev());
2038 int len = 0;
2039 char *data;
2040
2041 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
2042
2043 while (skb->data[len+RDS_OFFSET] != 0x0d)
2044 len++;
2045 len++;
2046
2047 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
2048 if (!data) {
2049 FMDERR("Failed to allocate memory");
2050 return;
2051 }
2052
2053 data[0] = len;
2054 data[1] = skb->data[RDS_PTYPE];
2055 data[2] = skb->data[RDS_PID_LOWER];
2056 data[3] = skb->data[RDS_PID_HIGHER];
2057 data[4] = 0;
2058
2059 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
2060 data[len+RDS_OFFSET] = 0x00;
2061
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002062 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002063
2064 kfree(data);
2065}
2066
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302067static void hci_ev_af_list(struct radio_hci_dev *hdev,
2068 struct sk_buff *skb)
2069{
2070 struct iris_device *radio = video_get_drvdata(video_get_dev());
2071 struct hci_ev_af_list ev;
2072
2073 ev.tune_freq = *((int *) &skb->data[0]);
2074 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
2075 ev.af_size = skb->data[AF_SIZE_OFFSET];
2076 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
2077 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
2078 iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
2079}
2080
2081static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
2082 struct sk_buff *skb)
2083{
2084 struct iris_device *radio = video_get_drvdata(video_get_dev());
2085 __u8 rds_status = skb->data[0];
2086
2087 if (rds_status)
2088 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2089 else
2090 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2091}
2092
2093static void hci_ev_service_available(struct radio_hci_dev *hdev,
2094 struct sk_buff *skb)
2095{
2096 struct iris_device *radio = video_get_drvdata(video_get_dev());
2097 if (radio->fm_st_rsp.station_rsp.serv_avble)
2098 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2099 else
2100 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2101}
2102
2103static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
2104 struct sk_buff *skb)
2105{
2106 struct iris_device *radio = video_get_drvdata(video_get_dev());
2107 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
2108}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002110void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
2111{
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302112 struct radio_hci_event_hdr *hdr;
2113 u8 event;
2114
2115 if (skb == NULL) {
2116 FMDERR("Socket buffer is NULL");
2117 return;
2118 }
2119
2120 hdr = (void *) skb->data;
2121 event = hdr->evt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002122
2123 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
2124
2125 switch (event) {
2126 case HCI_EV_TUNE_STATUS:
2127 hci_ev_tune_status(hdev, skb);
2128 break;
2129 case HCI_EV_SEARCH_PROGRESS:
2130 case HCI_EV_SEARCH_RDS_PROGRESS:
2131 case HCI_EV_SEARCH_LIST_PROGRESS:
2132 hci_ev_search_next(hdev, skb);
2133 break;
2134 case HCI_EV_STEREO_STATUS:
2135 hci_ev_stereo_status(hdev, skb);
2136 break;
2137 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302138 hci_ev_rds_lock_status(hdev, skb);
2139 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002140 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302141 hci_ev_service_available(hdev, skb);
2142 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143 case HCI_EV_RDS_RX_DATA:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002144 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002146 hci_ev_program_service(hdev, skb);
2147 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002148 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002149 hci_ev_radio_text(hdev, skb);
2150 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302152 hci_ev_af_list(hdev, skb);
2153 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302155 hci_ev_rds_grp_complete(hdev, skb);
2156 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002157 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2158 break;
2159
2160 case HCI_EV_CMD_COMPLETE:
2161 hci_cmd_complete_event(hdev, skb);
2162 break;
2163
2164 case HCI_EV_CMD_STATUS:
2165 hci_cmd_status_event(hdev, skb);
2166 break;
2167
2168 case HCI_EV_SEARCH_COMPLETE:
2169 case HCI_EV_SEARCH_RDS_COMPLETE:
2170 hci_ev_search_compl(hdev, skb);
2171 break;
2172
2173 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002174 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002175 break;
2176
2177 default:
2178 break;
2179 }
2180}
2181
2182/*
2183 * fops/IOCTL helper functions
2184 */
2185
2186static int iris_search(struct iris_device *radio, int on, int dir)
2187{
2188 int retval = 0;
2189 enum search_t srch = radio->g_search_mode & SRCH_MODE;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302190 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002191
2192 if (on) {
2193 switch (srch) {
2194 case SCAN_FOR_STRONG:
2195 case SCAN_FOR_WEAK:
2196 radio->srch_st_list.srch_list_dir = dir;
2197 radio->srch_st_list.srch_list_mode = srch;
2198 radio->srch_st_list.srch_list_max = 0;
2199 retval = hci_fm_search_station_list(
2200 &radio->srch_st_list, radio->fm_hdev);
2201 break;
2202 case RDS_SEEK_PTY:
2203 case RDS_SCAN_PTY:
2204 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002205 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206 radio->srch_rds.srch_station.srch_mode = srch;
2207 radio->srch_rds.srch_station.srch_dir = dir;
2208 radio->srch_rds.srch_station.scan_time =
2209 radio->g_scan_time;
2210 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2211 radio->fm_hdev);
2212 break;
2213 default:
2214 radio->srch_st.srch_mode = srch;
2215 radio->srch_st.scan_time = radio->g_scan_time;
2216 radio->srch_st.srch_dir = dir;
2217 retval = hci_fm_search_stations(
2218 &radio->srch_st, radio->fm_hdev);
2219 break;
2220 }
2221
2222 } else {
2223 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2224 }
2225
2226 return retval;
2227}
2228
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302229static int set_low_power_mode(struct iris_device *radio, int power_mode)
2230{
2231
2232 int rds_grps_proc = 0x00;
2233 int retval = 0;
2234 if (radio->power_mode != power_mode) {
2235
2236 if (power_mode) {
2237 radio->event_mask = 0x00;
2238 rds_grps_proc = 0x00 | AF_JUMP_ENABLE ;
2239 retval = hci_fm_rds_grps_process(
2240 &rds_grps_proc,
2241 radio->fm_hdev);
2242 if (retval < 0) {
2243 FMDERR("Disable RDS failed");
2244 return retval;
2245 }
2246 retval = hci_conf_event_mask(&radio->event_mask,
2247 radio->fm_hdev);
2248 } else {
2249
2250 radio->event_mask = SIG_LEVEL_INTR |
2251 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2252 retval = hci_conf_event_mask(&radio->event_mask,
2253 radio->fm_hdev);
2254 if (retval < 0) {
2255 FMDERR("Enable Async events failed");
2256 return retval;
2257 }
2258 retval = hci_fm_rds_grps_process(
2259 &radio->g_rds_grp_proc_ps,
2260 radio->fm_hdev);
2261 }
2262 radio->power_mode = power_mode;
2263 }
2264 return retval;
2265}
Ankur Nandwanid928d542011-08-11 13:15:41 -07002266static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267{
2268 int retval;
2269 radio->region = req_region;
2270
2271 switch (radio->region) {
2272 case IRIS_REGION_US:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002273 radio->recv_conf.band_low_limit =
2274 REGION_US_EU_BAND_LOW;
2275 radio->recv_conf.band_high_limit =
2276 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002277 break;
2278 case IRIS_REGION_EU:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002279 radio->recv_conf.band_low_limit =
2280 REGION_US_EU_BAND_LOW;
2281 radio->recv_conf.band_high_limit =
2282 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283 break;
2284 case IRIS_REGION_JAPAN:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002285 radio->recv_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002286 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302287 radio->recv_conf.band_high_limit =
2288 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002289 break;
2290 case IRIS_REGION_JAPAN_WIDE:
2291 radio->recv_conf.band_low_limit =
2292 REGION_JAPAN_WIDE_BAND_LOW;
2293 radio->recv_conf.band_high_limit =
2294 REGION_JAPAN_WIDE_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002295 break;
2296 default:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002297 /* The user specifies the value.
2298 So nothing needs to be done */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 break;
2300 }
2301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 retval = hci_set_fm_recv_conf(
2303 &radio->recv_conf,
2304 radio->fm_hdev);
2305
2306 return retval;
2307}
2308
Ankur Nandwanid928d542011-08-11 13:15:41 -07002309
2310static int iris_trans_set_region(struct iris_device *radio, int req_region)
2311{
2312 int retval;
2313 radio->region = req_region;
2314
2315 switch (radio->region) {
2316 case IRIS_REGION_US:
2317 radio->trans_conf.band_low_limit =
2318 REGION_US_EU_BAND_LOW;
2319 radio->trans_conf.band_high_limit =
2320 REGION_US_EU_BAND_HIGH;
2321 break;
2322 case IRIS_REGION_EU:
2323 radio->trans_conf.band_low_limit =
2324 REGION_US_EU_BAND_LOW;
2325 radio->trans_conf.band_high_limit =
2326 REGION_US_EU_BAND_HIGH;
2327 break;
2328 case IRIS_REGION_JAPAN:
2329 radio->trans_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002330 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302331 radio->trans_conf.band_high_limit =
2332 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002333 break;
2334 case IRIS_REGION_JAPAN_WIDE:
2335 radio->recv_conf.band_low_limit =
2336 REGION_JAPAN_WIDE_BAND_LOW;
2337 radio->recv_conf.band_high_limit =
2338 REGION_JAPAN_WIDE_BAND_HIGH;
2339 default:
2340 break;
2341 }
2342
2343 retval = hci_set_fm_trans_conf(
2344 &radio->trans_conf,
2345 radio->fm_hdev);
2346 return retval;
2347}
2348
2349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002350static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2351{
2352
2353 int retval;
2354 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2355 if (retval < 0)
2356 FMDERR("Error while setting the frequency : %d\n", retval);
2357 return retval;
2358}
2359
2360
2361static int iris_vidioc_queryctrl(struct file *file, void *priv,
2362 struct v4l2_queryctrl *qc)
2363{
2364 unsigned char i;
2365 int retval = -EINVAL;
2366
2367 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2368 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2369 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2370 retval = 0;
2371 break;
2372 }
2373 }
2374
2375 return retval;
2376}
2377
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302378static int iris_do_calibration(struct iris_device *radio)
2379{
2380 char cal_mode = 0x00;
2381 int retval = 0x00;
2382
2383 cal_mode = PROCS_CALIB_MODE;
2384 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2385 radio->fm_hdev);
2386 if (retval < 0) {
2387 FMDERR("Enable failed before calibration %x", retval);
2388 return retval;
2389 }
2390 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2391 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2392 if (retval < 0) {
2393 FMDERR("Do Process calibration failed %x", retval);
2394 return retval;
2395 }
2396 cal_mode = DC_CALIB_MODE;
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 DC calibration failed %x", retval);
2401 return retval;
2402 }
2403 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2404 radio->fm_hdev);
2405 if (retval < 0)
2406 FMDERR("Disable Failed after calibration %d", retval);
2407 return retval;
2408}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2410 struct v4l2_control *ctrl)
2411{
2412 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2413 int retval = 0;
2414
2415 switch (ctrl->id) {
2416 case V4L2_CID_AUDIO_VOLUME:
2417 break;
2418 case V4L2_CID_AUDIO_MUTE:
2419 ctrl->value = radio->mute_mode.hard_mute;
2420 break;
2421 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2422 ctrl->value = radio->g_search_mode;
2423 break;
2424 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2425 ctrl->value = radio->g_scan_time;
2426 break;
2427 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302428 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002429 break;
2430 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302431 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002432 break;
2433 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2434 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2435 if (retval < 0)
2436 return retval;
2437 ctrl->value = radio->st_dbg_param.io_verc;
2438 break;
2439 case V4L2_CID_PRIVATE_IRIS_INTDET:
2440 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2441 if (retval < 0)
2442 return retval;
2443 ctrl->value = radio->st_dbg_param.in_det_out;
2444 break;
2445 case V4L2_CID_PRIVATE_IRIS_REGION:
2446 ctrl->value = radio->region;
2447 break;
2448 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2449 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
2450 break;
2451 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302452 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 break;
2454 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302455 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 break;
2457 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302458 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 break;
2460 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002461 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002463 } else if (radio->mode == FM_TRANS) {
2464 ctrl->value = radio->trans_conf.emphasis;
2465 } else {
2466 FMDERR("Error in radio mode"
2467 " %d\n", retval);
2468 return -EINVAL;
2469 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 break;
2471 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002472 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002474 } else if (radio->mode == FM_TRANS) {
2475 ctrl->value = radio->trans_conf.rds_std;
2476 } else {
2477 FMDERR("Error in radio mode"
2478 " %d\n", retval);
2479 return -EINVAL;
2480 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481 break;
2482 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002483 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002485 } else {
2486 FMDERR("Error in radio mode"
2487 " %d\n", retval);
2488 return -EINVAL;
2489 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002490 break;
2491 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002492 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002494 } else {
2495 FMDERR("Error in radio mode"
2496 " %d\n", retval);
2497 return -EINVAL;
2498 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002499 break;
2500 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2501 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2502 break;
2503 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002504 case V4L2_CID_PRIVATE_IRIS_PSALL:
2505 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506 break;
2507 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2508 ctrl->value = radio->rds_grp.rds_buf_size;
2509 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302511 ctrl->value = radio->power_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002512 break;
2513 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2514 ctrl->value = radio->g_antenna;
2515 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002516 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2517 ctrl->value = radio->mute_mode.soft_mute;
2518 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302519 case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
2520 retval = iris_do_calibration(radio);
2521 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002522 default:
2523 retval = -EINVAL;
2524 }
2525 if (retval < 0)
2526 FMDERR("get control failed with %d, id: %d\n",
2527 retval, ctrl->id);
2528 return retval;
2529}
2530
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302531static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
2532 struct v4l2_ext_controls *ctrl)
2533{
2534 int retval = 0;
2535 char *data = NULL;
2536 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2537 struct hci_fm_def_data_rd_req default_data_rd;
2538
2539 switch ((ctrl->controls[0]).id) {
2540 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
2541 data = (ctrl->controls[0]).string;
2542 memset(&default_data_rd, 0, sizeof(default_data_rd));
2543 if (copy_from_user(&default_data_rd.mode, data,
2544 sizeof(default_data_rd)))
2545 return -EFAULT;
2546 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
2547 break;
2548 default:
2549 retval = -EINVAL;
2550 }
2551
2552 return retval;
2553}
2554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002555static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2556 struct v4l2_ext_controls *ctrl)
2557{
Ankur Nandwanid928d542011-08-11 13:15:41 -07002558 int retval = 0;
2559 int bytes_to_copy;
2560 struct hci_fm_tx_ps tx_ps;
2561 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302562 struct hci_fm_def_data_wr_req default_data;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302563 struct hci_fm_set_cal_req_proc proc_cal_req;
2564 struct hci_fm_set_cal_req_dc dc_cal_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002565
2566 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2567 char *data = NULL;
2568
2569 switch ((ctrl->controls[0]).id) {
2570 case V4L2_CID_RDS_TX_PS_NAME:
2571 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2572 /*Pass a sample PS string */
2573
2574 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
2575 bytes_to_copy = min((int)(ctrl->controls[0]).size,
2576 MAX_PS_LENGTH);
2577 data = (ctrl->controls[0]).string;
2578
2579 if (copy_from_user(tx_ps.ps_data,
2580 data, bytes_to_copy))
2581 return -EFAULT;
2582 tx_ps.ps_control = 0x01;
2583 tx_ps.pi = radio->pi;
2584 tx_ps.pty = radio->pty;
2585 tx_ps.ps_repeatcount = radio->ps_repeatcount;
2586 tx_ps.ps_len = bytes_to_copy;
2587
2588 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2589 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
2590 break;
2591 case V4L2_CID_RDS_TX_RADIO_TEXT:
2592 bytes_to_copy =
2593 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2594 data = (ctrl->controls[0]).string;
2595
2596 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
2597
2598 if (copy_from_user(tx_rt.rt_data,
2599 data, bytes_to_copy))
2600 return -EFAULT;
2601
2602 tx_rt.rt_control = 0x01;
2603 tx_rt.pi = radio->pi;
2604 tx_rt.pty = radio->pty;
2605 tx_rt.ps_len = bytes_to_copy;
2606
2607 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2608 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
2609 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302610 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
2611 data = (ctrl->controls[0]).string;
2612 memset(&default_data, 0, sizeof(default_data));
2613 if (copy_from_user(&default_data, data, sizeof(default_data)))
2614 return -EFAULT;
2615 retval = hci_def_data_write(&default_data, radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302616 break;
2617 case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302618 data = (ctrl->controls[0]).string;
2619 bytes_to_copy = (ctrl->controls[0]).size;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302620 if (bytes_to_copy < (PROCS_CALIB_SIZE + DC_CALIB_SIZE)) {
2621 FMDERR("data is less than required size");
2622 return -EFAULT;
2623 }
2624 memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
2625 proc_cal_req.mode = PROCS_CALIB_MODE;
2626 if (copy_from_user(&proc_cal_req.data[0],
2627 data, sizeof(proc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302628 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302629 retval = radio_hci_request(radio->fm_hdev,
2630 hci_fm_set_cal_req_proc,
2631 (unsigned long)&proc_cal_req,
2632 RADIO_HCI_TIMEOUT);
2633 if (retval < 0) {
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302634 FMDERR("Set Process calibration failed %d", retval);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302635 return retval;
2636 }
2637 memset(dc_cal_req.data, 0, DC_CALIB_SIZE);
2638 if (copy_from_user(&dc_cal_req.data[0], &data[PROCS_CALIB_SIZE],
2639 sizeof(dc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302640 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302641 dc_cal_req.mode = DC_CALIB_MODE;
2642 retval = radio_hci_request(radio->fm_hdev,
2643 hci_fm_set_cal_req_dc,
2644 (unsigned long)&dc_cal_req, RADIO_HCI_TIMEOUT);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302645 if (retval < 0)
2646 FMDERR("Set DC calibration failed %d", retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302647 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002648 default:
2649 FMDBG("Shouldn't reach here\n");
2650 retval = -1;
2651 }
2652 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002653}
2654
2655static int iris_vidioc_s_ctrl(struct file *file, void *priv,
2656 struct v4l2_control *ctrl)
2657{
2658 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2659 int retval = 0;
2660 unsigned int rds_grps_proc = 0;
2661 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002662 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302663 struct hci_fm_tx_ps tx_ps = {0};
2664 struct hci_fm_tx_rt tx_rt = {0};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002665
2666 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302667 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002668 radio->tone_freq = ctrl->value;
2669 retval = radio_hci_request(radio->fm_hdev,
2670 hci_fm_tone_generator, arg,
2671 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302672 if (retval < 0)
2673 FMDERR("Error while setting the tone %d", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002674 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002675 case V4L2_CID_AUDIO_VOLUME:
2676 break;
2677 case V4L2_CID_AUDIO_MUTE:
2678 radio->mute_mode.hard_mute = ctrl->value;
2679 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
2680 retval = hci_set_fm_mute_mode(
2681 &radio->mute_mode,
2682 radio->fm_hdev);
2683 if (retval < 0)
2684 FMDERR("Error while set FM hard mute"" %d\n",
2685 retval);
2686 break;
2687 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2688 radio->g_search_mode = ctrl->value;
2689 break;
2690 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2691 radio->g_scan_time = ctrl->value;
2692 break;
2693 case V4L2_CID_PRIVATE_IRIS_SRCHON:
2694 iris_search(radio, ctrl->value, SRCH_DIR_UP);
2695 break;
2696 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002697 switch (ctrl->value) {
2698 case FM_RECV:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2700 radio->fm_hdev);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302701 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002702 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002703 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302704 return retval;
2705 }
2706 radio->mode = FM_RECV;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002707 radio->mute_mode.soft_mute = CTRL_ON;
2708 retval = hci_set_fm_mute_mode(
2709 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002710 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302711 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002712 FMDERR("Failed to enable Smute\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302713 return retval;
2714 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002715 radio->stereo_mode.stereo_mode = CTRL_OFF;
2716 radio->stereo_mode.sig_blend = CTRL_ON;
2717 radio->stereo_mode.intf_blend = CTRL_ON;
2718 radio->stereo_mode.most_switch = CTRL_ON;
2719 retval = hci_set_fm_stereo_mode(
2720 &radio->stereo_mode,
2721 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302722 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002723 FMDERR("Failed to set stereo mode\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302724 return retval;
2725 }
Srinivasa Rao Uppalaf1febce2011-11-09 10:30:16 +05302726 radio->event_mask = SIG_LEVEL_INTR |
2727 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2728 retval = hci_conf_event_mask(&radio->event_mask,
2729 radio->fm_hdev);
2730 if (retval < 0) {
2731 FMDERR("Enable Async events failed");
2732 return retval;
2733 }
Srinivasa Rao Uppalaf0d13742011-09-08 10:13:13 +05302734 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2735 radio->fm_hdev);
2736 if (retval < 0)
2737 FMDERR("Failed to get the Recv Config\n");
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002738 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002739 case FM_TRANS:
2740 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
2741 radio->fm_hdev);
2742 radio->mode = FM_TRANS;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302743 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002744 FMDERR("Error while enabling TRANS FM"
2745 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302746 return retval;
2747 }
2748 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
2749 if (retval < 0)
2750 FMDERR("get frequency failed %d\n", retval);
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002751 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002752 case FM_OFF:
2753 switch (radio->mode) {
2754 case FM_RECV:
2755 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2756 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002757 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002758 FMDERR("Err on disable recv FM"
2759 " %d\n", retval);
2760 break;
2761 case FM_TRANS:
2762 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
2763 radio->fm_hdev);
2764
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002765 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002766 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002767 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002768 break;
2769 default:
2770 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302772 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002773 default:
2774 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002775 }
2776 break;
2777 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002778 if (radio->mode == FM_RECV) {
2779 retval = iris_recv_set_region(radio, ctrl->value);
2780 } else {
2781 if (radio->mode == FM_TRANS)
2782 retval = iris_trans_set_region(radio,
2783 ctrl->value);
2784 else
2785 retval = -EINVAL;
2786 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002787 break;
2788 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2789 temp_val = ctrl->value;
2790 retval = hci_fm_set_signal_threshold(
2791 &temp_val,
2792 radio->fm_hdev);
2793 if (retval < 0) {
2794 FMDERR("Error while setting signal threshold\n");
2795 break;
2796 }
2797 break;
2798 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
2799 radio->srch_rds.srch_pty = ctrl->value;
2800 radio->srch_st_list.srch_pty = ctrl->value;
2801 break;
2802 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
2803 radio->srch_rds.srch_pi = ctrl->value;
2804 break;
2805 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
2806 break;
2807 case V4L2_CID_PRIVATE_IRIS_SPACING:
Venkateshwarlu Domakonda45496f12011-11-23 12:51:13 +05302808 if (radio->mode == FM_RECV) {
2809 radio->recv_conf.ch_spacing = ctrl->value;
2810 retval = hci_set_fm_recv_conf(
2811 &radio->recv_conf,
2812 radio->fm_hdev);
2813 if (retval < 0)
2814 FMDERR("Error in setting channel spacing");
2815 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002816 break;
2817 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002818 switch (radio->mode) {
2819 case FM_RECV:
2820 radio->recv_conf.emphasis = ctrl->value;
2821 retval = hci_set_fm_recv_conf(
2822 &radio->recv_conf,
2823 radio->fm_hdev);
2824 if (retval < 0)
2825 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002826 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002827 case FM_TRANS:
2828 radio->trans_conf.emphasis = ctrl->value;
2829 retval = hci_set_fm_trans_conf(
2830 &radio->trans_conf,
2831 radio->fm_hdev);
2832 if (retval < 0)
2833 FMDERR("Error in setting emphasis");
2834 break;
2835 default:
2836 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002837 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002838 break;
2839 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002840 switch (radio->mode) {
2841 case FM_RECV:
2842 radio->recv_conf.rds_std = ctrl->value;
2843 retval = hci_set_fm_recv_conf(
2844 &radio->recv_conf,
2845 radio->fm_hdev);
2846 if (retval < 0)
2847 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002848 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002849 case FM_TRANS:
2850 radio->trans_conf.rds_std = ctrl->value;
2851 retval = hci_set_fm_trans_conf(
2852 &radio->trans_conf,
2853 radio->fm_hdev);
2854 if (retval < 0)
2855 FMDERR("Error in rds_Std");
2856 break;
2857 default:
2858 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002859 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860 break;
2861 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002862 switch (radio->mode) {
2863 case FM_RECV:
2864 radio->recv_conf.rds_std = ctrl->value;
2865 retval = hci_set_fm_recv_conf(
2866 &radio->recv_conf,
2867 radio->fm_hdev);
2868 if (retval < 0)
2869 FMDERR("Error in rds_std");
2870 break;
2871 case FM_TRANS:
2872 radio->trans_conf.rds_std = ctrl->value;
2873 retval = hci_set_fm_trans_conf(
2874 &radio->trans_conf,
2875 radio->fm_hdev);
2876 if (retval < 0)
2877 FMDERR("Error in rds_Std");
2878 break;
2879 default:
2880 retval = -EINVAL;
2881 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002882 break;
2883 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2884 radio->rds_grp.rds_grp_enable_mask = ctrl->value;
2885 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
2886 break;
2887 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
2888 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002889 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002890 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002891 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 radio->fm_hdev);
2893 break;
2894 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2895 radio->rds_grp.rds_buf_size = ctrl->value;
2896 break;
2897 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002898 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
2899 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2900 retval = hci_fm_rds_grps_process(
2901 &radio->g_rds_grp_proc_ps,
2902 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002903 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302904 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
2905 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_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);
2910 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002911 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302912 set_low_power_mode(radio, ctrl->value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002913 break;
2914 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2915 temp_val = ctrl->value;
2916 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
2917 break;
2918 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002919 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920 break;
2921 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002922 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923 break;
2924 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302925 tx_ps.ps_control = 0x00;
2926 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2927 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002928 break;
2929 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302930 tx_rt.rt_control = 0x00;
2931 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2932 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933 break;
2934 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002935 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002936 break;
2937 case V4L2_CID_TUNE_POWER_LEVEL:
2938 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002939 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2940 radio->mute_mode.soft_mute = ctrl->value;
2941 retval = hci_set_fm_mute_mode(
2942 &radio->mute_mode,
2943 radio->fm_hdev);
2944 if (retval < 0)
2945 FMDERR("Error while setting FM soft mute"" %d\n",
2946 retval);
2947 break;
2948 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
2949 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
2950 break;
2951 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
2952 radio->riva_data_req.cmd_params.length = ctrl->value;
2953 break;
2954 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
2955 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
2956 radio->riva_data_req.cmd_params.length);
2957 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
2958 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
2959 break;
2960 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
2961 radio->ssbi_data_accs.start_addr = ctrl->value;
2962 break;
2963 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
2964 radio->ssbi_data_accs.data = ctrl->value;
2965 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
2966 radio->fm_hdev);
2967 break;
2968 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
2969 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
2970 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
2971 radio->fm_hdev);
2972 break;
2973 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
2974 radio->ssbi_peek_reg.start_address = ctrl->value;
2975 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
2976 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302977 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
2978 temp_val = ctrl->value;
2979 hci_read_grp_counters(&temp_val, radio->fm_hdev);
2980 break;
2981 case V4L2_CID_PRIVATE_IRIS_HLSI:
2982 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2983 radio->fm_hdev);
2984 if (retval)
2985 break;
2986 radio->recv_conf.hlsi = ctrl->value;
2987 retval = hci_set_fm_recv_conf(
2988 &radio->recv_conf,
2989 radio->fm_hdev);
2990 break;
2991 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
2992 temp_val = ctrl->value;
2993 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
2994 break;
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05302995 case V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM:
2996 /*
2997 This private control is a place holder to keep the
2998 driver compatible with changes done in the frameworks
2999 which are specific to TAVARUA.
3000 */
3001 retval = 0;
3002 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 default:
3004 retval = -EINVAL;
3005 }
3006 return retval;
3007}
3008
3009static int iris_vidioc_g_tuner(struct file *file, void *priv,
3010 struct v4l2_tuner *tuner)
3011{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003012 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003013 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014 if (tuner->index > 0)
3015 return -EINVAL;
3016
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303017 if (radio->mode == FM_RECV) {
3018 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3019 if (retval < 0) {
3020 FMDERR("Failed to Get station params");
3021 return retval;
3022 }
3023 tuner->type = V4L2_TUNER_RADIO;
3024 tuner->rangelow =
3025 radio->recv_conf.band_low_limit * TUNE_PARAM;
3026 tuner->rangehigh =
3027 radio->recv_conf.band_high_limit * TUNE_PARAM;
3028 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
3029 tuner->capability = V4L2_TUNER_CAP_LOW;
3030 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
3031 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
3032 tuner->afc = 0;
3033 } else if (radio->mode == FM_TRANS) {
3034 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
3035 if (retval < 0) {
3036 FMDERR("get Tx config failed %d\n", retval);
3037 return retval;
3038 } else {
3039 tuner->type = V4L2_TUNER_RADIO;
3040 tuner->rangelow =
3041 radio->trans_conf.band_low_limit * TUNE_PARAM;
3042 tuner->rangehigh =
3043 radio->trans_conf.band_high_limit * TUNE_PARAM;
3044 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003045
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303046 } else
3047 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003048 return 0;
3049}
3050
3051static int iris_vidioc_s_tuner(struct file *file, void *priv,
3052 struct v4l2_tuner *tuner)
3053{
3054 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07003055 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003056 if (tuner->index > 0)
3057 return -EINVAL;
3058
Ankur Nandwanid928d542011-08-11 13:15:41 -07003059 if (radio->mode == FM_RECV) {
3060 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
3061 radio->recv_conf.band_high_limit =
3062 tuner->rangehigh / TUNE_PARAM;
3063 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
3064 radio->stereo_mode.stereo_mode = 0x01;
3065 retval = hci_set_fm_stereo_mode(
3066 &radio->stereo_mode,
3067 radio->fm_hdev);
3068 } else {
3069 radio->stereo_mode.stereo_mode = 0x00;
3070 retval = hci_set_fm_stereo_mode(
3071 &radio->stereo_mode,
3072 radio->fm_hdev);
3073 }
3074 if (retval < 0)
3075 FMDERR(": set tuner failed with %d\n", retval);
3076 return retval;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303077 } else if (radio->mode == FM_TRANS) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003078 radio->trans_conf.band_low_limit =
3079 tuner->rangelow / TUNE_PARAM;
3080 radio->trans_conf.band_high_limit =
3081 tuner->rangehigh / TUNE_PARAM;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303082 } else
3083 return -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003085 return retval;
3086}
3087
3088static int iris_vidioc_g_frequency(struct file *file, void *priv,
3089 struct v4l2_frequency *freq)
3090{
3091 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3092 int retval;
3093
3094 freq->type = V4L2_TUNER_RADIO;
3095 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3096 if (retval < 0)
3097 FMDERR("get frequency failed %d\n", retval);
3098 else
3099 freq->frequency =
3100 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
3101 return retval;
3102}
3103
3104static int iris_vidioc_s_frequency(struct file *file, void *priv,
3105 struct v4l2_frequency *freq)
3106{
3107 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3108 int retval = -1;
3109 freq->frequency = freq->frequency / TUNE_PARAM;
3110
3111 if (freq->type != V4L2_TUNER_RADIO)
3112 return -EINVAL;
3113
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003114 /* We turn off RDS prior to tuning to a new station.
3115 because of a bug in SoC which prevents tuning
3116 during RDS transmission.
3117 */
3118 if (radio->mode == FM_TRANS
3119 && (radio->trans_conf.rds_std == 0 ||
3120 radio->trans_conf.rds_std == 1)) {
3121 radio->prev_trans_rds = radio->trans_conf.rds_std;
3122 radio->trans_conf.rds_std = 2;
3123 hci_set_fm_trans_conf(&radio->trans_conf,
3124 radio->fm_hdev);
3125 }
3126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003127 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003128
3129 if (radio->mode == FM_TRANS
3130 && radio->trans_conf.rds_std == 2
3131 && (radio->prev_trans_rds == 1
3132 || radio->prev_trans_rds == 0)) {
3133 radio->trans_conf.rds_std = radio->prev_trans_rds;
3134 hci_set_fm_trans_conf(&radio->trans_conf,
3135 radio->fm_hdev);
3136 }
3137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003138 if (retval < 0)
3139 FMDERR(" set frequency failed with %d\n", retval);
3140 return retval;
3141}
3142
3143static int iris_vidioc_dqbuf(struct file *file, void *priv,
3144 struct v4l2_buffer *buffer)
3145{
3146 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3147 enum iris_buf_t buf_type = buffer->index;
3148 struct kfifo *data_fifo;
3149 unsigned char *buf = (unsigned char *)buffer->m.userptr;
3150 unsigned int len = buffer->length;
3151 if (!access_ok(VERIFY_WRITE, buf, len))
3152 return -EFAULT;
3153 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
3154 data_fifo = &radio->data_buf[buf_type];
3155 if (buf_type == IRIS_BUF_EVENTS)
3156 if (wait_event_interruptible(radio->event_queue,
3157 kfifo_len(data_fifo)) < 0)
3158 return -EINTR;
3159 } else {
3160 FMDERR("invalid buffer type\n");
3161 return -EINVAL;
3162 }
3163 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3164 &radio->buf_lock[buf_type]);
3165
3166 return 0;
3167}
3168
3169static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
3170 struct v4l2_format *f)
3171{
3172 return 0;
3173
3174}
3175
3176static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3177 struct v4l2_hw_freq_seek *seek)
3178{
3179 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3180 int dir;
3181 if (seek->seek_upward)
3182 dir = SRCH_DIR_UP;
3183 else
3184 dir = SRCH_DIR_DOWN;
3185 return iris_search(radio, CTRL_ON, dir);
3186}
3187
3188static int iris_vidioc_querycap(struct file *file, void *priv,
3189 struct v4l2_capability *capability)
3190{
3191 struct iris_device *radio;
3192 radio = video_get_drvdata(video_devdata(file));
3193 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
3194 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
3195 radio->g_cap = capability;
3196 return 0;
3197}
3198
3199
3200static const struct v4l2_ioctl_ops iris_ioctl_ops = {
3201 .vidioc_querycap = iris_vidioc_querycap,
3202 .vidioc_queryctrl = iris_vidioc_queryctrl,
3203 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
3204 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
3205 .vidioc_g_tuner = iris_vidioc_g_tuner,
3206 .vidioc_s_tuner = iris_vidioc_s_tuner,
3207 .vidioc_g_frequency = iris_vidioc_g_frequency,
3208 .vidioc_s_frequency = iris_vidioc_s_frequency,
3209 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
3210 .vidioc_dqbuf = iris_vidioc_dqbuf,
3211 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
3212 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303213 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214};
3215
3216static const struct v4l2_file_operations iris_fops = {
3217 .owner = THIS_MODULE,
3218 .unlocked_ioctl = video_ioctl2,
3219};
3220
3221static struct video_device iris_viddev_template = {
3222 .fops = &iris_fops,
3223 .ioctl_ops = &iris_ioctl_ops,
3224 .name = DRIVER_NAME,
3225 .release = video_device_release,
3226};
3227
3228static struct video_device *video_get_dev(void)
3229{
3230 return priv_videodev;
3231}
3232
3233static int __init iris_probe(struct platform_device *pdev)
3234{
3235 struct iris_device *radio;
3236 int retval;
3237 int radio_nr = -1;
3238 int i;
3239
3240 if (!pdev) {
3241 FMDERR(": pdev is null\n");
3242 return -ENOMEM;
3243 }
3244
3245 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
3246 if (!radio) {
3247 FMDERR(": Could not allocate radio device\n");
3248 return -ENOMEM;
3249 }
3250
3251 radio->dev = &pdev->dev;
3252 platform_set_drvdata(pdev, radio);
3253
3254 radio->videodev = video_device_alloc();
3255 if (!radio->videodev) {
3256 FMDERR(": Could not allocate V4L device\n");
3257 kfree(radio);
3258 return -ENOMEM;
3259 }
3260
3261 memcpy(radio->videodev, &iris_viddev_template,
3262 sizeof(iris_viddev_template));
3263
3264 for (i = 0; i < IRIS_BUF_MAX; i++) {
3265 int kfifo_alloc_rc = 0;
3266 spin_lock_init(&radio->buf_lock[i]);
3267
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07003268 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3270 rds_buf*3, GFP_KERNEL);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05303271 else if (i == IRIS_BUF_CAL_DATA)
3272 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3273 STD_BUF_SIZE*2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003274 else
3275 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3276 STD_BUF_SIZE, GFP_KERNEL);
3277
3278 if (kfifo_alloc_rc != 0) {
3279 FMDERR("failed allocating buffers %d\n",
3280 kfifo_alloc_rc);
3281 for (; i > -1; i--) {
3282 kfifo_free(&radio->data_buf[i]);
3283 kfree(radio);
3284 return -ENOMEM;
3285 }
3286 }
3287 }
3288
3289 mutex_init(&radio->lock);
3290 init_completion(&radio->sync_xfr_start);
3291 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003292 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003293 init_waitqueue_head(&radio->event_queue);
3294 init_waitqueue_head(&radio->read_queue);
3295
3296 video_set_drvdata(radio->videodev, radio);
3297
3298 if (NULL == video_get_drvdata(radio->videodev))
3299 FMDERR(": video_get_drvdata failed\n");
3300
3301 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
3302 radio_nr);
3303 if (retval) {
3304 FMDERR(": Could not register video device\n");
3305 video_device_release(radio->videodev);
3306 for (; i > -1; i--)
3307 kfifo_free(&radio->data_buf[i]);
3308 kfree(radio);
3309 return retval;
3310 } else {
3311 priv_videodev = kzalloc(sizeof(struct video_device),
3312 GFP_KERNEL);
3313 memcpy(priv_videodev, radio->videodev,
3314 sizeof(struct video_device));
3315 }
3316 return 0;
3317}
3318
3319
3320static int __devexit iris_remove(struct platform_device *pdev)
3321{
3322 int i;
3323 struct iris_device *radio = platform_get_drvdata(pdev);
3324
3325 video_unregister_device(radio->videodev);
3326
3327 for (i = 0; i < IRIS_BUF_MAX; i++)
3328 kfifo_free(&radio->data_buf[i]);
3329
3330 kfree(radio);
3331
3332 platform_set_drvdata(pdev, NULL);
3333
3334 return 0;
3335}
3336
3337static struct platform_driver iris_driver = {
3338 .driver = {
3339 .owner = THIS_MODULE,
3340 .name = "iris_fm",
3341 },
3342 .remove = __devexit_p(iris_remove),
3343};
3344
3345static int __init iris_radio_init(void)
3346{
3347 return platform_driver_probe(&iris_driver, iris_probe);
3348}
3349module_init(iris_radio_init);
3350
3351static void __exit iris_radio_exit(void)
3352{
3353 platform_driver_unregister(&iris_driver);
3354}
3355module_exit(iris_radio_exit);
3356
3357MODULE_LICENSE("GPL v2");
3358MODULE_AUTHOR(DRIVER_AUTHOR);
3359MODULE_DESCRIPTION(DRIVER_DESC);