blob: 179f46571808636d8d2d0969376bf4f9047b6646 [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 Uppala3c7a8eb2011-09-18 09:10:21 +053087 int search_on;
Ankur Nandwanid928d542011-08-11 13:15:41 -070088 unsigned int tone_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089 unsigned char g_scan_time;
90 unsigned int g_antenna;
91 unsigned int g_rds_grp_proc_ps;
92 enum iris_region_t region;
93 struct hci_fm_dbg_param_rsp st_dbg_param;
94 struct hci_ev_srch_list_compl srch_st_result;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -070095 struct hci_fm_riva_poke riva_data_req;
96 struct hci_fm_ssbi_req ssbi_data_accs;
97 struct hci_fm_ssbi_peek ssbi_peek_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098};
99
100static struct video_device *priv_videodev;
101
102static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
103 {
104 .id = V4L2_CID_AUDIO_VOLUME,
105 .type = V4L2_CTRL_TYPE_INTEGER,
106 .name = "Volume",
107 .minimum = 0,
108 .maximum = 15,
109 .step = 1,
110 .default_value = 15,
111 },
112 {
113 .id = V4L2_CID_AUDIO_BALANCE,
114 .flags = V4L2_CTRL_FLAG_DISABLED,
115 },
116 {
117 .id = V4L2_CID_AUDIO_BASS,
118 .flags = V4L2_CTRL_FLAG_DISABLED,
119 },
120 {
121 .id = V4L2_CID_AUDIO_TREBLE,
122 .flags = V4L2_CTRL_FLAG_DISABLED,
123 },
124 {
125 .id = V4L2_CID_AUDIO_MUTE,
126 .type = V4L2_CTRL_TYPE_BOOLEAN,
127 .name = "Mute",
128 .minimum = 0,
129 .maximum = 1,
130 .step = 1,
131 .default_value = 1,
132 },
133 {
134 .id = V4L2_CID_AUDIO_LOUDNESS,
135 .flags = V4L2_CTRL_FLAG_DISABLED,
136 },
137 {
138 .id = V4L2_CID_PRIVATE_IRIS_SRCHMODE,
139 .type = V4L2_CTRL_TYPE_INTEGER,
140 .name = "Search mode",
141 .minimum = 0,
142 .maximum = 7,
143 .step = 1,
144 .default_value = 0,
145 },
146 {
147 .id = V4L2_CID_PRIVATE_IRIS_SCANDWELL,
148 .type = V4L2_CTRL_TYPE_INTEGER,
149 .name = "Search dwell time",
150 .minimum = 0,
151 .maximum = 7,
152 .step = 1,
153 .default_value = 0,
154 },
155 {
156 .id = V4L2_CID_PRIVATE_IRIS_SRCHON,
157 .type = V4L2_CTRL_TYPE_BOOLEAN,
158 .name = "Search on/off",
159 .minimum = 0,
160 .maximum = 1,
161 .step = 1,
162 .default_value = 1,
163
164 },
165 {
166 .id = V4L2_CID_PRIVATE_IRIS_STATE,
167 .type = V4L2_CTRL_TYPE_INTEGER,
168 .name = "radio 0ff/rx/tx/reset",
169 .minimum = 0,
170 .maximum = 3,
171 .step = 1,
172 .default_value = 1,
173
174 },
175 {
176 .id = V4L2_CID_PRIVATE_IRIS_REGION,
177 .type = V4L2_CTRL_TYPE_INTEGER,
178 .name = "radio standard",
179 .minimum = 0,
180 .maximum = 2,
181 .step = 1,
182 .default_value = 0,
183 },
184 {
185 .id = V4L2_CID_PRIVATE_IRIS_SIGNAL_TH,
186 .type = V4L2_CTRL_TYPE_INTEGER,
187 .name = "Signal Threshold",
188 .minimum = 0x80,
189 .maximum = 0x7F,
190 .step = 1,
191 .default_value = 0,
192 },
193 {
194 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PTY,
195 .type = V4L2_CTRL_TYPE_INTEGER,
196 .name = "Search PTY",
197 .minimum = 0,
198 .maximum = 31,
199 .default_value = 0,
200 },
201 {
202 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PI,
203 .type = V4L2_CTRL_TYPE_INTEGER,
204 .name = "Search PI",
205 .minimum = 0,
206 .maximum = 0xFF,
207 .default_value = 0,
208 },
209 {
210 .id = V4L2_CID_PRIVATE_IRIS_SRCH_CNT,
211 .type = V4L2_CTRL_TYPE_INTEGER,
212 .name = "Preset num",
213 .minimum = 0,
214 .maximum = 12,
215 .default_value = 0,
216 },
217 {
218 .id = V4L2_CID_PRIVATE_IRIS_EMPHASIS,
219 .type = V4L2_CTRL_TYPE_BOOLEAN,
220 .name = "Emphasis",
221 .minimum = 0,
222 .maximum = 1,
223 .default_value = 0,
224 },
225 {
226 .id = V4L2_CID_PRIVATE_IRIS_RDS_STD,
227 .type = V4L2_CTRL_TYPE_BOOLEAN,
228 .name = "RDS standard",
229 .minimum = 0,
230 .maximum = 1,
231 .default_value = 0,
232 },
233 {
234 .id = V4L2_CID_PRIVATE_IRIS_SPACING,
235 .type = V4L2_CTRL_TYPE_INTEGER,
236 .name = "Channel spacing",
237 .minimum = 0,
238 .maximum = 2,
239 .default_value = 0,
240 },
241 {
242 .id = V4L2_CID_PRIVATE_IRIS_RDSON,
243 .type = V4L2_CTRL_TYPE_BOOLEAN,
244 .name = "RDS on/off",
245 .minimum = 0,
246 .maximum = 1,
247 .default_value = 0,
248 },
249 {
250 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK,
251 .type = V4L2_CTRL_TYPE_INTEGER,
252 .name = "RDS group mask",
253 .minimum = 0,
254 .maximum = 0xFFFFFFFF,
255 .default_value = 0,
256 },
257 {
258 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC,
259 .type = V4L2_CTRL_TYPE_INTEGER,
260 .name = "RDS processing",
261 .minimum = 0,
262 .maximum = 0xFF,
263 .default_value = 0,
264 },
265 {
266 .id = V4L2_CID_PRIVATE_IRIS_RDSD_BUF,
267 .type = V4L2_CTRL_TYPE_INTEGER,
268 .name = "RDS data groups to buffer",
269 .minimum = 1,
270 .maximum = 21,
271 .default_value = 0,
272 },
273 {
274 .id = V4L2_CID_PRIVATE_IRIS_PSALL,
275 .type = V4L2_CTRL_TYPE_BOOLEAN,
276 .name = "pass all ps strings",
277 .minimum = 0,
278 .maximum = 1,
279 .default_value = 0,
280 },
281 {
282 .id = V4L2_CID_PRIVATE_IRIS_LP_MODE,
283 .type = V4L2_CTRL_TYPE_BOOLEAN,
284 .name = "Low power mode",
285 .minimum = 0,
286 .maximum = 1,
287 .default_value = 0,
288 },
289 {
290 .id = V4L2_CID_PRIVATE_IRIS_ANTENNA,
291 .type = V4L2_CTRL_TYPE_BOOLEAN,
292 .name = "headset/internal",
293 .minimum = 0,
294 .maximum = 1,
295 .default_value = 0,
296 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 {
298 .id = V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT,
299 .type = V4L2_CTRL_TYPE_INTEGER,
300 .name = "Set PS REPEATCOUNT",
301 .minimum = 0,
302 .maximum = 15,
303 },
304 {
305 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME,
306 .type = V4L2_CTRL_TYPE_BOOLEAN,
307 .name = "Stop PS NAME",
308 .minimum = 0,
309 .maximum = 1,
310 },
311 {
312 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT,
313 .type = V4L2_CTRL_TYPE_BOOLEAN,
314 .name = "Stop RT",
315 .minimum = 0,
316 .maximum = 1,
317 },
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700318 {
319 .id = V4L2_CID_PRIVATE_IRIS_SOFT_MUTE,
320 .type = V4L2_CTRL_TYPE_BOOLEAN,
321 .name = "Soft Mute",
322 .minimum = 0,
323 .maximum = 1,
324 },
325 {
326 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR,
327 .type = V4L2_CTRL_TYPE_BOOLEAN,
328 .name = "Riva addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530329 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700330 .maximum = 0x31E0004,
331 },
332 {
333 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN,
334 .type = V4L2_CTRL_TYPE_INTEGER,
335 .name = "Data len",
336 .minimum = 0,
337 .maximum = 0xFF,
338 },
339 {
340 .id = V4L2_CID_PRIVATE_IRIS_RIVA_PEEK,
341 .type = V4L2_CTRL_TYPE_BOOLEAN,
342 .name = "Riva peek",
343 .minimum = 0,
344 .maximum = 1,
345 },
346 {
347 .id = V4L2_CID_PRIVATE_IRIS_RIVA_POKE,
348 .type = V4L2_CTRL_TYPE_INTEGER,
349 .name = "Riva poke",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530350 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700351 .maximum = 0x31E0004,
352 },
353 {
354 .id = V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR,
355 .type = V4L2_CTRL_TYPE_INTEGER,
356 .name = "Ssbi addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530357 .minimum = 0x280,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700358 .maximum = 0x37F,
359 },
360 {
361 .id = V4L2_CID_PRIVATE_IRIS_SSBI_PEEK,
362 .type = V4L2_CTRL_TYPE_INTEGER,
363 .name = "Ssbi peek",
364 .minimum = 0,
365 .maximum = 0x37F,
366 },
367 {
368 .id = V4L2_CID_PRIVATE_IRIS_SSBI_POKE,
369 .type = V4L2_CTRL_TYPE_INTEGER,
370 .name = "ssbi poke",
371 .minimum = 0x01,
372 .maximum = 0xFF,
373 },
374 {
375 .id = V4L2_CID_PRIVATE_IRIS_HLSI,
376 .type = V4L2_CTRL_TYPE_INTEGER,
377 .name = "set hlsi",
378 .minimum = 0,
379 .maximum = 2,
380 },
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530381 {
382 .id = V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS,
383 .type = V4L2_CTRL_TYPE_BOOLEAN,
384 .name = "RDS grp",
385 .minimum = 0,
386 .maximum = 1,
387 },
388 {
389 .id = V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER,
390 .type = V4L2_CTRL_TYPE_INTEGER,
391 .name = "Notch filter",
392 .minimum = 0,
393 .maximum = 2,
394 },
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530395 {
396 .id = V4L2_CID_PRIVATE_IRIS_READ_DEFAULT,
397 .type = V4L2_CTRL_TYPE_INTEGER,
398 .name = "Read default",
399 },
400 {
401 .id = V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT,
402 .type = V4L2_CTRL_TYPE_INTEGER,
403 .name = "Write default",
404 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405};
406
407static void iris_q_event(struct iris_device *radio,
408 enum iris_evt_t event)
409{
410 struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
411 unsigned char evt = event;
412 if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
413 wake_up_interruptible(&radio->event_queue);
414}
415
416static int hci_send_frame(struct sk_buff *skb)
417{
418 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
419
420 if (!hdev) {
421 kfree_skb(skb);
422 return -ENODEV;
423 }
424
425 __net_timestamp(skb);
426
427 skb_orphan(skb);
428 return hdev->send(skb);
429}
430
431static void radio_hci_cmd_task(unsigned long arg)
432{
433 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
434 struct sk_buff *skb;
435 if (!(atomic_read(&hdev->cmd_cnt))
436 && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
437 FMDERR("%s command tx timeout", hdev->name);
438 atomic_set(&hdev->cmd_cnt, 1);
439 }
440
441 skb = skb_dequeue(&hdev->cmd_q);
442 if (atomic_read(&hdev->cmd_cnt) && skb) {
443 kfree_skb(hdev->sent_cmd);
444 hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
445 if (hdev->sent_cmd) {
446 atomic_dec(&hdev->cmd_cnt);
447 hci_send_frame(skb);
448 hdev->cmd_last_tx = jiffies;
449 } else {
450 skb_queue_head(&hdev->cmd_q, skb);
451 tasklet_schedule(&hdev->cmd_task);
452 }
453 }
454
455}
456
457static void radio_hci_rx_task(unsigned long arg)
458{
459 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
460 struct sk_buff *skb;
461
462 read_lock(&hci_task_lock);
463
464 skb = skb_dequeue(&hdev->rx_q);
465 radio_hci_event_packet(hdev, skb);
466
467 read_unlock(&hci_task_lock);
468}
469
470int radio_hci_register_dev(struct radio_hci_dev *hdev)
471{
472 struct iris_device *radio = video_get_drvdata(video_get_dev());
473 if (!radio) {
474 FMDERR(":radio is null");
475 return -EINVAL;
476 }
477
478 if (!hdev) {
479 FMDERR("hdev is null");
480 return -EINVAL;
481 }
482
483 hdev->flags = 0;
484
485 tasklet_init(&hdev->cmd_task, radio_hci_cmd_task, (unsigned long)
486 hdev);
487 tasklet_init(&hdev->rx_task, radio_hci_rx_task, (unsigned long)
488 hdev);
489
490 init_waitqueue_head(&hdev->req_wait_q);
491
492 skb_queue_head_init(&hdev->rx_q);
493 skb_queue_head_init(&hdev->cmd_q);
494 skb_queue_head_init(&hdev->raw_q);
495
496 if (!radio)
497 FMDERR(":radio is null");
498
499 radio->fm_hdev = hdev;
500
501 return 0;
502}
503EXPORT_SYMBOL(radio_hci_register_dev);
504
505int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
506{
507 struct iris_device *radio = video_get_drvdata(video_get_dev());
508 if (!radio) {
509 FMDERR(":radio is null");
510 return -EINVAL;
511 }
512
513 tasklet_kill(&hdev->rx_task);
514 tasklet_kill(&hdev->cmd_task);
515 skb_queue_purge(&hdev->rx_q);
516 skb_queue_purge(&hdev->cmd_q);
517 skb_queue_purge(&hdev->raw_q);
518 kfree(radio->fm_hdev);
519 kfree(radio->videodev);
520
521 return 0;
522}
523EXPORT_SYMBOL(radio_hci_unregister_dev);
524
525int radio_hci_recv_frame(struct sk_buff *skb)
526{
527 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
528 if (!hdev) {
529 FMDERR("%s hdev is null while receiving frame", hdev->name);
530 kfree_skb(skb);
531 return -ENXIO;
532 }
533
534 __net_timestamp(skb);
535
536 radio_hci_event_packet(hdev, skb);
Srinivasa Rao Uppalacf3a8112011-09-22 21:02:02 +0530537 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700538 return 0;
539}
540EXPORT_SYMBOL(radio_hci_recv_frame);
541
542int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
543 void *param)
544{
545 int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
546 struct radio_hci_command_hdr *hdr;
547 struct sk_buff *skb;
548 int ret = 0;
549
550 skb = alloc_skb(len, GFP_ATOMIC);
551 if (!skb) {
552 FMDERR("%s no memory for command", hdev->name);
553 return -ENOMEM;
554 }
555
556 hdr = (struct radio_hci_command_hdr *) skb_put(skb,
557 RADIO_HCI_COMMAND_HDR_SIZE);
558 hdr->opcode = cpu_to_le16(opcode);
559 hdr->plen = plen;
560
561 if (plen)
562 memcpy(skb_put(skb, plen), param, plen);
563
564 skb->dev = (void *) hdev;
565
566 ret = hci_send_frame(skb);
567
568 return ret;
569}
570EXPORT_SYMBOL(radio_hci_send_cmd);
571
572static int hci_fm_enable_recv_req(struct radio_hci_dev *hdev,
573 unsigned long param)
574{
575 __u16 opcode = 0;
576
577 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
578 HCI_OCF_FM_ENABLE_RECV_REQ);
579 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
580}
581
Ankur Nandwanid928d542011-08-11 13:15:41 -0700582static int hci_fm_tone_generator(struct radio_hci_dev *hdev,
583 unsigned long param)
584{
585 struct iris_device *radio = video_get_drvdata(video_get_dev());
586 __u16 opcode = 0;
587
588 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
589 HCI_FM_SET_INTERNAL_TONE_GENRATOR);
590 return radio_hci_send_cmd(hdev, opcode,
591 sizeof(radio->tone_freq), &radio->tone_freq);
592}
593
594static int hci_fm_enable_trans_req(struct radio_hci_dev *hdev,
595 unsigned long param)
596{
597 __u16 opcode = 0;
598
599 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
600 HCI_OCF_FM_ENABLE_TRANS_REQ);
601 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
602}
603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604static int hci_fm_disable_recv_req(struct radio_hci_dev *hdev,
605 unsigned long param)
606{
607 __u16 opcode = 0;
608
609 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
610 HCI_OCF_FM_DISABLE_RECV_REQ);
611 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
612}
613
Ankur Nandwanid928d542011-08-11 13:15:41 -0700614static int hci_fm_disable_trans_req(struct radio_hci_dev *hdev,
615 unsigned long param)
616{
617 __u16 opcode = 0;
618
619 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
620 HCI_OCF_FM_DISABLE_TRANS_REQ);
621 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
622}
623
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624static int hci_get_fm_recv_conf_req(struct radio_hci_dev *hdev,
625 unsigned long param)
626{
627 __u16 opcode = 0;
628
629 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
630 HCI_OCF_FM_GET_RECV_CONF_REQ);
631 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
632}
633
634static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
635 unsigned long param)
636{
637 __u16 opcode = 0;
638
639 struct hci_fm_recv_conf_req *recv_conf_req =
640 (struct hci_fm_recv_conf_req *) param;
641
642 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
643 HCI_OCF_FM_SET_RECV_CONF_REQ);
644 return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
645 recv_conf_req);
646}
647
Ankur Nandwanid928d542011-08-11 13:15:41 -0700648static int hci_set_fm_trans_conf_req(struct radio_hci_dev *hdev,
649 unsigned long param)
650{
651 __u16 opcode = 0;
652
653 struct hci_fm_trans_conf_req_struct *trans_conf_req =
654 (struct hci_fm_trans_conf_req_struct *) param;
655
656 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
657 HCI_OCF_FM_SET_TRANS_CONF_REQ);
658 return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
659 trans_conf_req);
660}
661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
663 unsigned long param)
664{
665 __u16 opcode = 0;
666
667 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
668 HCI_OCF_FM_GET_STATION_PARAM_REQ);
669 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
670}
671
672static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
673 unsigned long param)
674{
675 __u16 opcode = 0;
676 struct hci_fm_mute_mode_req *mute_mode_req =
677 (struct hci_fm_mute_mode_req *) param;
678
679 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
680 HCI_OCF_FM_SET_MUTE_MODE_REQ);
681 return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
682 mute_mode_req);
683}
684
Ankur Nandwanid928d542011-08-11 13:15:41 -0700685
686static int hci_trans_ps_req(struct radio_hci_dev *hdev,
687 unsigned long param)
688{
689 __u16 opcode = 0;
690 struct hci_fm_tx_ps *tx_ps_req =
691 (struct hci_fm_tx_ps *) param;
692
693 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
694 HCI_OCF_FM_RDS_PS_REQ);
695
696 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_ps_req)),
697 tx_ps_req);
698}
699
700static int hci_trans_rt_req(struct radio_hci_dev *hdev,
701 unsigned long param)
702{
703 __u16 opcode = 0;
704 struct hci_fm_tx_rt *tx_rt_req =
705 (struct hci_fm_tx_rt *) param;
706
707 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
708 HCI_OCF_FM_RDS_RT_REQ);
709
710 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_rt_req)),
711 tx_rt_req);
712}
713
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700714static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
715 unsigned long param)
716{
717 __u16 opcode = 0;
718 struct hci_fm_stereo_mode_req *stereo_mode_req =
719 (struct hci_fm_stereo_mode_req *) param;
720 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
721 HCI_OCF_FM_SET_STEREO_MODE_REQ);
722 return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
723 stereo_mode_req);
724}
725
726static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
727 unsigned long param)
728{
729 __u16 opcode = 0;
730
731 __u8 antenna = param;
732
733 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
734 HCI_OCF_FM_SET_ANTENNA);
735 return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
736}
737
738static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
739 unsigned long param)
740{
741 __u16 opcode = 0;
742
743 __u8 sig_threshold = param;
744
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530745 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
747 return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
748 &sig_threshold);
749}
750
751static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
752 unsigned long param)
753{
754 __u16 opcode = 0;
755
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530756 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700757 HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
758 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
759}
760
761static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
762 unsigned long param)
763{
764 __u16 opcode = 0;
765
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530766 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700767 HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
768 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
769}
770
771static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
772 unsigned long param)
773{
774 __u16 opcode = 0;
775
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530776 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777 HCI_OCF_FM_GET_RADIO_TEXT_REQ);
778 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
779}
780
781static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
782 unsigned long param)
783{
784 __u16 opcode = 0;
785
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530786 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 HCI_OCF_FM_GET_AF_LIST_REQ);
788 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
789}
790
791static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
792 unsigned long param)
793{
794 __u16 opcode = 0;
795 struct hci_fm_search_station_req *srch_stations =
796 (struct hci_fm_search_station_req *) param;
797
798 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
799 HCI_OCF_FM_SEARCH_STATIONS);
800 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
801 srch_stations);
802}
803
804static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
805 unsigned long param)
806{
807 __u16 opcode = 0;
808 struct hci_fm_search_rds_station_req *srch_stations =
809 (struct hci_fm_search_rds_station_req *) param;
810
811 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
812 HCI_OCF_FM_SEARCH_RDS_STATIONS);
813 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
814 srch_stations);
815}
816
817static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
818 unsigned long param)
819{
820 __u16 opcode = 0;
821 struct hci_fm_search_station_list_req *srch_list =
822 (struct hci_fm_search_station_list_req *) param;
823
824 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
825 HCI_OCF_FM_SEARCH_STATIONS_LIST);
826 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
827 srch_list);
828}
829
830static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
831 unsigned long param)
832{
833 __u16 opcode = 0;
834
835 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
836 HCI_OCF_FM_CANCEL_SEARCH);
837 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
838}
839
840static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
841 unsigned long param)
842{
843 __u16 opcode = 0;
844
845 __u32 fm_grps_process = param;
846
847 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
848 HCI_OCF_FM_RDS_GRP_PROCESS);
849 return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
850 &fm_grps_process);
851}
852
853static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
854 unsigned long param)
855{
856 __u16 opcode = 0;
857
858 __u32 tune_freq = param;
859
860 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
861 HCI_OCF_FM_TUNE_STATION_REQ);
862 return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
863}
864
865static int hci_def_data_read_req(struct radio_hci_dev *hdev,
866 unsigned long param)
867{
868 __u16 opcode = 0;
869 struct hci_fm_def_data_rd_req *def_data_rd =
870 (struct hci_fm_def_data_rd_req *) param;
871
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530872 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700873 HCI_OCF_FM_DEFAULT_DATA_READ);
874 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
875 def_data_rd);
876}
877
878static int hci_def_data_write_req(struct radio_hci_dev *hdev,
879 unsigned long param)
880{
881 __u16 opcode = 0;
882 struct hci_fm_def_data_wr_req *def_data_wr =
883 (struct hci_fm_def_data_wr_req *) param;
884
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530885 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 HCI_OCF_FM_DEFAULT_DATA_WRITE);
887 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
888 def_data_wr);
889}
890
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530891static int hci_set_notch_filter_req(struct radio_hci_dev *hdev,
892 unsigned long param)
893{
894 __u16 opcode = 0;
895 __u8 notch_filter_val = param;
896
897 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
898 HCI_OCF_FM_EN_NOTCH_CTRL);
899 return radio_hci_send_cmd(hdev, opcode, sizeof(notch_filter_val),
900 &notch_filter_val);
901}
902
903
904
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
906{
907 __u16 opcode = 0;
908
909 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
910 HCI_OCF_FM_RESET);
911 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
912}
913
914static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
915 unsigned long param)
916{
917 __u16 opcode = 0;
918
919 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
920 HCI_OCF_FM_GET_FEATURE_LIST);
921 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
922}
923
924static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
925 unsigned long param)
926{
927 __u16 opcode = 0;
928
929 __u8 mode = param;
930
931 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
932 HCI_OCF_FM_DO_CALIBRATION);
933 return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
934}
935
936static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
937 unsigned long param)
938{
939 __u16 opcode = 0;
940
941 __u8 reset_counters = param;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530942 opcode = hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 HCI_OCF_FM_READ_GRP_COUNTERS);
944 return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
945 &reset_counters);
946}
947
948static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
949{
950 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700951 struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700952
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700953 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954 HCI_OCF_FM_PEEK_DATA);
955 return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
956 peek_data);
957}
958
959static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
960{
961 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700962 struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -0700964 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 HCI_OCF_FM_POKE_DATA);
966 return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
967 poke_data);
968}
969
970static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
971 unsigned long param)
972{
973 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700974 struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700975
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700976 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977 HCI_OCF_FM_SSBI_PEEK_REG);
978 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
979 ssbi_peek);
980}
981
982static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
983 unsigned long param)
984{
985 __u16 opcode = 0;
986 struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
987
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700988 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 HCI_OCF_FM_SSBI_POKE_REG);
990 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
991 ssbi_poke);
992}
993
994static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
995 unsigned long param)
996{
997 __u16 opcode = 0;
998
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530999 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000 HCI_OCF_FM_STATION_DBG_PARAM);
1001 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1002}
1003
1004static int radio_hci_err(__u16 code)
1005{
1006 switch (code) {
1007 case 0:
1008 return 0;
1009 case 0x01:
1010 return -EBADRQC;
1011 case 0x02:
1012 return -ENOTCONN;
1013 case 0x03:
1014 return -EIO;
1015 case 0x07:
1016 return -ENOMEM;
1017 case 0x0c:
1018 return -EBUSY;
1019 case 0x11:
1020 return -EOPNOTSUPP;
1021 case 0x12:
1022 return -EINVAL;
1023 default:
1024 return -ENOSYS;
1025 }
1026}
1027
1028static int __radio_hci_request(struct radio_hci_dev *hdev,
1029 int (*req)(struct radio_hci_dev *hdev,
1030 unsigned long param),
1031 unsigned long param, __u32 timeout)
1032{
1033 int err = 0;
1034
1035 DECLARE_WAITQUEUE(wait, current);
1036
1037 hdev->req_status = HCI_REQ_PEND;
1038
1039 add_wait_queue(&hdev->req_wait_q, &wait);
1040 set_current_state(TASK_INTERRUPTIBLE);
1041
1042 err = req(hdev, param);
1043
1044 schedule_timeout(timeout);
1045
1046 remove_wait_queue(&hdev->req_wait_q, &wait);
1047
1048 if (signal_pending(current))
1049 return -EINTR;
1050
1051 switch (hdev->req_status) {
1052 case HCI_REQ_DONE:
1053 case HCI_REQ_STATUS:
1054 err = radio_hci_err(hdev->req_result);
1055 break;
1056
1057 case HCI_REQ_CANCELED:
1058 err = -hdev->req_result;
1059 break;
1060
1061 default:
1062 err = -ETIMEDOUT;
1063 break;
1064 }
1065
1066 hdev->req_status = hdev->req_result = 0;
1067
1068 return err;
1069}
1070
1071static inline int radio_hci_request(struct radio_hci_dev *hdev,
1072 int (*req)(struct
1073 radio_hci_dev * hdev, unsigned long param),
1074 unsigned long param, __u32 timeout)
1075{
1076 int ret = 0;
1077
1078 ret = __radio_hci_request(hdev, req, param, timeout);
1079
1080 return ret;
1081}
1082
1083static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
1084 struct radio_hci_dev *hdev)
1085{
1086 int ret = 0;
1087 struct hci_fm_recv_conf_req *set_recv_conf = arg;
1088
1089 ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
1090 long)set_recv_conf, RADIO_HCI_TIMEOUT);
1091
1092 return ret;
1093}
1094
Ankur Nandwanid928d542011-08-11 13:15:41 -07001095static int hci_set_fm_trans_conf(struct hci_fm_trans_conf_req_struct *arg,
1096 struct radio_hci_dev *hdev)
1097{
1098 int ret = 0;
1099 struct hci_fm_trans_conf_req_struct *set_trans_conf = arg;
1100
1101 ret = radio_hci_request(hdev, hci_set_fm_trans_conf_req, (unsigned
1102 long)set_trans_conf, RADIO_HCI_TIMEOUT);
1103
1104 return ret;
1105}
1106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
1108{
1109 int ret = 0;
1110 __u32 tune_freq = *arg;
1111
1112 ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
1113 RADIO_HCI_TIMEOUT);
1114
1115 return ret;
1116}
1117
1118static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
1119 struct radio_hci_dev *hdev)
1120{
1121 int ret = 0;
1122 struct hci_fm_mute_mode_req *set_mute_conf = arg;
1123
1124 ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
1125 long)set_mute_conf, RADIO_HCI_TIMEOUT);
1126
1127 return ret;
1128}
1129
1130static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
1131 struct radio_hci_dev *hdev)
1132{
1133 int ret = 0;
1134 struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
1135
1136 ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
1137 long)set_stereo_conf, RADIO_HCI_TIMEOUT);
1138
1139 return ret;
1140}
1141
1142static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
1143{
1144 int ret = 0;
1145 __u8 antenna = *arg;
1146
1147 ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
1148 RADIO_HCI_TIMEOUT);
1149
1150 return ret;
1151}
1152
1153static int hci_fm_set_signal_threshold(__u8 *arg,
1154 struct radio_hci_dev *hdev)
1155{
1156 int ret = 0;
1157 __u8 sig_threshold = *arg;
1158
1159 ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
1160 sig_threshold, RADIO_HCI_TIMEOUT);
1161
1162 return ret;
1163}
1164
1165static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
1166 struct radio_hci_dev *hdev)
1167{
1168 int ret = 0;
1169 struct hci_fm_search_station_req *srch_stations = arg;
1170
1171 ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
1172 long)srch_stations, RADIO_HCI_TIMEOUT);
1173
1174 return ret;
1175}
1176
1177static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
1178 struct radio_hci_dev *hdev)
1179{
1180 int ret = 0;
1181 struct hci_fm_search_rds_station_req *srch_stations = arg;
1182
1183 ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
1184 long)srch_stations, RADIO_HCI_TIMEOUT);
1185
1186 return ret;
1187}
1188
1189static int hci_fm_search_station_list
1190 (struct hci_fm_search_station_list_req *arg,
1191 struct radio_hci_dev *hdev)
1192{
1193 int ret = 0;
1194 struct hci_fm_search_station_list_req *srch_list = arg;
1195
1196 ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
1197 long)srch_list, RADIO_HCI_TIMEOUT);
1198
1199 return ret;
1200}
1201
1202static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
1203 struct radio_hci_dev *hdev)
1204{
1205 return 0;
1206}
1207
1208static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
1209{
1210 int ret = 0;
1211 __u32 fm_grps_process = *arg;
1212
1213 ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
1214 fm_grps_process, RADIO_HCI_TIMEOUT);
1215
1216 return ret;
1217}
1218
1219int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
1220 struct radio_hci_dev *hdev)
1221{
1222 int ret = 0;
1223 struct hci_fm_def_data_rd_req *def_data_rd = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
1225 long)def_data_rd, RADIO_HCI_TIMEOUT);
1226
1227 return ret;
1228}
1229
1230int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
1231 struct radio_hci_dev *hdev)
1232{
1233 int ret = 0;
1234 struct hci_fm_def_data_wr_req *def_data_wr = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
1236 long)def_data_wr, RADIO_HCI_TIMEOUT);
1237
1238 return ret;
1239}
1240
1241int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
1242{
1243 int ret = 0;
1244 __u8 mode = *arg;
1245
1246 ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
1247 RADIO_HCI_TIMEOUT);
1248
1249 return ret;
1250}
1251
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301252static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253{
1254 int ret = 0;
1255 __u8 reset_counters = *arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 ret = radio_hci_request(hdev, hci_read_grp_counters_req,
1257 reset_counters, RADIO_HCI_TIMEOUT);
1258
1259 return ret;
1260}
1261
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301262static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
1263{
1264 int ret = 0;
1265 __u8 notch_filter = *arg;
1266 ret = radio_hci_request(hdev, hci_set_notch_filter_req,
1267 notch_filter, RADIO_HCI_TIMEOUT);
1268
1269 return ret;
1270}
1271
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001272static int hci_peek_data(struct hci_fm_riva_data *arg,
1273 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274{
1275 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001276 struct hci_fm_riva_data *peek_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277
1278 ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
1279 long)peek_data, RADIO_HCI_TIMEOUT);
1280
1281 return ret;
1282}
1283
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001284static int hci_poke_data(struct hci_fm_riva_poke *arg,
1285 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286{
1287 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001288 struct hci_fm_riva_poke *poke_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289
1290 ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
1291 long)poke_data, RADIO_HCI_TIMEOUT);
1292
1293 return ret;
1294}
1295
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001296static int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *arg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297 struct radio_hci_dev *hdev)
1298{
1299 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001300 struct hci_fm_ssbi_peek *ssbi_peek_reg = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301
1302 ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
1303 long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
1304
1305 return ret;
1306}
1307
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001308static int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg,
1309 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310{
1311 int ret = 0;
1312 struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
1313
1314 ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
1315 long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
1316
1317 return ret;
1318}
1319
1320static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1321{
1322 int ret = 0;
1323 unsigned long arg = 0;
1324
Ankur Nandwanid928d542011-08-11 13:15:41 -07001325 if (!hdev)
1326 return -ENODEV;
1327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 switch (cmd) {
1329 case HCI_FM_ENABLE_RECV_CMD:
1330 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1331 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1332 break;
1333
1334 case HCI_FM_DISABLE_RECV_CMD:
1335 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1336 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1337 break;
1338
1339 case HCI_FM_GET_RECV_CONF_CMD:
1340 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1341 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1342 break;
1343
1344 case HCI_FM_GET_STATION_PARAM_CMD:
1345 ret = radio_hci_request(hdev,
1346 hci_fm_get_station_param_req, arg,
1347 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1348 break;
1349
1350 case HCI_FM_GET_SIGNAL_TH_CMD:
1351 ret = radio_hci_request(hdev,
1352 hci_fm_get_sig_threshold_req, arg,
1353 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1354 break;
1355
1356 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1357 ret = radio_hci_request(hdev,
1358 hci_fm_get_program_service_req, arg,
1359 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1360 break;
1361
1362 case HCI_FM_GET_RADIO_TEXT_CMD:
1363 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1364 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1365 break;
1366
1367 case HCI_FM_GET_AF_LIST_CMD:
1368 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1369 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1370 break;
1371
1372 case HCI_FM_CANCEL_SEARCH_CMD:
1373 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1374 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1375 break;
1376
1377 case HCI_FM_RESET_CMD:
1378 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1379 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1380 break;
1381
1382 case HCI_FM_GET_FEATURES_CMD:
1383 ret = radio_hci_request(hdev,
1384 hci_fm_get_feature_lists_req, arg,
1385 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1386 break;
1387
1388 case HCI_FM_STATION_DBG_PARAM_CMD:
1389 ret = radio_hci_request(hdev,
1390 hci_fm_get_station_dbg_param_req, arg,
1391 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1392 break;
1393
Ankur Nandwanid928d542011-08-11 13:15:41 -07001394 case HCI_FM_ENABLE_TRANS_CMD:
1395 ret = radio_hci_request(hdev, hci_fm_enable_trans_req, arg,
1396 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1397 break;
1398
1399 case HCI_FM_DISABLE_TRANS_CMD:
1400 ret = radio_hci_request(hdev, hci_fm_disable_trans_req, arg,
1401 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1402 break;
1403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 default:
1405 ret = -EINVAL;
1406 break;
1407 }
1408
1409 return ret;
1410}
1411
1412static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1413{
1414 hdev->req_result = result;
1415 hdev->req_status = HCI_REQ_DONE;
1416 wake_up_interruptible(&hdev->req_wait_q);
1417}
1418
1419static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1420{
1421 hdev->req_result = result;
1422 hdev->req_status = HCI_REQ_STATUS;
1423 wake_up_interruptible(&hdev->req_wait_q);
1424}
1425
1426static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1427{
1428 __u8 status = *((__u8 *) skb->data);
1429
1430 if (status)
1431 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432 radio_hci_req_complete(hdev, status);
1433}
1434
1435static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1436 struct sk_buff *skb)
1437{
1438 __u8 status = *((__u8 *) skb->data);
1439 struct iris_device *radio = video_get_drvdata(video_get_dev());
1440
1441 if (status)
1442 return;
1443
1444 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1445
1446 radio_hci_req_complete(hdev, status);
1447}
1448
1449static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1450{
1451 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1452 struct iris_device *radio = video_get_drvdata(video_get_dev());
1453
1454 if (rsp->status)
1455 return;
1456
1457 radio->recv_conf = rsp->recv_conf_rsp;
1458 radio_hci_req_complete(hdev, rsp->status);
1459}
1460
1461static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1462 struct sk_buff *skb)
1463{
1464 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1465 struct iris_device *radio = video_get_drvdata(video_get_dev());
1466
1467 if (rsp->status)
1468 return;
1469
1470 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1471
1472 radio_hci_req_complete(hdev, rsp->status);
1473}
1474
Ankur Nandwanid928d542011-08-11 13:15:41 -07001475
1476static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
1477 struct sk_buff *skb)
1478{
1479 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1480 struct iris_device *radio = video_get_drvdata(video_get_dev());
1481
1482 if (rsp->status)
1483 return;
1484
1485 iris_q_event(radio, HCI_EV_CMD_COMPLETE);
1486
1487 radio_hci_req_complete(hdev, rsp->status);
1488}
1489
1490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1492 struct sk_buff *skb)
1493{
1494 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1495 struct iris_device *radio = video_get_drvdata(video_get_dev());
1496 struct v4l2_control *v4l_ctl = radio->g_ctl;
1497
1498 if (rsp->status)
1499 return;
1500
1501 v4l_ctl->value = rsp->sig_threshold;
1502
1503 radio_hci_req_complete(hdev, rsp->status);
1504}
1505
1506static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1507{
1508 struct iris_device *radio = video_get_drvdata(video_get_dev());
1509 struct hci_fm_station_rsp *rsp = (void *)skb->data;
1510 radio->fm_st_rsp = *(rsp);
1511
1512 /* Tune is always succesful */
1513 radio_hci_req_complete(hdev, 0);
1514}
1515
1516static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1517{
1518 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1519
1520 if (rsp->status)
1521 return;
1522
1523 radio_hci_req_complete(hdev, rsp->status);
1524}
1525
1526static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1527{
1528 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1529
1530 if (rsp->status)
1531 return;
1532
1533 radio_hci_req_complete(hdev, rsp->status);
1534}
1535
1536static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1537{
1538 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1539
1540 if (rsp->status)
1541 return;
1542
1543 radio_hci_req_complete(hdev, rsp->status);
1544}
1545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1547 struct sk_buff *skb)
1548{
1549 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1550 struct iris_device *radio = video_get_drvdata(video_get_dev());
1551 struct v4l2_capability *v4l_cap = radio->g_cap;
1552
1553 if (rsp->status)
1554 return;
1555 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1556 (rsp->feature_mask & 0x000001);
1557
1558 radio_hci_req_complete(hdev, rsp->status);
1559}
1560
1561static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1562 struct sk_buff *skb)
1563{
1564 struct iris_device *radio = video_get_drvdata(video_get_dev());
1565 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
1566 radio->st_dbg_param = *(rsp);
1567
1568 if (radio->st_dbg_param.status)
1569 return;
1570
1571 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1572}
1573
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001574static void iris_q_evt_data(struct iris_device *radio,
1575 char *data, int len, int event)
1576{
1577 struct kfifo *data_b = &radio->data_buf[event];
1578 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1579 wake_up_interruptible(&radio->event_queue);
1580}
1581
1582static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1583 struct sk_buff *skb)
1584{
1585 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301586 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001587 int len;
1588 char *data;
1589
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301590 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001591 return;
1592 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1593 data = kmalloc(len, GFP_ATOMIC);
1594
1595 if (!data) {
1596 FMDERR("Memory allocation failed");
1597 return;
1598 }
1599
1600 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1601 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301602 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001603
1604
1605}
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301606
1607static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
1608 struct sk_buff *skb)
1609{
1610 struct iris_device *radio = video_get_drvdata(video_get_dev());
1611 __u8 status = *((__u8 *) skb->data);
1612 __u8 len;
1613 char *data;
1614
1615 if (status)
1616 return;
1617 len = skb->data[1];
1618 data = kmalloc(len+2, GFP_ATOMIC);
1619 if (!data) {
1620 FMDERR("Memory allocation failed");
1621 return;
1622 }
1623
1624 data[0] = status;
1625 data[1] = len;
1626 memcpy(&data[2], &skb->data[DEFAULT_DATA_OFFSET], len);
1627 iris_q_evt_data(radio, data, len+2, IRIS_BUF_RD_DEFAULT);
1628 radio_hci_req_complete(hdev, status);
1629 kfree(data);
1630}
1631
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001632static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1633 struct sk_buff *skb)
1634{
1635 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301636 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001637 char *data;
1638
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301639 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001640 return;
1641 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1642 if (!data) {
1643 FMDERR("Memory allocation failed");
1644 return;
1645 }
1646
1647 data[0] = skb->data[PEEK_DATA_OFSET];
1648 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301649 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001650 kfree(data);
1651}
1652
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301653static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
1654 struct sk_buff *skb)
1655{
1656 struct iris_device *radio = video_get_drvdata(video_get_dev());
1657 __u8 status = *((__u8 *) skb->data);
1658 char *data;
1659 if (status)
1660 return;
1661 data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
1662 if (!data) {
1663 FMDERR("memory allocation failed");
1664 return;
1665 }
1666 memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
1667 iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
1668 radio_hci_req_complete(hdev, status);
1669 kfree(data);
1670
1671}
1672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
1674 struct sk_buff *skb)
1675{
1676 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
1677 __u16 opcode;
1678
1679 skb_pull(skb, sizeof(*cmd_compl_ev));
1680
1681 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
1682
1683 switch (opcode) {
1684 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
1685 hci_cc_fm_enable_rsp(hdev, skb);
1686 break;
1687 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
1688 hci_cc_conf_rsp(hdev, skb);
1689 break;
1690
1691 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
1692 hci_cc_fm_disable_rsp(hdev, skb);
1693 break;
1694
1695 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
1696 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
1697 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
1698 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
1699 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
1700 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
1701 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
1702 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
1703 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
1704 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001705 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
1706 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
1707 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
1708 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301710 hci_cc_rsp(hdev, skb);
1711 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001713 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001714 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001715 case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001716 hci_cc_rsp(hdev, skb);
1717 break;
1718
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001719 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
1720 hci_cc_ssbi_peek_rsp(hdev, skb);
1721 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
1723 hci_cc_sig_threshold_rsp(hdev, skb);
1724 break;
1725
1726 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
1727 hci_cc_station_rsp(hdev, skb);
1728 break;
1729
1730 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
1731 hci_cc_prg_srv_rsp(hdev, skb);
1732 break;
1733
1734 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
1735 hci_cc_rd_txt_rsp(hdev, skb);
1736 break;
1737
1738 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
1739 hci_cc_af_list_rsp(hdev, skb);
1740 break;
1741
1742 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301743 hci_cc_riva_read_default_rsp(hdev, skb);
1744 break;
1745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001747 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748 break;
1749
1750 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
1751 hci_cc_feature_list_rsp(hdev, skb);
1752 break;
1753
1754 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
1755 hci_cc_dbg_param_rsp(hdev, skb);
1756 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07001757 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_SET_TRANS_CONF_REQ):
1758 hci_cc_fm_trans_set_conf_rsp(hdev, skb);
1759 break;
1760
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301761 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
1762 hci_cc_rds_grp_cntrs_rsp(hdev, skb);
1763 break;
1764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 default:
1766 FMDERR("%s opcode 0x%x", hdev->name, opcode);
1767 break;
1768 }
1769
1770}
1771
1772static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
1773 struct sk_buff *skb)
1774{
1775 struct hci_ev_cmd_status *ev = (void *) skb->data;
1776 radio_hci_status_complete(hdev, ev->status);
1777}
1778
1779static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
1780 struct sk_buff *skb)
1781{
1782 int i;
1783 int len;
1784
1785 struct iris_device *radio = video_get_drvdata(video_get_dev());
1786
1787 len = sizeof(struct hci_fm_station_rsp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 memcpy(&radio->fm_st_rsp.station_rsp, skb_pull(skb, len), len);
1789
1790 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
1791
1792 for (i = 0; i < IRIS_BUF_MAX; i++) {
1793 if (i >= IRIS_BUF_RT_RDS)
1794 kfifo_reset(&radio->data_buf[i]);
1795 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 if (radio->fm_st_rsp.station_rsp.rssi)
1797 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1798 else
1799 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1800
1801 if (radio->fm_st_rsp.station_rsp.stereo_prg)
1802 iris_q_event(radio, IRIS_EVT_STEREO);
1803
1804 if (radio->fm_st_rsp.station_rsp.mute_mode)
1805 iris_q_event(radio, IRIS_EVT_MONO);
1806
1807 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
1808 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1809 else
1810 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1811}
1812
1813static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
1814 struct sk_buff *skb)
1815{
1816 struct iris_device *radio = video_get_drvdata(video_get_dev());
1817 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
1818}
1819
1820static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
1821 struct sk_buff *skb)
1822{
1823 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001824 struct hci_ev_srch_list_compl *ev ;
1825 int cnt;
1826 int stn_num;
1827 int rel_freq;
1828 int abs_freq;
1829 int len;
1830
1831 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1832 if (!ev) {
1833 FMDERR("Memory allocation failed");
1834 return ;
1835 }
1836
1837 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
1838 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
1839
1840 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
1841 (cnt < len) && (stn_num < ev->num_stations_found);
1842 cnt += PARAMS_PER_STATION, stn_num++) {
1843 abs_freq = *((int *)&skb->data[cnt]);
1844 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
1845 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
1846
1847 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
1848 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
1849 }
1850
1851 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
1852 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
1853 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
1854 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855}
1856
1857static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
1858 struct sk_buff *skb)
1859{
1860 struct iris_device *radio = video_get_drvdata(video_get_dev());
1861 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
1862}
1863
1864static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
1865 struct sk_buff *skb)
1866{
1867 struct iris_device *radio = video_get_drvdata(video_get_dev());
1868 __u8 st_status = *((__u8 *) skb->data);
1869 if (st_status)
1870 iris_q_event(radio, IRIS_EVT_STEREO);
1871 else
1872 iris_q_event(radio, IRIS_EVT_MONO);
1873}
1874
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001875
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001876static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
1877 struct sk_buff *skb)
1878{
1879 struct iris_device *radio = video_get_drvdata(video_get_dev());
1880 int len;
1881 char *data;
1882
1883 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
1884 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
1885 data = kmalloc(len, GFP_ATOMIC);
1886 if (!data) {
1887 FMDERR("Failed to allocate memory");
1888 return;
1889 }
1890
1891 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
1892 data[1] = skb->data[RDS_PTYPE];
1893 data[2] = skb->data[RDS_PID_LOWER];
1894 data[3] = skb->data[RDS_PID_HIGHER];
1895 data[4] = 0;
1896
1897 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
1898
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001899 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001900
1901 kfree(data);
1902}
1903
1904
1905static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
1906 struct sk_buff *skb)
1907{
1908 struct iris_device *radio = video_get_drvdata(video_get_dev());
1909 int len = 0;
1910 char *data;
1911
1912 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
1913
1914 while (skb->data[len+RDS_OFFSET] != 0x0d)
1915 len++;
1916 len++;
1917
1918 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
1919 if (!data) {
1920 FMDERR("Failed to allocate memory");
1921 return;
1922 }
1923
1924 data[0] = len;
1925 data[1] = skb->data[RDS_PTYPE];
1926 data[2] = skb->data[RDS_PID_LOWER];
1927 data[3] = skb->data[RDS_PID_HIGHER];
1928 data[4] = 0;
1929
1930 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
1931 data[len+RDS_OFFSET] = 0x00;
1932
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001933 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001934
1935 kfree(data);
1936}
1937
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05301938static void hci_ev_af_list(struct radio_hci_dev *hdev,
1939 struct sk_buff *skb)
1940{
1941 struct iris_device *radio = video_get_drvdata(video_get_dev());
1942 struct hci_ev_af_list ev;
1943
1944 ev.tune_freq = *((int *) &skb->data[0]);
1945 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
1946 ev.af_size = skb->data[AF_SIZE_OFFSET];
1947 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
1948 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
1949 iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
1950}
1951
1952static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
1953 struct sk_buff *skb)
1954{
1955 struct iris_device *radio = video_get_drvdata(video_get_dev());
1956 __u8 rds_status = skb->data[0];
1957
1958 if (rds_status)
1959 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1960 else
1961 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1962}
1963
1964static void hci_ev_service_available(struct radio_hci_dev *hdev,
1965 struct sk_buff *skb)
1966{
1967 struct iris_device *radio = video_get_drvdata(video_get_dev());
1968 if (radio->fm_st_rsp.station_rsp.serv_avble)
1969 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1970 else
1971 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1972}
1973
1974static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
1975 struct sk_buff *skb)
1976{
1977 struct iris_device *radio = video_get_drvdata(video_get_dev());
1978 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
1979}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001980
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001981void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
1982{
1983 struct radio_hci_event_hdr *hdr = (void *) skb->data;
1984 __u8 event = hdr->evt;
1985
1986 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
1987
1988 switch (event) {
1989 case HCI_EV_TUNE_STATUS:
1990 hci_ev_tune_status(hdev, skb);
1991 break;
1992 case HCI_EV_SEARCH_PROGRESS:
1993 case HCI_EV_SEARCH_RDS_PROGRESS:
1994 case HCI_EV_SEARCH_LIST_PROGRESS:
1995 hci_ev_search_next(hdev, skb);
1996 break;
1997 case HCI_EV_STEREO_STATUS:
1998 hci_ev_stereo_status(hdev, skb);
1999 break;
2000 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302001 hci_ev_rds_lock_status(hdev, skb);
2002 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002003 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302004 hci_ev_service_available(hdev, skb);
2005 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006 case HCI_EV_RDS_RX_DATA:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002007 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002009 hci_ev_program_service(hdev, skb);
2010 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002012 hci_ev_radio_text(hdev, skb);
2013 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302015 hci_ev_af_list(hdev, skb);
2016 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302018 hci_ev_rds_grp_complete(hdev, skb);
2019 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002020 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2021 break;
2022
2023 case HCI_EV_CMD_COMPLETE:
2024 hci_cmd_complete_event(hdev, skb);
2025 break;
2026
2027 case HCI_EV_CMD_STATUS:
2028 hci_cmd_status_event(hdev, skb);
2029 break;
2030
2031 case HCI_EV_SEARCH_COMPLETE:
2032 case HCI_EV_SEARCH_RDS_COMPLETE:
2033 hci_ev_search_compl(hdev, skb);
2034 break;
2035
2036 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002037 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 break;
2039
2040 default:
2041 break;
2042 }
2043}
2044
2045/*
2046 * fops/IOCTL helper functions
2047 */
2048
2049static int iris_search(struct iris_device *radio, int on, int dir)
2050{
2051 int retval = 0;
2052 enum search_t srch = radio->g_search_mode & SRCH_MODE;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302053 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054
2055 if (on) {
2056 switch (srch) {
2057 case SCAN_FOR_STRONG:
2058 case SCAN_FOR_WEAK:
2059 radio->srch_st_list.srch_list_dir = dir;
2060 radio->srch_st_list.srch_list_mode = srch;
2061 radio->srch_st_list.srch_list_max = 0;
2062 retval = hci_fm_search_station_list(
2063 &radio->srch_st_list, radio->fm_hdev);
2064 break;
2065 case RDS_SEEK_PTY:
2066 case RDS_SCAN_PTY:
2067 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002068 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002069 radio->srch_rds.srch_station.srch_mode = srch;
2070 radio->srch_rds.srch_station.srch_dir = dir;
2071 radio->srch_rds.srch_station.scan_time =
2072 radio->g_scan_time;
2073 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2074 radio->fm_hdev);
2075 break;
2076 default:
2077 radio->srch_st.srch_mode = srch;
2078 radio->srch_st.scan_time = radio->g_scan_time;
2079 radio->srch_st.srch_dir = dir;
2080 retval = hci_fm_search_stations(
2081 &radio->srch_st, radio->fm_hdev);
2082 break;
2083 }
2084
2085 } else {
2086 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2087 }
2088
2089 return retval;
2090}
2091
Ankur Nandwanid928d542011-08-11 13:15:41 -07002092static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093{
2094 int retval;
2095 radio->region = req_region;
2096
2097 switch (radio->region) {
2098 case IRIS_REGION_US:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002099 radio->recv_conf.band_low_limit =
2100 REGION_US_EU_BAND_LOW;
2101 radio->recv_conf.band_high_limit =
2102 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 break;
2104 case IRIS_REGION_EU:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002105 radio->recv_conf.band_low_limit =
2106 REGION_US_EU_BAND_LOW;
2107 radio->recv_conf.band_high_limit =
2108 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002109 break;
2110 case IRIS_REGION_JAPAN:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002111 radio->recv_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002112 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302113 radio->recv_conf.band_high_limit =
2114 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002115 break;
2116 case IRIS_REGION_JAPAN_WIDE:
2117 radio->recv_conf.band_low_limit =
2118 REGION_JAPAN_WIDE_BAND_LOW;
2119 radio->recv_conf.band_high_limit =
2120 REGION_JAPAN_WIDE_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121 break;
2122 default:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002123 /* The user specifies the value.
2124 So nothing needs to be done */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002125 break;
2126 }
2127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 retval = hci_set_fm_recv_conf(
2129 &radio->recv_conf,
2130 radio->fm_hdev);
2131
2132 return retval;
2133}
2134
Ankur Nandwanid928d542011-08-11 13:15:41 -07002135
2136static int iris_trans_set_region(struct iris_device *radio, int req_region)
2137{
2138 int retval;
2139 radio->region = req_region;
2140
2141 switch (radio->region) {
2142 case IRIS_REGION_US:
2143 radio->trans_conf.band_low_limit =
2144 REGION_US_EU_BAND_LOW;
2145 radio->trans_conf.band_high_limit =
2146 REGION_US_EU_BAND_HIGH;
2147 break;
2148 case IRIS_REGION_EU:
2149 radio->trans_conf.band_low_limit =
2150 REGION_US_EU_BAND_LOW;
2151 radio->trans_conf.band_high_limit =
2152 REGION_US_EU_BAND_HIGH;
2153 break;
2154 case IRIS_REGION_JAPAN:
2155 radio->trans_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002156 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302157 radio->trans_conf.band_high_limit =
2158 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002159 break;
2160 case IRIS_REGION_JAPAN_WIDE:
2161 radio->recv_conf.band_low_limit =
2162 REGION_JAPAN_WIDE_BAND_LOW;
2163 radio->recv_conf.band_high_limit =
2164 REGION_JAPAN_WIDE_BAND_HIGH;
2165 default:
2166 break;
2167 }
2168
2169 retval = hci_set_fm_trans_conf(
2170 &radio->trans_conf,
2171 radio->fm_hdev);
2172 return retval;
2173}
2174
2175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002176static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2177{
2178
2179 int retval;
2180 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2181 if (retval < 0)
2182 FMDERR("Error while setting the frequency : %d\n", retval);
2183 return retval;
2184}
2185
2186
2187static int iris_vidioc_queryctrl(struct file *file, void *priv,
2188 struct v4l2_queryctrl *qc)
2189{
2190 unsigned char i;
2191 int retval = -EINVAL;
2192
2193 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2194 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2195 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2196 retval = 0;
2197 break;
2198 }
2199 }
2200
2201 return retval;
2202}
2203
2204static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2205 struct v4l2_control *ctrl)
2206{
2207 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2208 int retval = 0;
2209
2210 switch (ctrl->id) {
2211 case V4L2_CID_AUDIO_VOLUME:
2212 break;
2213 case V4L2_CID_AUDIO_MUTE:
2214 ctrl->value = radio->mute_mode.hard_mute;
2215 break;
2216 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2217 ctrl->value = radio->g_search_mode;
2218 break;
2219 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2220 ctrl->value = radio->g_scan_time;
2221 break;
2222 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302223 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002224 break;
2225 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302226 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227 break;
2228 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2229 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2230 if (retval < 0)
2231 return retval;
2232 ctrl->value = radio->st_dbg_param.io_verc;
2233 break;
2234 case V4L2_CID_PRIVATE_IRIS_INTDET:
2235 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2236 if (retval < 0)
2237 return retval;
2238 ctrl->value = radio->st_dbg_param.in_det_out;
2239 break;
2240 case V4L2_CID_PRIVATE_IRIS_REGION:
2241 ctrl->value = radio->region;
2242 break;
2243 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2244 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
2245 break;
2246 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302247 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 break;
2249 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302250 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251 break;
2252 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302253 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 break;
2255 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002256 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002258 } else if (radio->mode == FM_TRANS) {
2259 ctrl->value = radio->trans_conf.emphasis;
2260 } else {
2261 FMDERR("Error in radio mode"
2262 " %d\n", retval);
2263 return -EINVAL;
2264 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265 break;
2266 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002267 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002269 } else if (radio->mode == FM_TRANS) {
2270 ctrl->value = radio->trans_conf.rds_std;
2271 } else {
2272 FMDERR("Error in radio mode"
2273 " %d\n", retval);
2274 return -EINVAL;
2275 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 break;
2277 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002278 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002280 } else {
2281 FMDERR("Error in radio mode"
2282 " %d\n", retval);
2283 return -EINVAL;
2284 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002285 break;
2286 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002287 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002288 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002289 } else {
2290 FMDERR("Error in radio mode"
2291 " %d\n", retval);
2292 return -EINVAL;
2293 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 break;
2295 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2296 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2297 break;
2298 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002299 case V4L2_CID_PRIVATE_IRIS_PSALL:
2300 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002301 break;
2302 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2303 ctrl->value = radio->rds_grp.rds_buf_size;
2304 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
2306 break;
2307 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2308 ctrl->value = radio->g_antenna;
2309 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002310 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2311 ctrl->value = radio->mute_mode.soft_mute;
2312 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 default:
2314 retval = -EINVAL;
2315 }
2316 if (retval < 0)
2317 FMDERR("get control failed with %d, id: %d\n",
2318 retval, ctrl->id);
2319 return retval;
2320}
2321
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302322static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
2323 struct v4l2_ext_controls *ctrl)
2324{
2325 int retval = 0;
2326 char *data = NULL;
2327 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2328 struct hci_fm_def_data_rd_req default_data_rd;
2329
2330 switch ((ctrl->controls[0]).id) {
2331 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
2332 data = (ctrl->controls[0]).string;
2333 memset(&default_data_rd, 0, sizeof(default_data_rd));
2334 if (copy_from_user(&default_data_rd.mode, data,
2335 sizeof(default_data_rd)))
2336 return -EFAULT;
2337 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
2338 break;
2339 default:
2340 retval = -EINVAL;
2341 }
2342
2343 return retval;
2344}
2345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2347 struct v4l2_ext_controls *ctrl)
2348{
Ankur Nandwanid928d542011-08-11 13:15:41 -07002349 int retval = 0;
2350 int bytes_to_copy;
2351 struct hci_fm_tx_ps tx_ps;
2352 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302353 struct hci_fm_def_data_wr_req default_data;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002354
2355 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2356 char *data = NULL;
2357
2358 switch ((ctrl->controls[0]).id) {
2359 case V4L2_CID_RDS_TX_PS_NAME:
2360 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2361 /*Pass a sample PS string */
2362
2363 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
2364 bytes_to_copy = min((int)(ctrl->controls[0]).size,
2365 MAX_PS_LENGTH);
2366 data = (ctrl->controls[0]).string;
2367
2368 if (copy_from_user(tx_ps.ps_data,
2369 data, bytes_to_copy))
2370 return -EFAULT;
2371 tx_ps.ps_control = 0x01;
2372 tx_ps.pi = radio->pi;
2373 tx_ps.pty = radio->pty;
2374 tx_ps.ps_repeatcount = radio->ps_repeatcount;
2375 tx_ps.ps_len = bytes_to_copy;
2376
2377 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2378 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
2379 break;
2380 case V4L2_CID_RDS_TX_RADIO_TEXT:
2381 bytes_to_copy =
2382 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2383 data = (ctrl->controls[0]).string;
2384
2385 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
2386
2387 if (copy_from_user(tx_rt.rt_data,
2388 data, bytes_to_copy))
2389 return -EFAULT;
2390
2391 tx_rt.rt_control = 0x01;
2392 tx_rt.pi = radio->pi;
2393 tx_rt.pty = radio->pty;
2394 tx_rt.ps_len = bytes_to_copy;
2395
2396 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2397 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
2398 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302399 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
2400 data = (ctrl->controls[0]).string;
2401 memset(&default_data, 0, sizeof(default_data));
2402 if (copy_from_user(&default_data, data, sizeof(default_data)))
2403 return -EFAULT;
2404 retval = hci_def_data_write(&default_data, radio->fm_hdev);
2405 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002406 default:
2407 FMDBG("Shouldn't reach here\n");
2408 retval = -1;
2409 }
2410 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002411}
2412
2413static int iris_vidioc_s_ctrl(struct file *file, void *priv,
2414 struct v4l2_control *ctrl)
2415{
2416 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2417 int retval = 0;
2418 unsigned int rds_grps_proc = 0;
2419 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002420 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302421 struct hci_fm_tx_ps tx_ps = {0};
2422 struct hci_fm_tx_rt tx_rt = {0};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002423
2424 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302425 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002426 radio->tone_freq = ctrl->value;
2427 retval = radio_hci_request(radio->fm_hdev,
2428 hci_fm_tone_generator, arg,
2429 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
2430 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002431 case V4L2_CID_AUDIO_VOLUME:
2432 break;
2433 case V4L2_CID_AUDIO_MUTE:
2434 radio->mute_mode.hard_mute = ctrl->value;
2435 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
2436 retval = hci_set_fm_mute_mode(
2437 &radio->mute_mode,
2438 radio->fm_hdev);
2439 if (retval < 0)
2440 FMDERR("Error while set FM hard mute"" %d\n",
2441 retval);
2442 break;
2443 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2444 radio->g_search_mode = ctrl->value;
2445 break;
2446 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2447 radio->g_scan_time = ctrl->value;
2448 break;
2449 case V4L2_CID_PRIVATE_IRIS_SRCHON:
2450 iris_search(radio, ctrl->value, SRCH_DIR_UP);
2451 break;
2452 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002453 switch (ctrl->value) {
2454 case FM_RECV:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2456 radio->fm_hdev);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002457
2458 radio->mode = FM_RECV;
2459
2460 if (retval < 0)
2461 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002462 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002463 radio->mute_mode.soft_mute = CTRL_ON;
2464 retval = hci_set_fm_mute_mode(
2465 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 radio->fm_hdev);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002467 if (retval < 0)
2468 FMDERR("Failed to enable Smute\n");
2469 radio->stereo_mode.stereo_mode = CTRL_OFF;
2470 radio->stereo_mode.sig_blend = CTRL_ON;
2471 radio->stereo_mode.intf_blend = CTRL_ON;
2472 radio->stereo_mode.most_switch = CTRL_ON;
2473 retval = hci_set_fm_stereo_mode(
2474 &radio->stereo_mode,
2475 radio->fm_hdev);
2476 if (retval < 0)
2477 FMDERR("Failed to set stereo mode\n");
Srinivasa Rao Uppalaf0d13742011-09-08 10:13:13 +05302478 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2479 radio->fm_hdev);
2480 if (retval < 0)
2481 FMDERR("Failed to get the Recv Config\n");
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002482 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002483 case FM_TRANS:
2484 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
2485 radio->fm_hdev);
2486 radio->mode = FM_TRANS;
2487
2488 if (retval < 0)
2489 FMDERR("Error while enabling TRANS FM"
2490 " %d\n", retval);
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002491 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002492 case FM_OFF:
2493 switch (radio->mode) {
2494 case FM_RECV:
2495 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2496 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002497 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002498 FMDERR("Err on disable recv FM"
2499 " %d\n", retval);
2500 break;
2501 case FM_TRANS:
2502 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
2503 radio->fm_hdev);
2504
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002505 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002506 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002507 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002508 break;
2509 default:
2510 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002511 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302512 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002513 default:
2514 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515 }
2516 break;
2517 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002518 if (radio->mode == FM_RECV) {
2519 retval = iris_recv_set_region(radio, ctrl->value);
2520 } else {
2521 if (radio->mode == FM_TRANS)
2522 retval = iris_trans_set_region(radio,
2523 ctrl->value);
2524 else
2525 retval = -EINVAL;
2526 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002527 break;
2528 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2529 temp_val = ctrl->value;
2530 retval = hci_fm_set_signal_threshold(
2531 &temp_val,
2532 radio->fm_hdev);
2533 if (retval < 0) {
2534 FMDERR("Error while setting signal threshold\n");
2535 break;
2536 }
2537 break;
2538 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
2539 radio->srch_rds.srch_pty = ctrl->value;
2540 radio->srch_st_list.srch_pty = ctrl->value;
2541 break;
2542 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
2543 radio->srch_rds.srch_pi = ctrl->value;
2544 break;
2545 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
2546 break;
2547 case V4L2_CID_PRIVATE_IRIS_SPACING:
2548 radio->recv_conf.ch_spacing = ctrl->value;
2549 break;
2550 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002551 switch (radio->mode) {
2552 case FM_RECV:
2553 radio->recv_conf.emphasis = ctrl->value;
2554 retval = hci_set_fm_recv_conf(
2555 &radio->recv_conf,
2556 radio->fm_hdev);
2557 if (retval < 0)
2558 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002559 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002560 case FM_TRANS:
2561 radio->trans_conf.emphasis = ctrl->value;
2562 retval = hci_set_fm_trans_conf(
2563 &radio->trans_conf,
2564 radio->fm_hdev);
2565 if (retval < 0)
2566 FMDERR("Error in setting emphasis");
2567 break;
2568 default:
2569 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002570 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571 break;
2572 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002573 switch (radio->mode) {
2574 case FM_RECV:
2575 radio->recv_conf.rds_std = ctrl->value;
2576 retval = hci_set_fm_recv_conf(
2577 &radio->recv_conf,
2578 radio->fm_hdev);
2579 if (retval < 0)
2580 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002581 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002582 case FM_TRANS:
2583 radio->trans_conf.rds_std = ctrl->value;
2584 retval = hci_set_fm_trans_conf(
2585 &radio->trans_conf,
2586 radio->fm_hdev);
2587 if (retval < 0)
2588 FMDERR("Error in rds_Std");
2589 break;
2590 default:
2591 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002592 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593 break;
2594 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002595 switch (radio->mode) {
2596 case FM_RECV:
2597 radio->recv_conf.rds_std = ctrl->value;
2598 retval = hci_set_fm_recv_conf(
2599 &radio->recv_conf,
2600 radio->fm_hdev);
2601 if (retval < 0)
2602 FMDERR("Error in rds_std");
2603 break;
2604 case FM_TRANS:
2605 radio->trans_conf.rds_std = ctrl->value;
2606 retval = hci_set_fm_trans_conf(
2607 &radio->trans_conf,
2608 radio->fm_hdev);
2609 if (retval < 0)
2610 FMDERR("Error in rds_Std");
2611 break;
2612 default:
2613 retval = -EINVAL;
2614 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002615 break;
2616 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2617 radio->rds_grp.rds_grp_enable_mask = ctrl->value;
2618 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
2619 break;
2620 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
2621 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002622 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002624 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625 radio->fm_hdev);
2626 break;
2627 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2628 radio->rds_grp.rds_buf_size = ctrl->value;
2629 break;
2630 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002631 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
2632 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2633 retval = hci_fm_rds_grps_process(
2634 &radio->g_rds_grp_proc_ps,
2635 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002636 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302637 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
2638 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_OFFSET);
2639 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2640 retval = hci_fm_rds_grps_process(
2641 &radio->g_rds_grp_proc_ps,
2642 radio->fm_hdev);
2643 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
2645 break;
2646 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2647 temp_val = ctrl->value;
2648 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
2649 break;
2650 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002651 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 break;
2653 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002654 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655 break;
2656 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302657 tx_ps.ps_control = 0x00;
2658 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2659 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 break;
2661 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302662 tx_rt.rt_control = 0x00;
2663 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2664 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002665 break;
2666 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002667 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002668 break;
2669 case V4L2_CID_TUNE_POWER_LEVEL:
2670 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002671 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2672 radio->mute_mode.soft_mute = ctrl->value;
2673 retval = hci_set_fm_mute_mode(
2674 &radio->mute_mode,
2675 radio->fm_hdev);
2676 if (retval < 0)
2677 FMDERR("Error while setting FM soft mute"" %d\n",
2678 retval);
2679 break;
2680 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
2681 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
2682 break;
2683 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
2684 radio->riva_data_req.cmd_params.length = ctrl->value;
2685 break;
2686 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
2687 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
2688 radio->riva_data_req.cmd_params.length);
2689 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
2690 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
2691 break;
2692 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
2693 radio->ssbi_data_accs.start_addr = ctrl->value;
2694 break;
2695 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
2696 radio->ssbi_data_accs.data = ctrl->value;
2697 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
2698 radio->fm_hdev);
2699 break;
2700 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
2701 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
2702 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
2703 radio->fm_hdev);
2704 break;
2705 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
2706 radio->ssbi_peek_reg.start_address = ctrl->value;
2707 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
2708 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302709 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
2710 temp_val = ctrl->value;
2711 hci_read_grp_counters(&temp_val, radio->fm_hdev);
2712 break;
2713 case V4L2_CID_PRIVATE_IRIS_HLSI:
2714 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2715 radio->fm_hdev);
2716 if (retval)
2717 break;
2718 radio->recv_conf.hlsi = ctrl->value;
2719 retval = hci_set_fm_recv_conf(
2720 &radio->recv_conf,
2721 radio->fm_hdev);
2722 break;
2723 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
2724 temp_val = ctrl->value;
2725 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
2726 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728 default:
2729 retval = -EINVAL;
2730 }
2731 return retval;
2732}
2733
2734static int iris_vidioc_g_tuner(struct file *file, void *priv,
2735 struct v4l2_tuner *tuner)
2736{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002737 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002738 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002739 if (tuner->index > 0)
2740 return -EINVAL;
2741
2742 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
2743 if (retval < 0)
2744 return retval;
2745
2746 tuner->type = V4L2_TUNER_RADIO;
2747 tuner->rangelow = radio->recv_conf.band_low_limit * TUNE_PARAM;
2748 tuner->rangehigh = radio->recv_conf.band_high_limit * TUNE_PARAM;
2749 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
2750 tuner->capability = V4L2_TUNER_CAP_LOW;
2751 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
2752 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
2753 tuner->afc = 0;
2754
2755 return 0;
2756}
2757
2758static int iris_vidioc_s_tuner(struct file *file, void *priv,
2759 struct v4l2_tuner *tuner)
2760{
2761 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07002762 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002763 if (tuner->index > 0)
2764 return -EINVAL;
2765
Ankur Nandwanid928d542011-08-11 13:15:41 -07002766 if (radio->mode == FM_RECV) {
2767 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
2768 radio->recv_conf.band_high_limit =
2769 tuner->rangehigh / TUNE_PARAM;
2770 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
2771 radio->stereo_mode.stereo_mode = 0x01;
2772 retval = hci_set_fm_stereo_mode(
2773 &radio->stereo_mode,
2774 radio->fm_hdev);
2775 } else {
2776 radio->stereo_mode.stereo_mode = 0x00;
2777 retval = hci_set_fm_stereo_mode(
2778 &radio->stereo_mode,
2779 radio->fm_hdev);
2780 }
2781 if (retval < 0)
2782 FMDERR(": set tuner failed with %d\n", retval);
2783 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002784 } else {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002785 if (radio->mode == FM_TRANS) {
2786 radio->trans_conf.band_low_limit =
2787 tuner->rangelow / TUNE_PARAM;
2788 radio->trans_conf.band_high_limit =
2789 tuner->rangehigh / TUNE_PARAM;
2790 } else {
2791 return -EINVAL;
2792 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002793 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002795 return retval;
2796}
2797
2798static int iris_vidioc_g_frequency(struct file *file, void *priv,
2799 struct v4l2_frequency *freq)
2800{
2801 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2802 int retval;
2803
2804 freq->type = V4L2_TUNER_RADIO;
2805 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
2806 if (retval < 0)
2807 FMDERR("get frequency failed %d\n", retval);
2808 else
2809 freq->frequency =
2810 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
2811 return retval;
2812}
2813
2814static int iris_vidioc_s_frequency(struct file *file, void *priv,
2815 struct v4l2_frequency *freq)
2816{
2817 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2818 int retval = -1;
2819 freq->frequency = freq->frequency / TUNE_PARAM;
2820
2821 if (freq->type != V4L2_TUNER_RADIO)
2822 return -EINVAL;
2823
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002824 /* We turn off RDS prior to tuning to a new station.
2825 because of a bug in SoC which prevents tuning
2826 during RDS transmission.
2827 */
2828 if (radio->mode == FM_TRANS
2829 && (radio->trans_conf.rds_std == 0 ||
2830 radio->trans_conf.rds_std == 1)) {
2831 radio->prev_trans_rds = radio->trans_conf.rds_std;
2832 radio->trans_conf.rds_std = 2;
2833 hci_set_fm_trans_conf(&radio->trans_conf,
2834 radio->fm_hdev);
2835 }
2836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002837 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002838
2839 if (radio->mode == FM_TRANS
2840 && radio->trans_conf.rds_std == 2
2841 && (radio->prev_trans_rds == 1
2842 || radio->prev_trans_rds == 0)) {
2843 radio->trans_conf.rds_std = radio->prev_trans_rds;
2844 hci_set_fm_trans_conf(&radio->trans_conf,
2845 radio->fm_hdev);
2846 }
2847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002848 if (retval < 0)
2849 FMDERR(" set frequency failed with %d\n", retval);
2850 return retval;
2851}
2852
2853static int iris_vidioc_dqbuf(struct file *file, void *priv,
2854 struct v4l2_buffer *buffer)
2855{
2856 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2857 enum iris_buf_t buf_type = buffer->index;
2858 struct kfifo *data_fifo;
2859 unsigned char *buf = (unsigned char *)buffer->m.userptr;
2860 unsigned int len = buffer->length;
2861 if (!access_ok(VERIFY_WRITE, buf, len))
2862 return -EFAULT;
2863 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
2864 data_fifo = &radio->data_buf[buf_type];
2865 if (buf_type == IRIS_BUF_EVENTS)
2866 if (wait_event_interruptible(radio->event_queue,
2867 kfifo_len(data_fifo)) < 0)
2868 return -EINTR;
2869 } else {
2870 FMDERR("invalid buffer type\n");
2871 return -EINVAL;
2872 }
2873 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
2874 &radio->buf_lock[buf_type]);
2875
2876 return 0;
2877}
2878
2879static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
2880 struct v4l2_format *f)
2881{
2882 return 0;
2883
2884}
2885
2886static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
2887 struct v4l2_hw_freq_seek *seek)
2888{
2889 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2890 int dir;
2891 if (seek->seek_upward)
2892 dir = SRCH_DIR_UP;
2893 else
2894 dir = SRCH_DIR_DOWN;
2895 return iris_search(radio, CTRL_ON, dir);
2896}
2897
2898static int iris_vidioc_querycap(struct file *file, void *priv,
2899 struct v4l2_capability *capability)
2900{
2901 struct iris_device *radio;
2902 radio = video_get_drvdata(video_devdata(file));
2903 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
2904 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
2905 radio->g_cap = capability;
2906 return 0;
2907}
2908
2909
2910static const struct v4l2_ioctl_ops iris_ioctl_ops = {
2911 .vidioc_querycap = iris_vidioc_querycap,
2912 .vidioc_queryctrl = iris_vidioc_queryctrl,
2913 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
2914 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
2915 .vidioc_g_tuner = iris_vidioc_g_tuner,
2916 .vidioc_s_tuner = iris_vidioc_s_tuner,
2917 .vidioc_g_frequency = iris_vidioc_g_frequency,
2918 .vidioc_s_frequency = iris_vidioc_s_frequency,
2919 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
2920 .vidioc_dqbuf = iris_vidioc_dqbuf,
2921 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
2922 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302923 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002924};
2925
2926static const struct v4l2_file_operations iris_fops = {
2927 .owner = THIS_MODULE,
2928 .unlocked_ioctl = video_ioctl2,
2929};
2930
2931static struct video_device iris_viddev_template = {
2932 .fops = &iris_fops,
2933 .ioctl_ops = &iris_ioctl_ops,
2934 .name = DRIVER_NAME,
2935 .release = video_device_release,
2936};
2937
2938static struct video_device *video_get_dev(void)
2939{
2940 return priv_videodev;
2941}
2942
2943static int __init iris_probe(struct platform_device *pdev)
2944{
2945 struct iris_device *radio;
2946 int retval;
2947 int radio_nr = -1;
2948 int i;
2949
2950 if (!pdev) {
2951 FMDERR(": pdev is null\n");
2952 return -ENOMEM;
2953 }
2954
2955 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
2956 if (!radio) {
2957 FMDERR(": Could not allocate radio device\n");
2958 return -ENOMEM;
2959 }
2960
2961 radio->dev = &pdev->dev;
2962 platform_set_drvdata(pdev, radio);
2963
2964 radio->videodev = video_device_alloc();
2965 if (!radio->videodev) {
2966 FMDERR(": Could not allocate V4L device\n");
2967 kfree(radio);
2968 return -ENOMEM;
2969 }
2970
2971 memcpy(radio->videodev, &iris_viddev_template,
2972 sizeof(iris_viddev_template));
2973
2974 for (i = 0; i < IRIS_BUF_MAX; i++) {
2975 int kfifo_alloc_rc = 0;
2976 spin_lock_init(&radio->buf_lock[i]);
2977
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07002978 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
2980 rds_buf*3, GFP_KERNEL);
2981 else
2982 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
2983 STD_BUF_SIZE, GFP_KERNEL);
2984
2985 if (kfifo_alloc_rc != 0) {
2986 FMDERR("failed allocating buffers %d\n",
2987 kfifo_alloc_rc);
2988 for (; i > -1; i--) {
2989 kfifo_free(&radio->data_buf[i]);
2990 kfree(radio);
2991 return -ENOMEM;
2992 }
2993 }
2994 }
2995
2996 mutex_init(&radio->lock);
2997 init_completion(&radio->sync_xfr_start);
2998 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002999 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000 init_waitqueue_head(&radio->event_queue);
3001 init_waitqueue_head(&radio->read_queue);
3002
3003 video_set_drvdata(radio->videodev, radio);
3004
3005 if (NULL == video_get_drvdata(radio->videodev))
3006 FMDERR(": video_get_drvdata failed\n");
3007
3008 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
3009 radio_nr);
3010 if (retval) {
3011 FMDERR(": Could not register video device\n");
3012 video_device_release(radio->videodev);
3013 for (; i > -1; i--)
3014 kfifo_free(&radio->data_buf[i]);
3015 kfree(radio);
3016 return retval;
3017 } else {
3018 priv_videodev = kzalloc(sizeof(struct video_device),
3019 GFP_KERNEL);
3020 memcpy(priv_videodev, radio->videodev,
3021 sizeof(struct video_device));
3022 }
3023 return 0;
3024}
3025
3026
3027static int __devexit iris_remove(struct platform_device *pdev)
3028{
3029 int i;
3030 struct iris_device *radio = platform_get_drvdata(pdev);
3031
3032 video_unregister_device(radio->videodev);
3033
3034 for (i = 0; i < IRIS_BUF_MAX; i++)
3035 kfifo_free(&radio->data_buf[i]);
3036
3037 kfree(radio);
3038
3039 platform_set_drvdata(pdev, NULL);
3040
3041 return 0;
3042}
3043
3044static struct platform_driver iris_driver = {
3045 .driver = {
3046 .owner = THIS_MODULE,
3047 .name = "iris_fm",
3048 },
3049 .remove = __devexit_p(iris_remove),
3050};
3051
3052static int __init iris_radio_init(void)
3053{
3054 return platform_driver_probe(&iris_driver, iris_probe);
3055}
3056module_init(iris_radio_init);
3057
3058static void __exit iris_radio_exit(void)
3059{
3060 platform_driver_unregister(&iris_driver);
3061}
3062module_exit(iris_radio_exit);
3063
3064MODULE_LICENSE("GPL v2");
3065MODULE_AUTHOR(DRIVER_AUTHOR);
3066MODULE_DESCRIPTION(DRIVER_DESC);