blob: 8a65df4fd2058122fc85c2028fc9f9f5d0dd59f2 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define DRIVER_AUTHOR "Archana Ramchandran <archanar@codeaurora.org>"
14#define DRIVER_NAME "radio-iris"
15#define DRIVER_CARD "Qualcomm FM Radio Transceiver"
16#define DRIVER_DESC "Driver for Qualcomm FM Radio Transceiver "
17
18#include <linux/version.h>
19#include <linux/init.h>
20#include <linux/delay.h>
21#include <linux/uaccess.h>
22#include <linux/kfifo.h>
23#include <linux/param.h>
24#include <linux/interrupt.h>
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/version.h>
28#include <linux/videodev2.h>
29#include <linux/mutex.h>
30#include <linux/unistd.h>
31#include <linux/atomic.h>
32#include <linux/platform_device.h>
33#include <linux/workqueue.h>
34#include <linux/slab.h>
35#include <media/v4l2-common.h>
36#include <media/v4l2-ioctl.h>
37#include <media/radio-iris.h>
38#include <asm/unaligned.h>
39
40static unsigned int rds_buf = 100;
41module_param(rds_buf, uint, 0);
42MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
43
44static void radio_hci_cmd_task(unsigned long arg);
45static void radio_hci_rx_task(unsigned long arg);
46static struct video_device *video_get_dev(void);
47static DEFINE_RWLOCK(hci_task_lock);
48
49struct iris_device {
50 struct device *dev;
51 struct kfifo data_buf[IRIS_BUF_MAX];
52
53 int pending_xfrs[IRIS_XFR_MAX];
54 int xfr_bytes_left;
55 int xfr_in_progress;
56 struct completion sync_xfr_start;
57 int tune_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -070058 unsigned int mode;
59
60 __u16 pi;
61 __u8 pty;
62 __u8 ps_repeatcount;
Ankur Nandwani8f972e52011-08-24 11:48:32 -070063 __u8 prev_trans_rds;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064
65 struct video_device *videodev;
66
67 struct mutex lock;
68 spinlock_t buf_lock[IRIS_BUF_MAX];
69 wait_queue_head_t event_queue;
70 wait_queue_head_t read_queue;
71
72 struct radio_hci_dev *fm_hdev;
73
74 struct v4l2_capability *g_cap;
75 struct v4l2_control *g_ctl;
76
77 struct hci_fm_mute_mode_req mute_mode;
78 struct hci_fm_stereo_mode_req stereo_mode;
79 struct hci_fm_station_rsp fm_st_rsp;
80 struct hci_fm_search_station_req srch_st;
81 struct hci_fm_search_rds_station_req srch_rds;
82 struct hci_fm_search_station_list_req srch_st_list;
83 struct hci_fm_recv_conf_req recv_conf;
Ankur Nandwanid928d542011-08-11 13:15:41 -070084 struct hci_fm_trans_conf_req_struct trans_conf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085 struct hci_fm_rds_grp_req rds_grp;
86 unsigned char g_search_mode;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +053087 unsigned char power_mode;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +053088 int search_on;
Ankur Nandwanid928d542011-08-11 13:15:41 -070089 unsigned int tone_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070090 unsigned char g_scan_time;
91 unsigned int g_antenna;
92 unsigned int g_rds_grp_proc_ps;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +053093 unsigned char event_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 enum iris_region_t region;
95 struct hci_fm_dbg_param_rsp st_dbg_param;
96 struct hci_ev_srch_list_compl srch_st_result;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -070097 struct hci_fm_riva_poke riva_data_req;
98 struct hci_fm_ssbi_req ssbi_data_accs;
99 struct hci_fm_ssbi_peek ssbi_peek_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100};
101
102static struct video_device *priv_videodev;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530103static int iris_do_calibration(struct iris_device *radio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700104
105static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
106 {
107 .id = V4L2_CID_AUDIO_VOLUME,
108 .type = V4L2_CTRL_TYPE_INTEGER,
109 .name = "Volume",
110 .minimum = 0,
111 .maximum = 15,
112 .step = 1,
113 .default_value = 15,
114 },
115 {
116 .id = V4L2_CID_AUDIO_BALANCE,
117 .flags = V4L2_CTRL_FLAG_DISABLED,
118 },
119 {
120 .id = V4L2_CID_AUDIO_BASS,
121 .flags = V4L2_CTRL_FLAG_DISABLED,
122 },
123 {
124 .id = V4L2_CID_AUDIO_TREBLE,
125 .flags = V4L2_CTRL_FLAG_DISABLED,
126 },
127 {
128 .id = V4L2_CID_AUDIO_MUTE,
129 .type = V4L2_CTRL_TYPE_BOOLEAN,
130 .name = "Mute",
131 .minimum = 0,
132 .maximum = 1,
133 .step = 1,
134 .default_value = 1,
135 },
136 {
137 .id = V4L2_CID_AUDIO_LOUDNESS,
138 .flags = V4L2_CTRL_FLAG_DISABLED,
139 },
140 {
141 .id = V4L2_CID_PRIVATE_IRIS_SRCHMODE,
142 .type = V4L2_CTRL_TYPE_INTEGER,
143 .name = "Search mode",
144 .minimum = 0,
145 .maximum = 7,
146 .step = 1,
147 .default_value = 0,
148 },
149 {
150 .id = V4L2_CID_PRIVATE_IRIS_SCANDWELL,
151 .type = V4L2_CTRL_TYPE_INTEGER,
152 .name = "Search dwell time",
153 .minimum = 0,
154 .maximum = 7,
155 .step = 1,
156 .default_value = 0,
157 },
158 {
159 .id = V4L2_CID_PRIVATE_IRIS_SRCHON,
160 .type = V4L2_CTRL_TYPE_BOOLEAN,
161 .name = "Search on/off",
162 .minimum = 0,
163 .maximum = 1,
164 .step = 1,
165 .default_value = 1,
166
167 },
168 {
169 .id = V4L2_CID_PRIVATE_IRIS_STATE,
170 .type = V4L2_CTRL_TYPE_INTEGER,
171 .name = "radio 0ff/rx/tx/reset",
172 .minimum = 0,
173 .maximum = 3,
174 .step = 1,
175 .default_value = 1,
176
177 },
178 {
179 .id = V4L2_CID_PRIVATE_IRIS_REGION,
180 .type = V4L2_CTRL_TYPE_INTEGER,
181 .name = "radio standard",
182 .minimum = 0,
183 .maximum = 2,
184 .step = 1,
185 .default_value = 0,
186 },
187 {
188 .id = V4L2_CID_PRIVATE_IRIS_SIGNAL_TH,
189 .type = V4L2_CTRL_TYPE_INTEGER,
190 .name = "Signal Threshold",
191 .minimum = 0x80,
192 .maximum = 0x7F,
193 .step = 1,
194 .default_value = 0,
195 },
196 {
197 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PTY,
198 .type = V4L2_CTRL_TYPE_INTEGER,
199 .name = "Search PTY",
200 .minimum = 0,
201 .maximum = 31,
202 .default_value = 0,
203 },
204 {
205 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PI,
206 .type = V4L2_CTRL_TYPE_INTEGER,
207 .name = "Search PI",
208 .minimum = 0,
209 .maximum = 0xFF,
210 .default_value = 0,
211 },
212 {
213 .id = V4L2_CID_PRIVATE_IRIS_SRCH_CNT,
214 .type = V4L2_CTRL_TYPE_INTEGER,
215 .name = "Preset num",
216 .minimum = 0,
217 .maximum = 12,
218 .default_value = 0,
219 },
220 {
221 .id = V4L2_CID_PRIVATE_IRIS_EMPHASIS,
222 .type = V4L2_CTRL_TYPE_BOOLEAN,
223 .name = "Emphasis",
224 .minimum = 0,
225 .maximum = 1,
226 .default_value = 0,
227 },
228 {
229 .id = V4L2_CID_PRIVATE_IRIS_RDS_STD,
230 .type = V4L2_CTRL_TYPE_BOOLEAN,
231 .name = "RDS standard",
232 .minimum = 0,
233 .maximum = 1,
234 .default_value = 0,
235 },
236 {
237 .id = V4L2_CID_PRIVATE_IRIS_SPACING,
238 .type = V4L2_CTRL_TYPE_INTEGER,
239 .name = "Channel spacing",
240 .minimum = 0,
241 .maximum = 2,
242 .default_value = 0,
243 },
244 {
245 .id = V4L2_CID_PRIVATE_IRIS_RDSON,
246 .type = V4L2_CTRL_TYPE_BOOLEAN,
247 .name = "RDS on/off",
248 .minimum = 0,
249 .maximum = 1,
250 .default_value = 0,
251 },
252 {
253 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK,
254 .type = V4L2_CTRL_TYPE_INTEGER,
255 .name = "RDS group mask",
256 .minimum = 0,
257 .maximum = 0xFFFFFFFF,
258 .default_value = 0,
259 },
260 {
261 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC,
262 .type = V4L2_CTRL_TYPE_INTEGER,
263 .name = "RDS processing",
264 .minimum = 0,
265 .maximum = 0xFF,
266 .default_value = 0,
267 },
268 {
269 .id = V4L2_CID_PRIVATE_IRIS_RDSD_BUF,
270 .type = V4L2_CTRL_TYPE_INTEGER,
271 .name = "RDS data groups to buffer",
272 .minimum = 1,
273 .maximum = 21,
274 .default_value = 0,
275 },
276 {
277 .id = V4L2_CID_PRIVATE_IRIS_PSALL,
278 .type = V4L2_CTRL_TYPE_BOOLEAN,
279 .name = "pass all ps strings",
280 .minimum = 0,
281 .maximum = 1,
282 .default_value = 0,
283 },
284 {
285 .id = V4L2_CID_PRIVATE_IRIS_LP_MODE,
286 .type = V4L2_CTRL_TYPE_BOOLEAN,
287 .name = "Low power mode",
288 .minimum = 0,
289 .maximum = 1,
290 .default_value = 0,
291 },
292 {
293 .id = V4L2_CID_PRIVATE_IRIS_ANTENNA,
294 .type = V4L2_CTRL_TYPE_BOOLEAN,
295 .name = "headset/internal",
296 .minimum = 0,
297 .maximum = 1,
298 .default_value = 0,
299 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 {
301 .id = V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT,
302 .type = V4L2_CTRL_TYPE_INTEGER,
303 .name = "Set PS REPEATCOUNT",
304 .minimum = 0,
305 .maximum = 15,
306 },
307 {
308 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME,
309 .type = V4L2_CTRL_TYPE_BOOLEAN,
310 .name = "Stop PS NAME",
311 .minimum = 0,
312 .maximum = 1,
313 },
314 {
315 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT,
316 .type = V4L2_CTRL_TYPE_BOOLEAN,
317 .name = "Stop RT",
318 .minimum = 0,
319 .maximum = 1,
320 },
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700321 {
322 .id = V4L2_CID_PRIVATE_IRIS_SOFT_MUTE,
323 .type = V4L2_CTRL_TYPE_BOOLEAN,
324 .name = "Soft Mute",
325 .minimum = 0,
326 .maximum = 1,
327 },
328 {
329 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR,
330 .type = V4L2_CTRL_TYPE_BOOLEAN,
331 .name = "Riva addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530332 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700333 .maximum = 0x31E0004,
334 },
335 {
336 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN,
337 .type = V4L2_CTRL_TYPE_INTEGER,
338 .name = "Data len",
339 .minimum = 0,
340 .maximum = 0xFF,
341 },
342 {
343 .id = V4L2_CID_PRIVATE_IRIS_RIVA_PEEK,
344 .type = V4L2_CTRL_TYPE_BOOLEAN,
345 .name = "Riva peek",
346 .minimum = 0,
347 .maximum = 1,
348 },
349 {
350 .id = V4L2_CID_PRIVATE_IRIS_RIVA_POKE,
351 .type = V4L2_CTRL_TYPE_INTEGER,
352 .name = "Riva poke",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530353 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700354 .maximum = 0x31E0004,
355 },
356 {
357 .id = V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR,
358 .type = V4L2_CTRL_TYPE_INTEGER,
359 .name = "Ssbi addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530360 .minimum = 0x280,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700361 .maximum = 0x37F,
362 },
363 {
364 .id = V4L2_CID_PRIVATE_IRIS_SSBI_PEEK,
365 .type = V4L2_CTRL_TYPE_INTEGER,
366 .name = "Ssbi peek",
367 .minimum = 0,
368 .maximum = 0x37F,
369 },
370 {
371 .id = V4L2_CID_PRIVATE_IRIS_SSBI_POKE,
372 .type = V4L2_CTRL_TYPE_INTEGER,
373 .name = "ssbi poke",
374 .minimum = 0x01,
375 .maximum = 0xFF,
376 },
377 {
378 .id = V4L2_CID_PRIVATE_IRIS_HLSI,
379 .type = V4L2_CTRL_TYPE_INTEGER,
380 .name = "set hlsi",
381 .minimum = 0,
382 .maximum = 2,
383 },
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530384 {
385 .id = V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS,
386 .type = V4L2_CTRL_TYPE_BOOLEAN,
387 .name = "RDS grp",
388 .minimum = 0,
389 .maximum = 1,
390 },
391 {
392 .id = V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER,
393 .type = V4L2_CTRL_TYPE_INTEGER,
394 .name = "Notch filter",
395 .minimum = 0,
396 .maximum = 2,
397 },
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530398 {
399 .id = V4L2_CID_PRIVATE_IRIS_READ_DEFAULT,
400 .type = V4L2_CTRL_TYPE_INTEGER,
401 .name = "Read default",
402 },
403 {
404 .id = V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT,
405 .type = V4L2_CTRL_TYPE_INTEGER,
406 .name = "Write default",
407 },
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530408 {
409 .id = V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION,
410 .type = V4L2_CTRL_TYPE_BOOLEAN,
411 .name = "SET Calibration",
412 .minimum = 0,
413 .maximum = 1,
414 },
415 {
416 .id = V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION,
417 .type = V4L2_CTRL_TYPE_BOOLEAN,
418 .name = "SET Calibration",
419 .minimum = 0,
420 .maximum = 1,
421 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422};
423
424static void iris_q_event(struct iris_device *radio,
425 enum iris_evt_t event)
426{
427 struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
428 unsigned char evt = event;
429 if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
430 wake_up_interruptible(&radio->event_queue);
431}
432
433static int hci_send_frame(struct sk_buff *skb)
434{
435 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
436
437 if (!hdev) {
438 kfree_skb(skb);
439 return -ENODEV;
440 }
441
442 __net_timestamp(skb);
443
444 skb_orphan(skb);
445 return hdev->send(skb);
446}
447
448static void radio_hci_cmd_task(unsigned long arg)
449{
450 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
451 struct sk_buff *skb;
452 if (!(atomic_read(&hdev->cmd_cnt))
453 && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
454 FMDERR("%s command tx timeout", hdev->name);
455 atomic_set(&hdev->cmd_cnt, 1);
456 }
457
458 skb = skb_dequeue(&hdev->cmd_q);
459 if (atomic_read(&hdev->cmd_cnt) && skb) {
460 kfree_skb(hdev->sent_cmd);
461 hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
462 if (hdev->sent_cmd) {
463 atomic_dec(&hdev->cmd_cnt);
464 hci_send_frame(skb);
465 hdev->cmd_last_tx = jiffies;
466 } else {
467 skb_queue_head(&hdev->cmd_q, skb);
468 tasklet_schedule(&hdev->cmd_task);
469 }
470 }
471
472}
473
474static void radio_hci_rx_task(unsigned long arg)
475{
476 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
477 struct sk_buff *skb;
478
479 read_lock(&hci_task_lock);
480
481 skb = skb_dequeue(&hdev->rx_q);
482 radio_hci_event_packet(hdev, skb);
483
484 read_unlock(&hci_task_lock);
485}
486
487int radio_hci_register_dev(struct radio_hci_dev *hdev)
488{
489 struct iris_device *radio = video_get_drvdata(video_get_dev());
490 if (!radio) {
491 FMDERR(":radio is null");
492 return -EINVAL;
493 }
494
495 if (!hdev) {
496 FMDERR("hdev is null");
497 return -EINVAL;
498 }
499
500 hdev->flags = 0;
501
502 tasklet_init(&hdev->cmd_task, radio_hci_cmd_task, (unsigned long)
503 hdev);
504 tasklet_init(&hdev->rx_task, radio_hci_rx_task, (unsigned long)
505 hdev);
506
507 init_waitqueue_head(&hdev->req_wait_q);
508
509 skb_queue_head_init(&hdev->rx_q);
510 skb_queue_head_init(&hdev->cmd_q);
511 skb_queue_head_init(&hdev->raw_q);
512
513 if (!radio)
514 FMDERR(":radio is null");
515
516 radio->fm_hdev = hdev;
517
518 return 0;
519}
520EXPORT_SYMBOL(radio_hci_register_dev);
521
522int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
523{
524 struct iris_device *radio = video_get_drvdata(video_get_dev());
525 if (!radio) {
526 FMDERR(":radio is null");
527 return -EINVAL;
528 }
529
530 tasklet_kill(&hdev->rx_task);
531 tasklet_kill(&hdev->cmd_task);
532 skb_queue_purge(&hdev->rx_q);
533 skb_queue_purge(&hdev->cmd_q);
534 skb_queue_purge(&hdev->raw_q);
535 kfree(radio->fm_hdev);
536 kfree(radio->videodev);
537
538 return 0;
539}
540EXPORT_SYMBOL(radio_hci_unregister_dev);
541
542int radio_hci_recv_frame(struct sk_buff *skb)
543{
544 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
545 if (!hdev) {
546 FMDERR("%s hdev is null while receiving frame", hdev->name);
547 kfree_skb(skb);
548 return -ENXIO;
549 }
550
551 __net_timestamp(skb);
552
553 radio_hci_event_packet(hdev, skb);
Srinivasa Rao Uppalacf3a8112011-09-22 21:02:02 +0530554 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 return 0;
556}
557EXPORT_SYMBOL(radio_hci_recv_frame);
558
559int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
560 void *param)
561{
562 int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
563 struct radio_hci_command_hdr *hdr;
564 struct sk_buff *skb;
565 int ret = 0;
566
567 skb = alloc_skb(len, GFP_ATOMIC);
568 if (!skb) {
569 FMDERR("%s no memory for command", hdev->name);
570 return -ENOMEM;
571 }
572
573 hdr = (struct radio_hci_command_hdr *) skb_put(skb,
574 RADIO_HCI_COMMAND_HDR_SIZE);
575 hdr->opcode = cpu_to_le16(opcode);
576 hdr->plen = plen;
577
578 if (plen)
579 memcpy(skb_put(skb, plen), param, plen);
580
581 skb->dev = (void *) hdev;
582
583 ret = hci_send_frame(skb);
584
585 return ret;
586}
587EXPORT_SYMBOL(radio_hci_send_cmd);
588
589static int hci_fm_enable_recv_req(struct radio_hci_dev *hdev,
590 unsigned long param)
591{
592 __u16 opcode = 0;
593
594 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
595 HCI_OCF_FM_ENABLE_RECV_REQ);
596 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
597}
598
Ankur Nandwanid928d542011-08-11 13:15:41 -0700599static int hci_fm_tone_generator(struct radio_hci_dev *hdev,
600 unsigned long param)
601{
602 struct iris_device *radio = video_get_drvdata(video_get_dev());
603 __u16 opcode = 0;
604
605 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
606 HCI_FM_SET_INTERNAL_TONE_GENRATOR);
607 return radio_hci_send_cmd(hdev, opcode,
608 sizeof(radio->tone_freq), &radio->tone_freq);
609}
610
611static int hci_fm_enable_trans_req(struct radio_hci_dev *hdev,
612 unsigned long param)
613{
614 __u16 opcode = 0;
615
616 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
617 HCI_OCF_FM_ENABLE_TRANS_REQ);
618 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
619}
620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621static int hci_fm_disable_recv_req(struct radio_hci_dev *hdev,
622 unsigned long param)
623{
624 __u16 opcode = 0;
625
626 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
627 HCI_OCF_FM_DISABLE_RECV_REQ);
628 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
629}
630
Ankur Nandwanid928d542011-08-11 13:15:41 -0700631static int hci_fm_disable_trans_req(struct radio_hci_dev *hdev,
632 unsigned long param)
633{
634 __u16 opcode = 0;
635
636 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
637 HCI_OCF_FM_DISABLE_TRANS_REQ);
638 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
639}
640
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641static int hci_get_fm_recv_conf_req(struct radio_hci_dev *hdev,
642 unsigned long param)
643{
644 __u16 opcode = 0;
645
646 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
647 HCI_OCF_FM_GET_RECV_CONF_REQ);
648 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
649}
650
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +0530651static int hci_get_fm_trans_conf_req(struct radio_hci_dev *hdev,
652 unsigned long param)
653{
654 u16 opcode = 0;
655
656 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
657 HCI_OCF_FM_GET_TRANS_CONF_REQ);
658 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
659}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
661 unsigned long param)
662{
663 __u16 opcode = 0;
664
665 struct hci_fm_recv_conf_req *recv_conf_req =
666 (struct hci_fm_recv_conf_req *) param;
667
668 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
669 HCI_OCF_FM_SET_RECV_CONF_REQ);
670 return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
671 recv_conf_req);
672}
673
Ankur Nandwanid928d542011-08-11 13:15:41 -0700674static int hci_set_fm_trans_conf_req(struct radio_hci_dev *hdev,
675 unsigned long param)
676{
677 __u16 opcode = 0;
678
679 struct hci_fm_trans_conf_req_struct *trans_conf_req =
680 (struct hci_fm_trans_conf_req_struct *) param;
681
682 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
683 HCI_OCF_FM_SET_TRANS_CONF_REQ);
684 return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
685 trans_conf_req);
686}
687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
689 unsigned long param)
690{
691 __u16 opcode = 0;
692
693 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
694 HCI_OCF_FM_GET_STATION_PARAM_REQ);
695 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
696}
697
698static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
699 unsigned long param)
700{
701 __u16 opcode = 0;
702 struct hci_fm_mute_mode_req *mute_mode_req =
703 (struct hci_fm_mute_mode_req *) param;
704
705 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
706 HCI_OCF_FM_SET_MUTE_MODE_REQ);
707 return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
708 mute_mode_req);
709}
710
Ankur Nandwanid928d542011-08-11 13:15:41 -0700711
712static int hci_trans_ps_req(struct radio_hci_dev *hdev,
713 unsigned long param)
714{
715 __u16 opcode = 0;
716 struct hci_fm_tx_ps *tx_ps_req =
717 (struct hci_fm_tx_ps *) param;
718
719 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
720 HCI_OCF_FM_RDS_PS_REQ);
721
722 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_ps_req)),
723 tx_ps_req);
724}
725
726static int hci_trans_rt_req(struct radio_hci_dev *hdev,
727 unsigned long param)
728{
729 __u16 opcode = 0;
730 struct hci_fm_tx_rt *tx_rt_req =
731 (struct hci_fm_tx_rt *) param;
732
733 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
734 HCI_OCF_FM_RDS_RT_REQ);
735
736 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_rt_req)),
737 tx_rt_req);
738}
739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700740static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
741 unsigned long param)
742{
743 __u16 opcode = 0;
744 struct hci_fm_stereo_mode_req *stereo_mode_req =
745 (struct hci_fm_stereo_mode_req *) param;
746 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
747 HCI_OCF_FM_SET_STEREO_MODE_REQ);
748 return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
749 stereo_mode_req);
750}
751
752static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
753 unsigned long param)
754{
755 __u16 opcode = 0;
756
757 __u8 antenna = param;
758
759 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
760 HCI_OCF_FM_SET_ANTENNA);
761 return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
762}
763
764static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
765 unsigned long param)
766{
767 __u16 opcode = 0;
768
769 __u8 sig_threshold = param;
770
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530771 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
773 return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
774 &sig_threshold);
775}
776
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +0530777static int hci_fm_set_event_mask(struct radio_hci_dev *hdev,
778 unsigned long param)
779{
780 u16 opcode = 0;
781 u8 event_mask = param;
782
783 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
784 HCI_OCF_FM_SET_EVENT_MASK);
785 return radio_hci_send_cmd(hdev, opcode, sizeof(event_mask),
786 &event_mask);
787}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
789 unsigned long param)
790{
791 __u16 opcode = 0;
792
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530793 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700794 HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
795 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
796}
797
798static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
799 unsigned long param)
800{
801 __u16 opcode = 0;
802
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530803 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
805 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
806}
807
808static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
809 unsigned long param)
810{
811 __u16 opcode = 0;
812
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530813 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814 HCI_OCF_FM_GET_RADIO_TEXT_REQ);
815 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
816}
817
818static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
819 unsigned long param)
820{
821 __u16 opcode = 0;
822
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530823 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 HCI_OCF_FM_GET_AF_LIST_REQ);
825 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
826}
827
828static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
829 unsigned long param)
830{
831 __u16 opcode = 0;
832 struct hci_fm_search_station_req *srch_stations =
833 (struct hci_fm_search_station_req *) param;
834
835 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
836 HCI_OCF_FM_SEARCH_STATIONS);
837 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
838 srch_stations);
839}
840
841static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
842 unsigned long param)
843{
844 __u16 opcode = 0;
845 struct hci_fm_search_rds_station_req *srch_stations =
846 (struct hci_fm_search_rds_station_req *) param;
847
848 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
849 HCI_OCF_FM_SEARCH_RDS_STATIONS);
850 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
851 srch_stations);
852}
853
854static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
855 unsigned long param)
856{
857 __u16 opcode = 0;
858 struct hci_fm_search_station_list_req *srch_list =
859 (struct hci_fm_search_station_list_req *) param;
860
861 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
862 HCI_OCF_FM_SEARCH_STATIONS_LIST);
863 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
864 srch_list);
865}
866
867static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
868 unsigned long param)
869{
870 __u16 opcode = 0;
871
872 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
873 HCI_OCF_FM_CANCEL_SEARCH);
874 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
875}
876
877static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
878 unsigned long param)
879{
880 __u16 opcode = 0;
881
882 __u32 fm_grps_process = param;
883
884 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
885 HCI_OCF_FM_RDS_GRP_PROCESS);
886 return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
887 &fm_grps_process);
888}
889
890static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
891 unsigned long param)
892{
893 __u16 opcode = 0;
894
895 __u32 tune_freq = param;
896
897 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
898 HCI_OCF_FM_TUNE_STATION_REQ);
899 return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
900}
901
902static int hci_def_data_read_req(struct radio_hci_dev *hdev,
903 unsigned long param)
904{
905 __u16 opcode = 0;
906 struct hci_fm_def_data_rd_req *def_data_rd =
907 (struct hci_fm_def_data_rd_req *) param;
908
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530909 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 HCI_OCF_FM_DEFAULT_DATA_READ);
911 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
912 def_data_rd);
913}
914
915static int hci_def_data_write_req(struct radio_hci_dev *hdev,
916 unsigned long param)
917{
918 __u16 opcode = 0;
919 struct hci_fm_def_data_wr_req *def_data_wr =
920 (struct hci_fm_def_data_wr_req *) param;
921
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530922 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 HCI_OCF_FM_DEFAULT_DATA_WRITE);
924 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
925 def_data_wr);
926}
927
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530928static int hci_set_notch_filter_req(struct radio_hci_dev *hdev,
929 unsigned long param)
930{
931 __u16 opcode = 0;
932 __u8 notch_filter_val = param;
933
934 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
935 HCI_OCF_FM_EN_NOTCH_CTRL);
936 return radio_hci_send_cmd(hdev, opcode, sizeof(notch_filter_val),
937 &notch_filter_val);
938}
939
940
941
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
943{
944 __u16 opcode = 0;
945
946 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
947 HCI_OCF_FM_RESET);
948 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
949}
950
951static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
952 unsigned long param)
953{
954 __u16 opcode = 0;
955
956 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
957 HCI_OCF_FM_GET_FEATURE_LIST);
958 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
959}
960
961static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
962 unsigned long param)
963{
964 __u16 opcode = 0;
965
966 __u8 mode = param;
967
968 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
969 HCI_OCF_FM_DO_CALIBRATION);
970 return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
971}
972
973static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
974 unsigned long param)
975{
976 __u16 opcode = 0;
977
978 __u8 reset_counters = param;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530979 opcode = hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700980 HCI_OCF_FM_READ_GRP_COUNTERS);
981 return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
982 &reset_counters);
983}
984
985static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
986{
987 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700988 struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700990 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991 HCI_OCF_FM_PEEK_DATA);
992 return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
993 peek_data);
994}
995
996static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
997{
998 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700999 struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07001001 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001002 HCI_OCF_FM_POKE_DATA);
1003 return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
1004 poke_data);
1005}
1006
1007static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
1008 unsigned long param)
1009{
1010 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001011 struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001013 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 HCI_OCF_FM_SSBI_PEEK_REG);
1015 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
1016 ssbi_peek);
1017}
1018
1019static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
1020 unsigned long param)
1021{
1022 __u16 opcode = 0;
1023 struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
1024
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001025 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 HCI_OCF_FM_SSBI_POKE_REG);
1027 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
1028 ssbi_poke);
1029}
1030
1031static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
1032 unsigned long param)
1033{
1034 __u16 opcode = 0;
1035
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +05301036 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001037 HCI_OCF_FM_STATION_DBG_PARAM);
1038 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1039}
1040
1041static int radio_hci_err(__u16 code)
1042{
1043 switch (code) {
1044 case 0:
1045 return 0;
1046 case 0x01:
1047 return -EBADRQC;
1048 case 0x02:
1049 return -ENOTCONN;
1050 case 0x03:
1051 return -EIO;
1052 case 0x07:
1053 return -ENOMEM;
1054 case 0x0c:
1055 return -EBUSY;
1056 case 0x11:
1057 return -EOPNOTSUPP;
1058 case 0x12:
1059 return -EINVAL;
1060 default:
1061 return -ENOSYS;
1062 }
1063}
1064
1065static int __radio_hci_request(struct radio_hci_dev *hdev,
1066 int (*req)(struct radio_hci_dev *hdev,
1067 unsigned long param),
1068 unsigned long param, __u32 timeout)
1069{
1070 int err = 0;
1071
1072 DECLARE_WAITQUEUE(wait, current);
1073
1074 hdev->req_status = HCI_REQ_PEND;
1075
1076 add_wait_queue(&hdev->req_wait_q, &wait);
1077 set_current_state(TASK_INTERRUPTIBLE);
1078
1079 err = req(hdev, param);
1080
1081 schedule_timeout(timeout);
1082
1083 remove_wait_queue(&hdev->req_wait_q, &wait);
1084
1085 if (signal_pending(current))
1086 return -EINTR;
1087
1088 switch (hdev->req_status) {
1089 case HCI_REQ_DONE:
1090 case HCI_REQ_STATUS:
1091 err = radio_hci_err(hdev->req_result);
1092 break;
1093
1094 case HCI_REQ_CANCELED:
1095 err = -hdev->req_result;
1096 break;
1097
1098 default:
1099 err = -ETIMEDOUT;
1100 break;
1101 }
1102
1103 hdev->req_status = hdev->req_result = 0;
1104
1105 return err;
1106}
1107
1108static inline int radio_hci_request(struct radio_hci_dev *hdev,
1109 int (*req)(struct
1110 radio_hci_dev * hdev, unsigned long param),
1111 unsigned long param, __u32 timeout)
1112{
1113 int ret = 0;
1114
1115 ret = __radio_hci_request(hdev, req, param, timeout);
1116
1117 return ret;
1118}
1119
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301120static inline int hci_conf_event_mask(__u8 *arg,
1121 struct radio_hci_dev *hdev)
1122{
1123 u8 event_mask = *arg;
1124 return radio_hci_request(hdev, hci_fm_set_event_mask,
1125 event_mask, RADIO_HCI_TIMEOUT);
1126}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
1128 struct radio_hci_dev *hdev)
1129{
1130 int ret = 0;
1131 struct hci_fm_recv_conf_req *set_recv_conf = arg;
1132
1133 ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
1134 long)set_recv_conf, RADIO_HCI_TIMEOUT);
1135
1136 return ret;
1137}
1138
Ankur Nandwanid928d542011-08-11 13:15:41 -07001139static int hci_set_fm_trans_conf(struct hci_fm_trans_conf_req_struct *arg,
1140 struct radio_hci_dev *hdev)
1141{
1142 int ret = 0;
1143 struct hci_fm_trans_conf_req_struct *set_trans_conf = arg;
1144
1145 ret = radio_hci_request(hdev, hci_set_fm_trans_conf_req, (unsigned
1146 long)set_trans_conf, RADIO_HCI_TIMEOUT);
1147
1148 return ret;
1149}
1150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
1152{
1153 int ret = 0;
1154 __u32 tune_freq = *arg;
1155
1156 ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
1157 RADIO_HCI_TIMEOUT);
1158
1159 return ret;
1160}
1161
1162static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
1163 struct radio_hci_dev *hdev)
1164{
1165 int ret = 0;
1166 struct hci_fm_mute_mode_req *set_mute_conf = arg;
1167
1168 ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
1169 long)set_mute_conf, RADIO_HCI_TIMEOUT);
1170
1171 return ret;
1172}
1173
1174static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
1175 struct radio_hci_dev *hdev)
1176{
1177 int ret = 0;
1178 struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
1179
1180 ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
1181 long)set_stereo_conf, RADIO_HCI_TIMEOUT);
1182
1183 return ret;
1184}
1185
1186static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
1187{
1188 int ret = 0;
1189 __u8 antenna = *arg;
1190
1191 ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
1192 RADIO_HCI_TIMEOUT);
1193
1194 return ret;
1195}
1196
1197static int hci_fm_set_signal_threshold(__u8 *arg,
1198 struct radio_hci_dev *hdev)
1199{
1200 int ret = 0;
1201 __u8 sig_threshold = *arg;
1202
1203 ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
1204 sig_threshold, RADIO_HCI_TIMEOUT);
1205
1206 return ret;
1207}
1208
1209static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
1210 struct radio_hci_dev *hdev)
1211{
1212 int ret = 0;
1213 struct hci_fm_search_station_req *srch_stations = arg;
1214
1215 ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
1216 long)srch_stations, RADIO_HCI_TIMEOUT);
1217
1218 return ret;
1219}
1220
1221static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
1222 struct radio_hci_dev *hdev)
1223{
1224 int ret = 0;
1225 struct hci_fm_search_rds_station_req *srch_stations = arg;
1226
1227 ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
1228 long)srch_stations, RADIO_HCI_TIMEOUT);
1229
1230 return ret;
1231}
1232
1233static int hci_fm_search_station_list
1234 (struct hci_fm_search_station_list_req *arg,
1235 struct radio_hci_dev *hdev)
1236{
1237 int ret = 0;
1238 struct hci_fm_search_station_list_req *srch_list = arg;
1239
1240 ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
1241 long)srch_list, RADIO_HCI_TIMEOUT);
1242
1243 return ret;
1244}
1245
1246static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
1247 struct radio_hci_dev *hdev)
1248{
1249 return 0;
1250}
1251
1252static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
1253{
1254 int ret = 0;
1255 __u32 fm_grps_process = *arg;
1256
1257 ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
1258 fm_grps_process, RADIO_HCI_TIMEOUT);
1259
1260 return ret;
1261}
1262
1263int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
1264 struct radio_hci_dev *hdev)
1265{
1266 int ret = 0;
1267 struct hci_fm_def_data_rd_req *def_data_rd = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
1269 long)def_data_rd, RADIO_HCI_TIMEOUT);
1270
1271 return ret;
1272}
1273
1274int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
1275 struct radio_hci_dev *hdev)
1276{
1277 int ret = 0;
1278 struct hci_fm_def_data_wr_req *def_data_wr = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
1280 long)def_data_wr, RADIO_HCI_TIMEOUT);
1281
1282 return ret;
1283}
1284
1285int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
1286{
1287 int ret = 0;
1288 __u8 mode = *arg;
1289
1290 ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
1291 RADIO_HCI_TIMEOUT);
1292
1293 return ret;
1294}
1295
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301296static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297{
1298 int ret = 0;
1299 __u8 reset_counters = *arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 ret = radio_hci_request(hdev, hci_read_grp_counters_req,
1301 reset_counters, RADIO_HCI_TIMEOUT);
1302
1303 return ret;
1304}
1305
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301306static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
1307{
1308 int ret = 0;
1309 __u8 notch_filter = *arg;
1310 ret = radio_hci_request(hdev, hci_set_notch_filter_req,
1311 notch_filter, RADIO_HCI_TIMEOUT);
1312
1313 return ret;
1314}
1315
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001316static int hci_peek_data(struct hci_fm_riva_data *arg,
1317 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318{
1319 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001320 struct hci_fm_riva_data *peek_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321
1322 ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
1323 long)peek_data, RADIO_HCI_TIMEOUT);
1324
1325 return ret;
1326}
1327
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001328static int hci_poke_data(struct hci_fm_riva_poke *arg,
1329 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330{
1331 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001332 struct hci_fm_riva_poke *poke_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333
1334 ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
1335 long)poke_data, RADIO_HCI_TIMEOUT);
1336
1337 return ret;
1338}
1339
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001340static int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *arg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 struct radio_hci_dev *hdev)
1342{
1343 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001344 struct hci_fm_ssbi_peek *ssbi_peek_reg = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345
1346 ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
1347 long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
1348
1349 return ret;
1350}
1351
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001352static int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg,
1353 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354{
1355 int ret = 0;
1356 struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
1357
1358 ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
1359 long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
1360
1361 return ret;
1362}
1363
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301364static int hci_fm_set_cal_req_proc(struct radio_hci_dev *hdev,
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301365 unsigned long param)
1366{
1367 u16 opcode = 0;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301368 struct hci_fm_set_cal_req_proc *cal_req =
1369 (struct hci_fm_set_cal_req_proc *)param;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301370
1371 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1372 HCI_OCF_FM_SET_CALIBRATION);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301373 return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301374 cal_req);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301375}
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301376
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301377static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
1378 unsigned long param)
1379{
1380 u16 opcode = 0;
1381 u8 cal_mode = param;
1382
1383 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1384 HCI_OCF_FM_DO_CALIBRATION);
1385 return radio_hci_send_cmd(hdev, opcode, sizeof(cal_mode),
1386 &cal_mode);
1387
1388}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1390{
1391 int ret = 0;
1392 unsigned long arg = 0;
1393
Ankur Nandwanid928d542011-08-11 13:15:41 -07001394 if (!hdev)
1395 return -ENODEV;
1396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001397 switch (cmd) {
1398 case HCI_FM_ENABLE_RECV_CMD:
1399 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1400 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1401 break;
1402
1403 case HCI_FM_DISABLE_RECV_CMD:
1404 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1405 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1406 break;
1407
1408 case HCI_FM_GET_RECV_CONF_CMD:
1409 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1410 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1411 break;
1412
1413 case HCI_FM_GET_STATION_PARAM_CMD:
1414 ret = radio_hci_request(hdev,
1415 hci_fm_get_station_param_req, arg,
1416 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1417 break;
1418
1419 case HCI_FM_GET_SIGNAL_TH_CMD:
1420 ret = radio_hci_request(hdev,
1421 hci_fm_get_sig_threshold_req, arg,
1422 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1423 break;
1424
1425 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1426 ret = radio_hci_request(hdev,
1427 hci_fm_get_program_service_req, arg,
1428 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1429 break;
1430
1431 case HCI_FM_GET_RADIO_TEXT_CMD:
1432 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1433 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1434 break;
1435
1436 case HCI_FM_GET_AF_LIST_CMD:
1437 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1438 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1439 break;
1440
1441 case HCI_FM_CANCEL_SEARCH_CMD:
1442 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1443 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1444 break;
1445
1446 case HCI_FM_RESET_CMD:
1447 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1448 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1449 break;
1450
1451 case HCI_FM_GET_FEATURES_CMD:
1452 ret = radio_hci_request(hdev,
1453 hci_fm_get_feature_lists_req, arg,
1454 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1455 break;
1456
1457 case HCI_FM_STATION_DBG_PARAM_CMD:
1458 ret = radio_hci_request(hdev,
1459 hci_fm_get_station_dbg_param_req, arg,
1460 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1461 break;
1462
Ankur Nandwanid928d542011-08-11 13:15:41 -07001463 case HCI_FM_ENABLE_TRANS_CMD:
1464 ret = radio_hci_request(hdev, hci_fm_enable_trans_req, arg,
1465 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1466 break;
1467
1468 case HCI_FM_DISABLE_TRANS_CMD:
1469 ret = radio_hci_request(hdev, hci_fm_disable_trans_req, arg,
1470 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1471 break;
1472
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301473 case HCI_FM_GET_TX_CONFIG:
1474 ret = radio_hci_request(hdev, hci_get_fm_trans_conf_req, arg,
1475 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1476 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 default:
1478 ret = -EINVAL;
1479 break;
1480 }
1481
1482 return ret;
1483}
1484
1485static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1486{
1487 hdev->req_result = result;
1488 hdev->req_status = HCI_REQ_DONE;
1489 wake_up_interruptible(&hdev->req_wait_q);
1490}
1491
1492static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1493{
1494 hdev->req_result = result;
1495 hdev->req_status = HCI_REQ_STATUS;
1496 wake_up_interruptible(&hdev->req_wait_q);
1497}
1498
1499static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1500{
1501 __u8 status = *((__u8 *) skb->data);
1502
1503 if (status)
1504 return;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001506 radio_hci_req_complete(hdev, status);
1507}
1508
1509static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1510 struct sk_buff *skb)
1511{
1512 __u8 status = *((__u8 *) skb->data);
1513 struct iris_device *radio = video_get_drvdata(video_get_dev());
1514
1515 if (status)
1516 return;
1517
1518 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1519
1520 radio_hci_req_complete(hdev, status);
1521}
1522
1523static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1524{
1525 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1526 struct iris_device *radio = video_get_drvdata(video_get_dev());
1527
1528 if (rsp->status)
1529 return;
1530
1531 radio->recv_conf = rsp->recv_conf_rsp;
1532 radio_hci_req_complete(hdev, rsp->status);
1533}
1534
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301535static void hci_cc_fm_trans_get_conf_rsp(struct radio_hci_dev *hdev,
1536 struct sk_buff *skb)
1537{
1538 struct hci_fm_get_trans_conf_rsp *rsp = (void *)skb->data;
1539 struct iris_device *radio = video_get_drvdata(video_get_dev());
1540
1541 if (rsp->status)
1542 return;
1543 memcpy((void *)&radio->trans_conf, (void*)&rsp->trans_conf_rsp,
1544 sizeof(rsp->trans_conf_rsp));
1545 radio_hci_req_complete(hdev, rsp->status);
1546}
1547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1549 struct sk_buff *skb)
1550{
1551 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1552 struct iris_device *radio = video_get_drvdata(video_get_dev());
1553
1554 if (rsp->status)
1555 return;
1556
1557 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1558
1559 radio_hci_req_complete(hdev, rsp->status);
1560}
1561
Ankur Nandwanid928d542011-08-11 13:15:41 -07001562
1563static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
1564 struct sk_buff *skb)
1565{
1566 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1567 struct iris_device *radio = video_get_drvdata(video_get_dev());
1568
1569 if (rsp->status)
1570 return;
1571
1572 iris_q_event(radio, HCI_EV_CMD_COMPLETE);
1573
1574 radio_hci_req_complete(hdev, rsp->status);
1575}
1576
1577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1579 struct sk_buff *skb)
1580{
1581 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1582 struct iris_device *radio = video_get_drvdata(video_get_dev());
1583 struct v4l2_control *v4l_ctl = radio->g_ctl;
1584
1585 if (rsp->status)
1586 return;
1587
1588 v4l_ctl->value = rsp->sig_threshold;
1589
1590 radio_hci_req_complete(hdev, rsp->status);
1591}
1592
1593static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1594{
1595 struct iris_device *radio = video_get_drvdata(video_get_dev());
1596 struct hci_fm_station_rsp *rsp = (void *)skb->data;
1597 radio->fm_st_rsp = *(rsp);
1598
1599 /* Tune is always succesful */
1600 radio_hci_req_complete(hdev, 0);
1601}
1602
1603static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1604{
1605 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1606
1607 if (rsp->status)
1608 return;
1609
1610 radio_hci_req_complete(hdev, rsp->status);
1611}
1612
1613static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1614{
1615 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1616
1617 if (rsp->status)
1618 return;
1619
1620 radio_hci_req_complete(hdev, rsp->status);
1621}
1622
1623static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1624{
1625 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1626
1627 if (rsp->status)
1628 return;
1629
1630 radio_hci_req_complete(hdev, rsp->status);
1631}
1632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1634 struct sk_buff *skb)
1635{
1636 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1637 struct iris_device *radio = video_get_drvdata(video_get_dev());
1638 struct v4l2_capability *v4l_cap = radio->g_cap;
1639
1640 if (rsp->status)
1641 return;
1642 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1643 (rsp->feature_mask & 0x000001);
1644
1645 radio_hci_req_complete(hdev, rsp->status);
1646}
1647
1648static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1649 struct sk_buff *skb)
1650{
1651 struct iris_device *radio = video_get_drvdata(video_get_dev());
1652 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
1653 radio->st_dbg_param = *(rsp);
1654
1655 if (radio->st_dbg_param.status)
1656 return;
1657
1658 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1659}
1660
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001661static void iris_q_evt_data(struct iris_device *radio,
1662 char *data, int len, int event)
1663{
1664 struct kfifo *data_b = &radio->data_buf[event];
1665 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1666 wake_up_interruptible(&radio->event_queue);
1667}
1668
1669static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1670 struct sk_buff *skb)
1671{
1672 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301673 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001674 int len;
1675 char *data;
1676
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301677 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001678 return;
1679 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1680 data = kmalloc(len, GFP_ATOMIC);
1681
1682 if (!data) {
1683 FMDERR("Memory allocation failed");
1684 return;
1685 }
1686
1687 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1688 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301689 radio_hci_req_complete(hdev, status);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301690 kfree(data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001691
1692}
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301693
1694static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
1695 struct sk_buff *skb)
1696{
1697 struct iris_device *radio = video_get_drvdata(video_get_dev());
1698 __u8 status = *((__u8 *) skb->data);
1699 __u8 len;
1700 char *data;
1701
1702 if (status)
1703 return;
1704 len = skb->data[1];
1705 data = kmalloc(len+2, GFP_ATOMIC);
1706 if (!data) {
1707 FMDERR("Memory allocation failed");
1708 return;
1709 }
1710
1711 data[0] = status;
1712 data[1] = len;
1713 memcpy(&data[2], &skb->data[DEFAULT_DATA_OFFSET], len);
1714 iris_q_evt_data(radio, data, len+2, IRIS_BUF_RD_DEFAULT);
1715 radio_hci_req_complete(hdev, status);
1716 kfree(data);
1717}
1718
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001719static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1720 struct sk_buff *skb)
1721{
1722 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301723 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001724 char *data;
1725
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301726 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001727 return;
1728 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1729 if (!data) {
1730 FMDERR("Memory allocation failed");
1731 return;
1732 }
1733
1734 data[0] = skb->data[PEEK_DATA_OFSET];
1735 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301736 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001737 kfree(data);
1738}
1739
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301740static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
1741 struct sk_buff *skb)
1742{
1743 struct iris_device *radio = video_get_drvdata(video_get_dev());
1744 __u8 status = *((__u8 *) skb->data);
1745 char *data;
1746 if (status)
1747 return;
1748 data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
1749 if (!data) {
1750 FMDERR("memory allocation failed");
1751 return;
1752 }
1753 memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
1754 iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
1755 radio_hci_req_complete(hdev, status);
1756 kfree(data);
1757
1758}
1759
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301760static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
1761 struct sk_buff *skb)
1762{
1763 struct iris_device *radio = video_get_drvdata(video_get_dev());
1764 static struct hci_cc_do_calibration_rsp rsp ;
1765 rsp.status = skb->data[0];
1766 rsp.mode = skb->data[CALIB_MODE_OFSET];
1767
1768 if (rsp.status) {
1769 FMDERR("status = %d", rsp.status);
1770 return;
1771 }
1772 if (rsp.mode == PROCS_CALIB_MODE) {
1773 memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
1774 PROCS_CALIB_SIZE);
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05301775 iris_q_evt_data(radio, rsp.data, PROCS_CALIB_SIZE,
1776 IRIS_BUF_CAL_DATA);
1777 } else {
1778 return;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301779 }
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05301780
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301781 radio_hci_req_complete(hdev, rsp.status);
1782}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
1784 struct sk_buff *skb)
1785{
1786 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
1787 __u16 opcode;
1788
1789 skb_pull(skb, sizeof(*cmd_compl_ev));
1790
1791 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
1792
1793 switch (opcode) {
1794 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
1795 hci_cc_fm_enable_rsp(hdev, skb);
1796 break;
1797 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
1798 hci_cc_conf_rsp(hdev, skb);
1799 break;
1800
1801 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
1802 hci_cc_fm_disable_rsp(hdev, skb);
1803 break;
1804
1805 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
1806 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
1807 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
1808 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
1809 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
1810 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
1811 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
1812 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
1813 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
1814 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001815 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
1816 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
1817 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
1818 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301820 hci_cc_rsp(hdev, skb);
1821 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001822 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001824 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001825 case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301826 case hci_common_cmd_op_pack(HCI_OCF_FM_SET_CALIBRATION):
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301827 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_EVENT_MASK):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828 hci_cc_rsp(hdev, skb);
1829 break;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301830
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001831 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
1832 hci_cc_ssbi_peek_rsp(hdev, skb);
1833 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
1835 hci_cc_sig_threshold_rsp(hdev, skb);
1836 break;
1837
1838 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
1839 hci_cc_station_rsp(hdev, skb);
1840 break;
1841
1842 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
1843 hci_cc_prg_srv_rsp(hdev, skb);
1844 break;
1845
1846 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
1847 hci_cc_rd_txt_rsp(hdev, skb);
1848 break;
1849
1850 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
1851 hci_cc_af_list_rsp(hdev, skb);
1852 break;
1853
1854 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301855 hci_cc_riva_read_default_rsp(hdev, skb);
1856 break;
1857
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001858 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001859 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001860 break;
1861
1862 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
1863 hci_cc_feature_list_rsp(hdev, skb);
1864 break;
1865
1866 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
1867 hci_cc_dbg_param_rsp(hdev, skb);
1868 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07001869 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_SET_TRANS_CONF_REQ):
1870 hci_cc_fm_trans_set_conf_rsp(hdev, skb);
1871 break;
1872
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301873 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
1874 hci_cc_rds_grp_cntrs_rsp(hdev, skb);
1875 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301876 case hci_common_cmd_op_pack(HCI_OCF_FM_DO_CALIBRATION):
1877 hci_cc_do_calibration_rsp(hdev, skb);
1878 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301879
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301880 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_GET_TRANS_CONF_REQ):
1881 hci_cc_fm_trans_get_conf_rsp(hdev, skb);
1882 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883 default:
1884 FMDERR("%s opcode 0x%x", hdev->name, opcode);
1885 break;
1886 }
1887
1888}
1889
1890static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
1891 struct sk_buff *skb)
1892{
1893 struct hci_ev_cmd_status *ev = (void *) skb->data;
1894 radio_hci_status_complete(hdev, ev->status);
1895}
1896
1897static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
1898 struct sk_buff *skb)
1899{
1900 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901 struct iris_device *radio = video_get_drvdata(video_get_dev());
1902
Venkateshwarlu Domakonda862492d2011-11-29 11:51:24 +05301903 memcpy(&radio->fm_st_rsp.station_rsp, &skb->data[0],
1904 sizeof(struct hci_ev_tune_status));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
1906
1907 for (i = 0; i < IRIS_BUF_MAX; i++) {
1908 if (i >= IRIS_BUF_RT_RDS)
1909 kfifo_reset(&radio->data_buf[i]);
1910 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001911 if (radio->fm_st_rsp.station_rsp.rssi)
1912 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1913 else
1914 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1915
1916 if (radio->fm_st_rsp.station_rsp.stereo_prg)
1917 iris_q_event(radio, IRIS_EVT_STEREO);
1918
1919 if (radio->fm_st_rsp.station_rsp.mute_mode)
1920 iris_q_event(radio, IRIS_EVT_MONO);
1921
1922 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
1923 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1924 else
1925 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1926}
1927
1928static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
1929 struct sk_buff *skb)
1930{
1931 struct iris_device *radio = video_get_drvdata(video_get_dev());
1932 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
1933}
1934
1935static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
1936 struct sk_buff *skb)
1937{
1938 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001939 struct hci_ev_srch_list_compl *ev ;
1940 int cnt;
1941 int stn_num;
1942 int rel_freq;
1943 int abs_freq;
1944 int len;
1945
1946 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1947 if (!ev) {
1948 FMDERR("Memory allocation failed");
1949 return ;
1950 }
1951
1952 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
1953 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
1954
1955 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301956 (cnt < len) && (stn_num < ev->num_stations_found)
1957 && (stn_num < ARRAY_SIZE(ev->rel_freq));
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001958 cnt += PARAMS_PER_STATION, stn_num++) {
1959 abs_freq = *((int *)&skb->data[cnt]);
1960 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
1961 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
1962
1963 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
1964 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
1965 }
1966
1967 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
1968 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
1969 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
1970 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971}
1972
1973static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
1974 struct sk_buff *skb)
1975{
1976 struct iris_device *radio = video_get_drvdata(video_get_dev());
1977 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
1978}
1979
1980static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
1981 struct sk_buff *skb)
1982{
1983 struct iris_device *radio = video_get_drvdata(video_get_dev());
1984 __u8 st_status = *((__u8 *) skb->data);
1985 if (st_status)
1986 iris_q_event(radio, IRIS_EVT_STEREO);
1987 else
1988 iris_q_event(radio, IRIS_EVT_MONO);
1989}
1990
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001991
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001992static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
1993 struct sk_buff *skb)
1994{
1995 struct iris_device *radio = video_get_drvdata(video_get_dev());
1996 int len;
1997 char *data;
1998
1999 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
2000 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
2001 data = kmalloc(len, GFP_ATOMIC);
2002 if (!data) {
2003 FMDERR("Failed to allocate memory");
2004 return;
2005 }
2006
2007 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
2008 data[1] = skb->data[RDS_PTYPE];
2009 data[2] = skb->data[RDS_PID_LOWER];
2010 data[3] = skb->data[RDS_PID_HIGHER];
2011 data[4] = 0;
2012
2013 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
2014
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002015 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002016
2017 kfree(data);
2018}
2019
2020
2021static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
2022 struct sk_buff *skb)
2023{
2024 struct iris_device *radio = video_get_drvdata(video_get_dev());
2025 int len = 0;
2026 char *data;
2027
2028 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
2029
2030 while (skb->data[len+RDS_OFFSET] != 0x0d)
2031 len++;
2032 len++;
2033
2034 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
2035 if (!data) {
2036 FMDERR("Failed to allocate memory");
2037 return;
2038 }
2039
2040 data[0] = len;
2041 data[1] = skb->data[RDS_PTYPE];
2042 data[2] = skb->data[RDS_PID_LOWER];
2043 data[3] = skb->data[RDS_PID_HIGHER];
2044 data[4] = 0;
2045
2046 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
2047 data[len+RDS_OFFSET] = 0x00;
2048
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002049 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002050
2051 kfree(data);
2052}
2053
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302054static void hci_ev_af_list(struct radio_hci_dev *hdev,
2055 struct sk_buff *skb)
2056{
2057 struct iris_device *radio = video_get_drvdata(video_get_dev());
2058 struct hci_ev_af_list ev;
2059
2060 ev.tune_freq = *((int *) &skb->data[0]);
2061 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
2062 ev.af_size = skb->data[AF_SIZE_OFFSET];
2063 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
2064 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
2065 iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
2066}
2067
2068static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
2069 struct sk_buff *skb)
2070{
2071 struct iris_device *radio = video_get_drvdata(video_get_dev());
2072 __u8 rds_status = skb->data[0];
2073
2074 if (rds_status)
2075 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2076 else
2077 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2078}
2079
2080static void hci_ev_service_available(struct radio_hci_dev *hdev,
2081 struct sk_buff *skb)
2082{
2083 struct iris_device *radio = video_get_drvdata(video_get_dev());
2084 if (radio->fm_st_rsp.station_rsp.serv_avble)
2085 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2086 else
2087 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2088}
2089
2090static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
2091 struct sk_buff *skb)
2092{
2093 struct iris_device *radio = video_get_drvdata(video_get_dev());
2094 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
2095}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002096
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002097void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
2098{
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302099 struct radio_hci_event_hdr *hdr;
2100 u8 event;
2101
2102 if (skb == NULL) {
2103 FMDERR("Socket buffer is NULL");
2104 return;
2105 }
2106
2107 hdr = (void *) skb->data;
2108 event = hdr->evt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002109
2110 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
2111
2112 switch (event) {
2113 case HCI_EV_TUNE_STATUS:
2114 hci_ev_tune_status(hdev, skb);
2115 break;
2116 case HCI_EV_SEARCH_PROGRESS:
2117 case HCI_EV_SEARCH_RDS_PROGRESS:
2118 case HCI_EV_SEARCH_LIST_PROGRESS:
2119 hci_ev_search_next(hdev, skb);
2120 break;
2121 case HCI_EV_STEREO_STATUS:
2122 hci_ev_stereo_status(hdev, skb);
2123 break;
2124 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302125 hci_ev_rds_lock_status(hdev, skb);
2126 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002127 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302128 hci_ev_service_available(hdev, skb);
2129 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130 case HCI_EV_RDS_RX_DATA:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002131 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002132 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002133 hci_ev_program_service(hdev, skb);
2134 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002135 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002136 hci_ev_radio_text(hdev, skb);
2137 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002138 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302139 hci_ev_af_list(hdev, skb);
2140 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302142 hci_ev_rds_grp_complete(hdev, skb);
2143 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2145 break;
2146
2147 case HCI_EV_CMD_COMPLETE:
2148 hci_cmd_complete_event(hdev, skb);
2149 break;
2150
2151 case HCI_EV_CMD_STATUS:
2152 hci_cmd_status_event(hdev, skb);
2153 break;
2154
2155 case HCI_EV_SEARCH_COMPLETE:
2156 case HCI_EV_SEARCH_RDS_COMPLETE:
2157 hci_ev_search_compl(hdev, skb);
2158 break;
2159
2160 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002161 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002162 break;
2163
2164 default:
2165 break;
2166 }
2167}
2168
2169/*
2170 * fops/IOCTL helper functions
2171 */
2172
2173static int iris_search(struct iris_device *radio, int on, int dir)
2174{
2175 int retval = 0;
2176 enum search_t srch = radio->g_search_mode & SRCH_MODE;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302177 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002178
2179 if (on) {
2180 switch (srch) {
2181 case SCAN_FOR_STRONG:
2182 case SCAN_FOR_WEAK:
2183 radio->srch_st_list.srch_list_dir = dir;
2184 radio->srch_st_list.srch_list_mode = srch;
2185 radio->srch_st_list.srch_list_max = 0;
2186 retval = hci_fm_search_station_list(
2187 &radio->srch_st_list, radio->fm_hdev);
2188 break;
2189 case RDS_SEEK_PTY:
2190 case RDS_SCAN_PTY:
2191 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002192 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002193 radio->srch_rds.srch_station.srch_mode = srch;
2194 radio->srch_rds.srch_station.srch_dir = dir;
2195 radio->srch_rds.srch_station.scan_time =
2196 radio->g_scan_time;
2197 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2198 radio->fm_hdev);
2199 break;
2200 default:
2201 radio->srch_st.srch_mode = srch;
2202 radio->srch_st.scan_time = radio->g_scan_time;
2203 radio->srch_st.srch_dir = dir;
2204 retval = hci_fm_search_stations(
2205 &radio->srch_st, radio->fm_hdev);
2206 break;
2207 }
2208
2209 } else {
2210 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2211 }
2212
2213 return retval;
2214}
2215
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302216static int set_low_power_mode(struct iris_device *radio, int power_mode)
2217{
2218
2219 int rds_grps_proc = 0x00;
2220 int retval = 0;
2221 if (radio->power_mode != power_mode) {
2222
2223 if (power_mode) {
2224 radio->event_mask = 0x00;
2225 rds_grps_proc = 0x00 | AF_JUMP_ENABLE ;
2226 retval = hci_fm_rds_grps_process(
2227 &rds_grps_proc,
2228 radio->fm_hdev);
2229 if (retval < 0) {
2230 FMDERR("Disable RDS failed");
2231 return retval;
2232 }
2233 retval = hci_conf_event_mask(&radio->event_mask,
2234 radio->fm_hdev);
2235 } else {
2236
2237 radio->event_mask = SIG_LEVEL_INTR |
2238 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2239 retval = hci_conf_event_mask(&radio->event_mask,
2240 radio->fm_hdev);
2241 if (retval < 0) {
2242 FMDERR("Enable Async events failed");
2243 return retval;
2244 }
2245 retval = hci_fm_rds_grps_process(
2246 &radio->g_rds_grp_proc_ps,
2247 radio->fm_hdev);
2248 }
2249 radio->power_mode = power_mode;
2250 }
2251 return retval;
2252}
Ankur Nandwanid928d542011-08-11 13:15:41 -07002253static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254{
2255 int retval;
2256 radio->region = req_region;
2257
2258 switch (radio->region) {
2259 case IRIS_REGION_US:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002260 radio->recv_conf.band_low_limit =
2261 REGION_US_EU_BAND_LOW;
2262 radio->recv_conf.band_high_limit =
2263 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264 break;
2265 case IRIS_REGION_EU:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002266 radio->recv_conf.band_low_limit =
2267 REGION_US_EU_BAND_LOW;
2268 radio->recv_conf.band_high_limit =
2269 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 break;
2271 case IRIS_REGION_JAPAN:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002272 radio->recv_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002273 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302274 radio->recv_conf.band_high_limit =
2275 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002276 break;
2277 case IRIS_REGION_JAPAN_WIDE:
2278 radio->recv_conf.band_low_limit =
2279 REGION_JAPAN_WIDE_BAND_LOW;
2280 radio->recv_conf.band_high_limit =
2281 REGION_JAPAN_WIDE_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 break;
2283 default:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002284 /* The user specifies the value.
2285 So nothing needs to be done */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286 break;
2287 }
2288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 retval = hci_set_fm_recv_conf(
2290 &radio->recv_conf,
2291 radio->fm_hdev);
2292
2293 return retval;
2294}
2295
Ankur Nandwanid928d542011-08-11 13:15:41 -07002296
2297static int iris_trans_set_region(struct iris_device *radio, int req_region)
2298{
2299 int retval;
2300 radio->region = req_region;
2301
2302 switch (radio->region) {
2303 case IRIS_REGION_US:
2304 radio->trans_conf.band_low_limit =
2305 REGION_US_EU_BAND_LOW;
2306 radio->trans_conf.band_high_limit =
2307 REGION_US_EU_BAND_HIGH;
2308 break;
2309 case IRIS_REGION_EU:
2310 radio->trans_conf.band_low_limit =
2311 REGION_US_EU_BAND_LOW;
2312 radio->trans_conf.band_high_limit =
2313 REGION_US_EU_BAND_HIGH;
2314 break;
2315 case IRIS_REGION_JAPAN:
2316 radio->trans_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002317 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302318 radio->trans_conf.band_high_limit =
2319 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002320 break;
2321 case IRIS_REGION_JAPAN_WIDE:
2322 radio->recv_conf.band_low_limit =
2323 REGION_JAPAN_WIDE_BAND_LOW;
2324 radio->recv_conf.band_high_limit =
2325 REGION_JAPAN_WIDE_BAND_HIGH;
2326 default:
2327 break;
2328 }
2329
2330 retval = hci_set_fm_trans_conf(
2331 &radio->trans_conf,
2332 radio->fm_hdev);
2333 return retval;
2334}
2335
2336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2338{
2339
2340 int retval;
2341 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2342 if (retval < 0)
2343 FMDERR("Error while setting the frequency : %d\n", retval);
2344 return retval;
2345}
2346
2347
2348static int iris_vidioc_queryctrl(struct file *file, void *priv,
2349 struct v4l2_queryctrl *qc)
2350{
2351 unsigned char i;
2352 int retval = -EINVAL;
2353
2354 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2355 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2356 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2357 retval = 0;
2358 break;
2359 }
2360 }
2361
2362 return retval;
2363}
2364
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302365static int iris_do_calibration(struct iris_device *radio)
2366{
2367 char cal_mode = 0x00;
2368 int retval = 0x00;
2369
2370 cal_mode = PROCS_CALIB_MODE;
2371 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2372 radio->fm_hdev);
2373 if (retval < 0) {
2374 FMDERR("Enable failed before calibration %x", retval);
2375 return retval;
2376 }
2377 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2378 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2379 if (retval < 0) {
2380 FMDERR("Do Process calibration failed %x", retval);
2381 return retval;
2382 }
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302383 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2384 radio->fm_hdev);
2385 if (retval < 0)
2386 FMDERR("Disable Failed after calibration %d", retval);
2387 return retval;
2388}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002389static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2390 struct v4l2_control *ctrl)
2391{
2392 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2393 int retval = 0;
2394
2395 switch (ctrl->id) {
2396 case V4L2_CID_AUDIO_VOLUME:
2397 break;
2398 case V4L2_CID_AUDIO_MUTE:
2399 ctrl->value = radio->mute_mode.hard_mute;
2400 break;
2401 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2402 ctrl->value = radio->g_search_mode;
2403 break;
2404 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2405 ctrl->value = radio->g_scan_time;
2406 break;
2407 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302408 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409 break;
2410 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302411 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412 break;
2413 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2414 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2415 if (retval < 0)
2416 return retval;
2417 ctrl->value = radio->st_dbg_param.io_verc;
2418 break;
2419 case V4L2_CID_PRIVATE_IRIS_INTDET:
2420 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2421 if (retval < 0)
2422 return retval;
2423 ctrl->value = radio->st_dbg_param.in_det_out;
2424 break;
2425 case V4L2_CID_PRIVATE_IRIS_REGION:
2426 ctrl->value = radio->region;
2427 break;
2428 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2429 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
2430 break;
2431 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302432 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002433 break;
2434 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302435 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436 break;
2437 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302438 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439 break;
2440 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002441 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002443 } else if (radio->mode == FM_TRANS) {
2444 ctrl->value = radio->trans_conf.emphasis;
2445 } else {
2446 FMDERR("Error in radio mode"
2447 " %d\n", retval);
2448 return -EINVAL;
2449 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 break;
2451 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002452 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002454 } else if (radio->mode == FM_TRANS) {
2455 ctrl->value = radio->trans_conf.rds_std;
2456 } else {
2457 FMDERR("Error in radio mode"
2458 " %d\n", retval);
2459 return -EINVAL;
2460 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 break;
2462 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002463 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002465 } else {
2466 FMDERR("Error in radio mode"
2467 " %d\n", retval);
2468 return -EINVAL;
2469 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 break;
2471 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002472 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002474 } else {
2475 FMDERR("Error in radio mode"
2476 " %d\n", retval);
2477 return -EINVAL;
2478 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 break;
2480 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2481 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2482 break;
2483 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002484 case V4L2_CID_PRIVATE_IRIS_PSALL:
2485 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002486 break;
2487 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2488 ctrl->value = radio->rds_grp.rds_buf_size;
2489 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002490 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302491 ctrl->value = radio->power_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492 break;
2493 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2494 ctrl->value = radio->g_antenna;
2495 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002496 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2497 ctrl->value = radio->mute_mode.soft_mute;
2498 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302499 case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
2500 retval = iris_do_calibration(radio);
2501 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002502 default:
2503 retval = -EINVAL;
2504 }
2505 if (retval < 0)
2506 FMDERR("get control failed with %d, id: %d\n",
2507 retval, ctrl->id);
2508 return retval;
2509}
2510
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302511static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
2512 struct v4l2_ext_controls *ctrl)
2513{
2514 int retval = 0;
2515 char *data = NULL;
2516 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2517 struct hci_fm_def_data_rd_req default_data_rd;
2518
2519 switch ((ctrl->controls[0]).id) {
2520 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
2521 data = (ctrl->controls[0]).string;
2522 memset(&default_data_rd, 0, sizeof(default_data_rd));
2523 if (copy_from_user(&default_data_rd.mode, data,
2524 sizeof(default_data_rd)))
2525 return -EFAULT;
2526 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
2527 break;
2528 default:
2529 retval = -EINVAL;
2530 }
2531
2532 return retval;
2533}
2534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002535static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2536 struct v4l2_ext_controls *ctrl)
2537{
Ankur Nandwanid928d542011-08-11 13:15:41 -07002538 int retval = 0;
2539 int bytes_to_copy;
2540 struct hci_fm_tx_ps tx_ps;
2541 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302542 struct hci_fm_def_data_wr_req default_data;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302543 struct hci_fm_set_cal_req_proc proc_cal_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002544
2545 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2546 char *data = NULL;
2547
2548 switch ((ctrl->controls[0]).id) {
2549 case V4L2_CID_RDS_TX_PS_NAME:
2550 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2551 /*Pass a sample PS string */
2552
2553 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
2554 bytes_to_copy = min((int)(ctrl->controls[0]).size,
2555 MAX_PS_LENGTH);
2556 data = (ctrl->controls[0]).string;
2557
2558 if (copy_from_user(tx_ps.ps_data,
2559 data, bytes_to_copy))
2560 return -EFAULT;
2561 tx_ps.ps_control = 0x01;
2562 tx_ps.pi = radio->pi;
2563 tx_ps.pty = radio->pty;
2564 tx_ps.ps_repeatcount = radio->ps_repeatcount;
2565 tx_ps.ps_len = bytes_to_copy;
2566
2567 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2568 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
2569 break;
2570 case V4L2_CID_RDS_TX_RADIO_TEXT:
2571 bytes_to_copy =
2572 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2573 data = (ctrl->controls[0]).string;
2574
2575 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
2576
2577 if (copy_from_user(tx_rt.rt_data,
2578 data, bytes_to_copy))
2579 return -EFAULT;
2580
2581 tx_rt.rt_control = 0x01;
2582 tx_rt.pi = radio->pi;
2583 tx_rt.pty = radio->pty;
2584 tx_rt.ps_len = bytes_to_copy;
2585
2586 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2587 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
2588 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302589 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
2590 data = (ctrl->controls[0]).string;
2591 memset(&default_data, 0, sizeof(default_data));
2592 if (copy_from_user(&default_data, data, sizeof(default_data)))
2593 return -EFAULT;
2594 retval = hci_def_data_write(&default_data, radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302595 break;
2596 case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302597 data = (ctrl->controls[0]).string;
2598 bytes_to_copy = (ctrl->controls[0]).size;
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05302599 if (bytes_to_copy < PROCS_CALIB_SIZE) {
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302600 FMDERR("data is less than required size");
2601 return -EFAULT;
2602 }
2603 memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
2604 proc_cal_req.mode = PROCS_CALIB_MODE;
2605 if (copy_from_user(&proc_cal_req.data[0],
2606 data, sizeof(proc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302607 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302608 retval = radio_hci_request(radio->fm_hdev,
2609 hci_fm_set_cal_req_proc,
2610 (unsigned long)&proc_cal_req,
2611 RADIO_HCI_TIMEOUT);
2612 if (retval < 0) {
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302613 FMDERR("Set Process calibration failed %d", retval);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302614 }
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302615 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002616 default:
2617 FMDBG("Shouldn't reach here\n");
2618 retval = -1;
2619 }
2620 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002621}
2622
2623static int iris_vidioc_s_ctrl(struct file *file, void *priv,
2624 struct v4l2_control *ctrl)
2625{
2626 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2627 int retval = 0;
2628 unsigned int rds_grps_proc = 0;
2629 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002630 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302631 struct hci_fm_tx_ps tx_ps = {0};
2632 struct hci_fm_tx_rt tx_rt = {0};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002633
2634 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302635 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002636 radio->tone_freq = ctrl->value;
2637 retval = radio_hci_request(radio->fm_hdev,
2638 hci_fm_tone_generator, arg,
2639 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302640 if (retval < 0)
2641 FMDERR("Error while setting the tone %d", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002642 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002643 case V4L2_CID_AUDIO_VOLUME:
2644 break;
2645 case V4L2_CID_AUDIO_MUTE:
2646 radio->mute_mode.hard_mute = ctrl->value;
2647 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
2648 retval = hci_set_fm_mute_mode(
2649 &radio->mute_mode,
2650 radio->fm_hdev);
2651 if (retval < 0)
2652 FMDERR("Error while set FM hard mute"" %d\n",
2653 retval);
2654 break;
2655 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2656 radio->g_search_mode = ctrl->value;
2657 break;
2658 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2659 radio->g_scan_time = ctrl->value;
2660 break;
2661 case V4L2_CID_PRIVATE_IRIS_SRCHON:
2662 iris_search(radio, ctrl->value, SRCH_DIR_UP);
2663 break;
2664 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002665 switch (ctrl->value) {
2666 case FM_RECV:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2668 radio->fm_hdev);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302669 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002670 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002671 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302672 return retval;
2673 }
2674 radio->mode = FM_RECV;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002675 radio->mute_mode.soft_mute = CTRL_ON;
2676 retval = hci_set_fm_mute_mode(
2677 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302679 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002680 FMDERR("Failed to enable Smute\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302681 return retval;
2682 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002683 radio->stereo_mode.stereo_mode = CTRL_OFF;
2684 radio->stereo_mode.sig_blend = CTRL_ON;
2685 radio->stereo_mode.intf_blend = CTRL_ON;
2686 radio->stereo_mode.most_switch = CTRL_ON;
2687 retval = hci_set_fm_stereo_mode(
2688 &radio->stereo_mode,
2689 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302690 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002691 FMDERR("Failed to set stereo mode\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302692 return retval;
2693 }
Srinivasa Rao Uppalaf1febce2011-11-09 10:30:16 +05302694 radio->event_mask = SIG_LEVEL_INTR |
2695 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2696 retval = hci_conf_event_mask(&radio->event_mask,
2697 radio->fm_hdev);
2698 if (retval < 0) {
2699 FMDERR("Enable Async events failed");
2700 return retval;
2701 }
Srinivasa Rao Uppalaf0d13742011-09-08 10:13:13 +05302702 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2703 radio->fm_hdev);
2704 if (retval < 0)
2705 FMDERR("Failed to get the Recv Config\n");
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002706 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002707 case FM_TRANS:
2708 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
2709 radio->fm_hdev);
2710 radio->mode = FM_TRANS;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302711 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002712 FMDERR("Error while enabling TRANS FM"
2713 " %d\n", retval);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302714 return retval;
2715 }
2716 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
2717 if (retval < 0)
2718 FMDERR("get frequency failed %d\n", retval);
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002719 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002720 case FM_OFF:
2721 switch (radio->mode) {
2722 case FM_RECV:
2723 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2724 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002725 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002726 FMDERR("Err on disable recv FM"
2727 " %d\n", retval);
2728 break;
2729 case FM_TRANS:
2730 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
2731 radio->fm_hdev);
2732
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002733 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002734 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002735 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002736 break;
2737 default:
2738 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002739 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302740 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002741 default:
2742 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002743 }
2744 break;
2745 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002746 if (radio->mode == FM_RECV) {
2747 retval = iris_recv_set_region(radio, ctrl->value);
2748 } else {
2749 if (radio->mode == FM_TRANS)
2750 retval = iris_trans_set_region(radio,
2751 ctrl->value);
2752 else
2753 retval = -EINVAL;
2754 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002755 break;
2756 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2757 temp_val = ctrl->value;
2758 retval = hci_fm_set_signal_threshold(
2759 &temp_val,
2760 radio->fm_hdev);
2761 if (retval < 0) {
2762 FMDERR("Error while setting signal threshold\n");
2763 break;
2764 }
2765 break;
2766 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
2767 radio->srch_rds.srch_pty = ctrl->value;
2768 radio->srch_st_list.srch_pty = ctrl->value;
2769 break;
2770 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
2771 radio->srch_rds.srch_pi = ctrl->value;
2772 break;
2773 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
2774 break;
2775 case V4L2_CID_PRIVATE_IRIS_SPACING:
Venkateshwarlu Domakonda45496f12011-11-23 12:51:13 +05302776 if (radio->mode == FM_RECV) {
2777 radio->recv_conf.ch_spacing = ctrl->value;
2778 retval = hci_set_fm_recv_conf(
2779 &radio->recv_conf,
2780 radio->fm_hdev);
2781 if (retval < 0)
2782 FMDERR("Error in setting channel spacing");
2783 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002784 break;
2785 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002786 switch (radio->mode) {
2787 case FM_RECV:
2788 radio->recv_conf.emphasis = ctrl->value;
2789 retval = hci_set_fm_recv_conf(
2790 &radio->recv_conf,
2791 radio->fm_hdev);
2792 if (retval < 0)
2793 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002794 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002795 case FM_TRANS:
2796 radio->trans_conf.emphasis = ctrl->value;
2797 retval = hci_set_fm_trans_conf(
2798 &radio->trans_conf,
2799 radio->fm_hdev);
2800 if (retval < 0)
2801 FMDERR("Error in setting emphasis");
2802 break;
2803 default:
2804 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002805 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806 break;
2807 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002808 switch (radio->mode) {
2809 case FM_RECV:
2810 radio->recv_conf.rds_std = ctrl->value;
2811 retval = hci_set_fm_recv_conf(
2812 &radio->recv_conf,
2813 radio->fm_hdev);
2814 if (retval < 0)
2815 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002816 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002817 case FM_TRANS:
2818 radio->trans_conf.rds_std = ctrl->value;
2819 retval = hci_set_fm_trans_conf(
2820 &radio->trans_conf,
2821 radio->fm_hdev);
2822 if (retval < 0)
2823 FMDERR("Error in rds_Std");
2824 break;
2825 default:
2826 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002827 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002828 break;
2829 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002830 switch (radio->mode) {
2831 case FM_RECV:
2832 radio->recv_conf.rds_std = ctrl->value;
2833 retval = hci_set_fm_recv_conf(
2834 &radio->recv_conf,
2835 radio->fm_hdev);
2836 if (retval < 0)
2837 FMDERR("Error in rds_std");
2838 break;
2839 case FM_TRANS:
2840 radio->trans_conf.rds_std = ctrl->value;
2841 retval = hci_set_fm_trans_conf(
2842 &radio->trans_conf,
2843 radio->fm_hdev);
2844 if (retval < 0)
2845 FMDERR("Error in rds_Std");
2846 break;
2847 default:
2848 retval = -EINVAL;
2849 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002850 break;
2851 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2852 radio->rds_grp.rds_grp_enable_mask = ctrl->value;
2853 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
2854 break;
2855 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
2856 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002857 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002858 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002859 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860 radio->fm_hdev);
2861 break;
2862 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2863 radio->rds_grp.rds_buf_size = ctrl->value;
2864 break;
2865 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002866 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
2867 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2868 retval = hci_fm_rds_grps_process(
2869 &radio->g_rds_grp_proc_ps,
2870 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002871 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302872 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
2873 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_OFFSET);
2874 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2875 retval = hci_fm_rds_grps_process(
2876 &radio->g_rds_grp_proc_ps,
2877 radio->fm_hdev);
2878 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302880 set_low_power_mode(radio, ctrl->value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002881 break;
2882 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2883 temp_val = ctrl->value;
2884 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
2885 break;
2886 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002887 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002888 break;
2889 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002890 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891 break;
2892 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302893 tx_ps.ps_control = 0x00;
2894 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2895 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002896 break;
2897 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302898 tx_rt.rt_control = 0x00;
2899 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2900 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901 break;
2902 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002903 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002904 break;
2905 case V4L2_CID_TUNE_POWER_LEVEL:
2906 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002907 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2908 radio->mute_mode.soft_mute = ctrl->value;
2909 retval = hci_set_fm_mute_mode(
2910 &radio->mute_mode,
2911 radio->fm_hdev);
2912 if (retval < 0)
2913 FMDERR("Error while setting FM soft mute"" %d\n",
2914 retval);
2915 break;
2916 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
2917 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
2918 break;
2919 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
2920 radio->riva_data_req.cmd_params.length = ctrl->value;
2921 break;
2922 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
2923 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
2924 radio->riva_data_req.cmd_params.length);
2925 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
2926 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
2927 break;
2928 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
2929 radio->ssbi_data_accs.start_addr = ctrl->value;
2930 break;
2931 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
2932 radio->ssbi_data_accs.data = ctrl->value;
2933 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
2934 radio->fm_hdev);
2935 break;
2936 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
2937 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
2938 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
2939 radio->fm_hdev);
2940 break;
2941 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
2942 radio->ssbi_peek_reg.start_address = ctrl->value;
2943 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
2944 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302945 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
2946 temp_val = ctrl->value;
2947 hci_read_grp_counters(&temp_val, radio->fm_hdev);
2948 break;
2949 case V4L2_CID_PRIVATE_IRIS_HLSI:
2950 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2951 radio->fm_hdev);
2952 if (retval)
2953 break;
2954 radio->recv_conf.hlsi = ctrl->value;
2955 retval = hci_set_fm_recv_conf(
2956 &radio->recv_conf,
2957 radio->fm_hdev);
2958 break;
2959 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
2960 temp_val = ctrl->value;
2961 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
2962 break;
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05302963 case V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM:
2964 /*
2965 This private control is a place holder to keep the
2966 driver compatible with changes done in the frameworks
2967 which are specific to TAVARUA.
2968 */
2969 retval = 0;
2970 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971 default:
2972 retval = -EINVAL;
2973 }
2974 return retval;
2975}
2976
2977static int iris_vidioc_g_tuner(struct file *file, void *priv,
2978 struct v4l2_tuner *tuner)
2979{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002981 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002982 if (tuner->index > 0)
2983 return -EINVAL;
2984
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302985 if (radio->mode == FM_RECV) {
2986 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
2987 if (retval < 0) {
2988 FMDERR("Failed to Get station params");
2989 return retval;
2990 }
2991 tuner->type = V4L2_TUNER_RADIO;
2992 tuner->rangelow =
2993 radio->recv_conf.band_low_limit * TUNE_PARAM;
2994 tuner->rangehigh =
2995 radio->recv_conf.band_high_limit * TUNE_PARAM;
2996 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
2997 tuner->capability = V4L2_TUNER_CAP_LOW;
2998 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
2999 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
3000 tuner->afc = 0;
3001 } else if (radio->mode == FM_TRANS) {
3002 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
3003 if (retval < 0) {
3004 FMDERR("get Tx config failed %d\n", retval);
3005 return retval;
3006 } else {
3007 tuner->type = V4L2_TUNER_RADIO;
3008 tuner->rangelow =
3009 radio->trans_conf.band_low_limit * TUNE_PARAM;
3010 tuner->rangehigh =
3011 radio->trans_conf.band_high_limit * TUNE_PARAM;
3012 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303014 } else
3015 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003016 return 0;
3017}
3018
3019static int iris_vidioc_s_tuner(struct file *file, void *priv,
3020 struct v4l2_tuner *tuner)
3021{
3022 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07003023 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003024 if (tuner->index > 0)
3025 return -EINVAL;
3026
Ankur Nandwanid928d542011-08-11 13:15:41 -07003027 if (radio->mode == FM_RECV) {
3028 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
3029 radio->recv_conf.band_high_limit =
3030 tuner->rangehigh / TUNE_PARAM;
3031 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
3032 radio->stereo_mode.stereo_mode = 0x01;
3033 retval = hci_set_fm_stereo_mode(
3034 &radio->stereo_mode,
3035 radio->fm_hdev);
3036 } else {
3037 radio->stereo_mode.stereo_mode = 0x00;
3038 retval = hci_set_fm_stereo_mode(
3039 &radio->stereo_mode,
3040 radio->fm_hdev);
3041 }
3042 if (retval < 0)
3043 FMDERR(": set tuner failed with %d\n", retval);
3044 return retval;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303045 } else if (radio->mode == FM_TRANS) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003046 radio->trans_conf.band_low_limit =
3047 tuner->rangelow / TUNE_PARAM;
3048 radio->trans_conf.band_high_limit =
3049 tuner->rangehigh / TUNE_PARAM;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303050 } else
3051 return -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003052
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003053 return retval;
3054}
3055
3056static int iris_vidioc_g_frequency(struct file *file, void *priv,
3057 struct v4l2_frequency *freq)
3058{
3059 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3060 int retval;
3061
3062 freq->type = V4L2_TUNER_RADIO;
3063 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3064 if (retval < 0)
3065 FMDERR("get frequency failed %d\n", retval);
3066 else
3067 freq->frequency =
3068 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
3069 return retval;
3070}
3071
3072static int iris_vidioc_s_frequency(struct file *file, void *priv,
3073 struct v4l2_frequency *freq)
3074{
3075 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3076 int retval = -1;
3077 freq->frequency = freq->frequency / TUNE_PARAM;
3078
3079 if (freq->type != V4L2_TUNER_RADIO)
3080 return -EINVAL;
3081
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003082 /* We turn off RDS prior to tuning to a new station.
3083 because of a bug in SoC which prevents tuning
3084 during RDS transmission.
3085 */
3086 if (radio->mode == FM_TRANS
3087 && (radio->trans_conf.rds_std == 0 ||
3088 radio->trans_conf.rds_std == 1)) {
3089 radio->prev_trans_rds = radio->trans_conf.rds_std;
3090 radio->trans_conf.rds_std = 2;
3091 hci_set_fm_trans_conf(&radio->trans_conf,
3092 radio->fm_hdev);
3093 }
3094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003095 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003096
3097 if (radio->mode == FM_TRANS
3098 && radio->trans_conf.rds_std == 2
3099 && (radio->prev_trans_rds == 1
3100 || radio->prev_trans_rds == 0)) {
3101 radio->trans_conf.rds_std = radio->prev_trans_rds;
3102 hci_set_fm_trans_conf(&radio->trans_conf,
3103 radio->fm_hdev);
3104 }
3105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106 if (retval < 0)
3107 FMDERR(" set frequency failed with %d\n", retval);
3108 return retval;
3109}
3110
3111static int iris_vidioc_dqbuf(struct file *file, void *priv,
3112 struct v4l2_buffer *buffer)
3113{
3114 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3115 enum iris_buf_t buf_type = buffer->index;
3116 struct kfifo *data_fifo;
3117 unsigned char *buf = (unsigned char *)buffer->m.userptr;
3118 unsigned int len = buffer->length;
3119 if (!access_ok(VERIFY_WRITE, buf, len))
3120 return -EFAULT;
3121 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
3122 data_fifo = &radio->data_buf[buf_type];
3123 if (buf_type == IRIS_BUF_EVENTS)
3124 if (wait_event_interruptible(radio->event_queue,
3125 kfifo_len(data_fifo)) < 0)
3126 return -EINTR;
3127 } else {
3128 FMDERR("invalid buffer type\n");
3129 return -EINVAL;
3130 }
3131 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3132 &radio->buf_lock[buf_type]);
3133
3134 return 0;
3135}
3136
3137static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
3138 struct v4l2_format *f)
3139{
3140 return 0;
3141
3142}
3143
3144static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3145 struct v4l2_hw_freq_seek *seek)
3146{
3147 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3148 int dir;
3149 if (seek->seek_upward)
3150 dir = SRCH_DIR_UP;
3151 else
3152 dir = SRCH_DIR_DOWN;
3153 return iris_search(radio, CTRL_ON, dir);
3154}
3155
3156static int iris_vidioc_querycap(struct file *file, void *priv,
3157 struct v4l2_capability *capability)
3158{
3159 struct iris_device *radio;
3160 radio = video_get_drvdata(video_devdata(file));
3161 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
3162 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
3163 radio->g_cap = capability;
3164 return 0;
3165}
3166
3167
3168static const struct v4l2_ioctl_ops iris_ioctl_ops = {
3169 .vidioc_querycap = iris_vidioc_querycap,
3170 .vidioc_queryctrl = iris_vidioc_queryctrl,
3171 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
3172 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
3173 .vidioc_g_tuner = iris_vidioc_g_tuner,
3174 .vidioc_s_tuner = iris_vidioc_s_tuner,
3175 .vidioc_g_frequency = iris_vidioc_g_frequency,
3176 .vidioc_s_frequency = iris_vidioc_s_frequency,
3177 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
3178 .vidioc_dqbuf = iris_vidioc_dqbuf,
3179 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
3180 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303181 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003182};
3183
3184static const struct v4l2_file_operations iris_fops = {
3185 .owner = THIS_MODULE,
3186 .unlocked_ioctl = video_ioctl2,
3187};
3188
3189static struct video_device iris_viddev_template = {
3190 .fops = &iris_fops,
3191 .ioctl_ops = &iris_ioctl_ops,
3192 .name = DRIVER_NAME,
3193 .release = video_device_release,
3194};
3195
3196static struct video_device *video_get_dev(void)
3197{
3198 return priv_videodev;
3199}
3200
3201static int __init iris_probe(struct platform_device *pdev)
3202{
3203 struct iris_device *radio;
3204 int retval;
3205 int radio_nr = -1;
3206 int i;
3207
3208 if (!pdev) {
3209 FMDERR(": pdev is null\n");
3210 return -ENOMEM;
3211 }
3212
3213 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
3214 if (!radio) {
3215 FMDERR(": Could not allocate radio device\n");
3216 return -ENOMEM;
3217 }
3218
3219 radio->dev = &pdev->dev;
3220 platform_set_drvdata(pdev, radio);
3221
3222 radio->videodev = video_device_alloc();
3223 if (!radio->videodev) {
3224 FMDERR(": Could not allocate V4L device\n");
3225 kfree(radio);
3226 return -ENOMEM;
3227 }
3228
3229 memcpy(radio->videodev, &iris_viddev_template,
3230 sizeof(iris_viddev_template));
3231
3232 for (i = 0; i < IRIS_BUF_MAX; i++) {
3233 int kfifo_alloc_rc = 0;
3234 spin_lock_init(&radio->buf_lock[i]);
3235
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07003236 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003237 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3238 rds_buf*3, GFP_KERNEL);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05303239 else if (i == IRIS_BUF_CAL_DATA)
3240 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3241 STD_BUF_SIZE*2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 else
3243 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3244 STD_BUF_SIZE, GFP_KERNEL);
3245
3246 if (kfifo_alloc_rc != 0) {
3247 FMDERR("failed allocating buffers %d\n",
3248 kfifo_alloc_rc);
3249 for (; i > -1; i--) {
3250 kfifo_free(&radio->data_buf[i]);
3251 kfree(radio);
3252 return -ENOMEM;
3253 }
3254 }
3255 }
3256
3257 mutex_init(&radio->lock);
3258 init_completion(&radio->sync_xfr_start);
3259 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003260 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003261 init_waitqueue_head(&radio->event_queue);
3262 init_waitqueue_head(&radio->read_queue);
3263
3264 video_set_drvdata(radio->videodev, radio);
3265
3266 if (NULL == video_get_drvdata(radio->videodev))
3267 FMDERR(": video_get_drvdata failed\n");
3268
3269 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
3270 radio_nr);
3271 if (retval) {
3272 FMDERR(": Could not register video device\n");
3273 video_device_release(radio->videodev);
3274 for (; i > -1; i--)
3275 kfifo_free(&radio->data_buf[i]);
3276 kfree(radio);
3277 return retval;
3278 } else {
3279 priv_videodev = kzalloc(sizeof(struct video_device),
3280 GFP_KERNEL);
3281 memcpy(priv_videodev, radio->videodev,
3282 sizeof(struct video_device));
3283 }
3284 return 0;
3285}
3286
3287
3288static int __devexit iris_remove(struct platform_device *pdev)
3289{
3290 int i;
3291 struct iris_device *radio = platform_get_drvdata(pdev);
3292
3293 video_unregister_device(radio->videodev);
3294
3295 for (i = 0; i < IRIS_BUF_MAX; i++)
3296 kfifo_free(&radio->data_buf[i]);
3297
3298 kfree(radio);
3299
3300 platform_set_drvdata(pdev, NULL);
3301
3302 return 0;
3303}
3304
3305static struct platform_driver iris_driver = {
3306 .driver = {
3307 .owner = THIS_MODULE,
3308 .name = "iris_fm",
3309 },
3310 .remove = __devexit_p(iris_remove),
3311};
3312
3313static int __init iris_radio_init(void)
3314{
3315 return platform_driver_probe(&iris_driver, iris_probe);
3316}
3317module_init(iris_radio_init);
3318
3319static void __exit iris_radio_exit(void)
3320{
3321 platform_driver_unregister(&iris_driver);
3322}
3323module_exit(iris_radio_exit);
3324
3325MODULE_LICENSE("GPL v2");
3326MODULE_AUTHOR(DRIVER_AUTHOR);
3327MODULE_DESCRIPTION(DRIVER_DESC);