blob: 2d42e17a94616055049123b17c4f6a17c92274e0 [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
651static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
652 unsigned long param)
653{
654 __u16 opcode = 0;
655
656 struct hci_fm_recv_conf_req *recv_conf_req =
657 (struct hci_fm_recv_conf_req *) param;
658
659 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
660 HCI_OCF_FM_SET_RECV_CONF_REQ);
661 return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
662 recv_conf_req);
663}
664
Ankur Nandwanid928d542011-08-11 13:15:41 -0700665static int hci_set_fm_trans_conf_req(struct radio_hci_dev *hdev,
666 unsigned long param)
667{
668 __u16 opcode = 0;
669
670 struct hci_fm_trans_conf_req_struct *trans_conf_req =
671 (struct hci_fm_trans_conf_req_struct *) param;
672
673 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
674 HCI_OCF_FM_SET_TRANS_CONF_REQ);
675 return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
676 trans_conf_req);
677}
678
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
680 unsigned long param)
681{
682 __u16 opcode = 0;
683
684 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
685 HCI_OCF_FM_GET_STATION_PARAM_REQ);
686 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
687}
688
689static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
690 unsigned long param)
691{
692 __u16 opcode = 0;
693 struct hci_fm_mute_mode_req *mute_mode_req =
694 (struct hci_fm_mute_mode_req *) param;
695
696 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
697 HCI_OCF_FM_SET_MUTE_MODE_REQ);
698 return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
699 mute_mode_req);
700}
701
Ankur Nandwanid928d542011-08-11 13:15:41 -0700702
703static int hci_trans_ps_req(struct radio_hci_dev *hdev,
704 unsigned long param)
705{
706 __u16 opcode = 0;
707 struct hci_fm_tx_ps *tx_ps_req =
708 (struct hci_fm_tx_ps *) param;
709
710 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
711 HCI_OCF_FM_RDS_PS_REQ);
712
713 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_ps_req)),
714 tx_ps_req);
715}
716
717static int hci_trans_rt_req(struct radio_hci_dev *hdev,
718 unsigned long param)
719{
720 __u16 opcode = 0;
721 struct hci_fm_tx_rt *tx_rt_req =
722 (struct hci_fm_tx_rt *) param;
723
724 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
725 HCI_OCF_FM_RDS_RT_REQ);
726
727 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_rt_req)),
728 tx_rt_req);
729}
730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
732 unsigned long param)
733{
734 __u16 opcode = 0;
735 struct hci_fm_stereo_mode_req *stereo_mode_req =
736 (struct hci_fm_stereo_mode_req *) param;
737 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
738 HCI_OCF_FM_SET_STEREO_MODE_REQ);
739 return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
740 stereo_mode_req);
741}
742
743static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
744 unsigned long param)
745{
746 __u16 opcode = 0;
747
748 __u8 antenna = param;
749
750 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
751 HCI_OCF_FM_SET_ANTENNA);
752 return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
753}
754
755static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
756 unsigned long param)
757{
758 __u16 opcode = 0;
759
760 __u8 sig_threshold = param;
761
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530762 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763 HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
764 return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
765 &sig_threshold);
766}
767
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +0530768static int hci_fm_set_event_mask(struct radio_hci_dev *hdev,
769 unsigned long param)
770{
771 u16 opcode = 0;
772 u8 event_mask = param;
773
774 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
775 HCI_OCF_FM_SET_EVENT_MASK);
776 return radio_hci_send_cmd(hdev, opcode, sizeof(event_mask),
777 &event_mask);
778}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
780 unsigned long param)
781{
782 __u16 opcode = 0;
783
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530784 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700785 HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
786 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
787}
788
789static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
790 unsigned long param)
791{
792 __u16 opcode = 0;
793
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530794 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795 HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
796 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
797}
798
799static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
800 unsigned long param)
801{
802 __u16 opcode = 0;
803
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530804 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805 HCI_OCF_FM_GET_RADIO_TEXT_REQ);
806 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
807}
808
809static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
810 unsigned long param)
811{
812 __u16 opcode = 0;
813
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530814 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700815 HCI_OCF_FM_GET_AF_LIST_REQ);
816 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
817}
818
819static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
820 unsigned long param)
821{
822 __u16 opcode = 0;
823 struct hci_fm_search_station_req *srch_stations =
824 (struct hci_fm_search_station_req *) param;
825
826 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
827 HCI_OCF_FM_SEARCH_STATIONS);
828 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
829 srch_stations);
830}
831
832static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
833 unsigned long param)
834{
835 __u16 opcode = 0;
836 struct hci_fm_search_rds_station_req *srch_stations =
837 (struct hci_fm_search_rds_station_req *) param;
838
839 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
840 HCI_OCF_FM_SEARCH_RDS_STATIONS);
841 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
842 srch_stations);
843}
844
845static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
846 unsigned long param)
847{
848 __u16 opcode = 0;
849 struct hci_fm_search_station_list_req *srch_list =
850 (struct hci_fm_search_station_list_req *) param;
851
852 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
853 HCI_OCF_FM_SEARCH_STATIONS_LIST);
854 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
855 srch_list);
856}
857
858static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
859 unsigned long param)
860{
861 __u16 opcode = 0;
862
863 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
864 HCI_OCF_FM_CANCEL_SEARCH);
865 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
866}
867
868static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
869 unsigned long param)
870{
871 __u16 opcode = 0;
872
873 __u32 fm_grps_process = param;
874
875 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
876 HCI_OCF_FM_RDS_GRP_PROCESS);
877 return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
878 &fm_grps_process);
879}
880
881static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
882 unsigned long param)
883{
884 __u16 opcode = 0;
885
886 __u32 tune_freq = param;
887
888 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
889 HCI_OCF_FM_TUNE_STATION_REQ);
890 return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
891}
892
893static int hci_def_data_read_req(struct radio_hci_dev *hdev,
894 unsigned long param)
895{
896 __u16 opcode = 0;
897 struct hci_fm_def_data_rd_req *def_data_rd =
898 (struct hci_fm_def_data_rd_req *) param;
899
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530900 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 HCI_OCF_FM_DEFAULT_DATA_READ);
902 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
903 def_data_rd);
904}
905
906static int hci_def_data_write_req(struct radio_hci_dev *hdev,
907 unsigned long param)
908{
909 __u16 opcode = 0;
910 struct hci_fm_def_data_wr_req *def_data_wr =
911 (struct hci_fm_def_data_wr_req *) param;
912
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530913 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700914 HCI_OCF_FM_DEFAULT_DATA_WRITE);
915 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
916 def_data_wr);
917}
918
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530919static int hci_set_notch_filter_req(struct radio_hci_dev *hdev,
920 unsigned long param)
921{
922 __u16 opcode = 0;
923 __u8 notch_filter_val = param;
924
925 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
926 HCI_OCF_FM_EN_NOTCH_CTRL);
927 return radio_hci_send_cmd(hdev, opcode, sizeof(notch_filter_val),
928 &notch_filter_val);
929}
930
931
932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
934{
935 __u16 opcode = 0;
936
937 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
938 HCI_OCF_FM_RESET);
939 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
940}
941
942static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
943 unsigned long param)
944{
945 __u16 opcode = 0;
946
947 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
948 HCI_OCF_FM_GET_FEATURE_LIST);
949 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
950}
951
952static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
953 unsigned long param)
954{
955 __u16 opcode = 0;
956
957 __u8 mode = param;
958
959 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
960 HCI_OCF_FM_DO_CALIBRATION);
961 return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
962}
963
964static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
965 unsigned long param)
966{
967 __u16 opcode = 0;
968
969 __u8 reset_counters = param;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530970 opcode = hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 HCI_OCF_FM_READ_GRP_COUNTERS);
972 return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
973 &reset_counters);
974}
975
976static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
977{
978 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700979 struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700980
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700981 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982 HCI_OCF_FM_PEEK_DATA);
983 return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
984 peek_data);
985}
986
987static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
988{
989 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700990 struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -0700992 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 HCI_OCF_FM_POKE_DATA);
994 return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
995 poke_data);
996}
997
998static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
999 unsigned long param)
1000{
1001 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001002 struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001004 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 HCI_OCF_FM_SSBI_PEEK_REG);
1006 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
1007 ssbi_peek);
1008}
1009
1010static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
1011 unsigned long param)
1012{
1013 __u16 opcode = 0;
1014 struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
1015
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001016 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017 HCI_OCF_FM_SSBI_POKE_REG);
1018 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
1019 ssbi_poke);
1020}
1021
1022static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
1023 unsigned long param)
1024{
1025 __u16 opcode = 0;
1026
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +05301027 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 HCI_OCF_FM_STATION_DBG_PARAM);
1029 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1030}
1031
1032static int radio_hci_err(__u16 code)
1033{
1034 switch (code) {
1035 case 0:
1036 return 0;
1037 case 0x01:
1038 return -EBADRQC;
1039 case 0x02:
1040 return -ENOTCONN;
1041 case 0x03:
1042 return -EIO;
1043 case 0x07:
1044 return -ENOMEM;
1045 case 0x0c:
1046 return -EBUSY;
1047 case 0x11:
1048 return -EOPNOTSUPP;
1049 case 0x12:
1050 return -EINVAL;
1051 default:
1052 return -ENOSYS;
1053 }
1054}
1055
1056static int __radio_hci_request(struct radio_hci_dev *hdev,
1057 int (*req)(struct radio_hci_dev *hdev,
1058 unsigned long param),
1059 unsigned long param, __u32 timeout)
1060{
1061 int err = 0;
1062
1063 DECLARE_WAITQUEUE(wait, current);
1064
1065 hdev->req_status = HCI_REQ_PEND;
1066
1067 add_wait_queue(&hdev->req_wait_q, &wait);
1068 set_current_state(TASK_INTERRUPTIBLE);
1069
1070 err = req(hdev, param);
1071
1072 schedule_timeout(timeout);
1073
1074 remove_wait_queue(&hdev->req_wait_q, &wait);
1075
1076 if (signal_pending(current))
1077 return -EINTR;
1078
1079 switch (hdev->req_status) {
1080 case HCI_REQ_DONE:
1081 case HCI_REQ_STATUS:
1082 err = radio_hci_err(hdev->req_result);
1083 break;
1084
1085 case HCI_REQ_CANCELED:
1086 err = -hdev->req_result;
1087 break;
1088
1089 default:
1090 err = -ETIMEDOUT;
1091 break;
1092 }
1093
1094 hdev->req_status = hdev->req_result = 0;
1095
1096 return err;
1097}
1098
1099static inline int radio_hci_request(struct radio_hci_dev *hdev,
1100 int (*req)(struct
1101 radio_hci_dev * hdev, unsigned long param),
1102 unsigned long param, __u32 timeout)
1103{
1104 int ret = 0;
1105
1106 ret = __radio_hci_request(hdev, req, param, timeout);
1107
1108 return ret;
1109}
1110
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301111static inline int hci_conf_event_mask(__u8 *arg,
1112 struct radio_hci_dev *hdev)
1113{
1114 u8 event_mask = *arg;
1115 return radio_hci_request(hdev, hci_fm_set_event_mask,
1116 event_mask, RADIO_HCI_TIMEOUT);
1117}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
1119 struct radio_hci_dev *hdev)
1120{
1121 int ret = 0;
1122 struct hci_fm_recv_conf_req *set_recv_conf = arg;
1123
1124 ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
1125 long)set_recv_conf, RADIO_HCI_TIMEOUT);
1126
1127 return ret;
1128}
1129
Ankur Nandwanid928d542011-08-11 13:15:41 -07001130static int hci_set_fm_trans_conf(struct hci_fm_trans_conf_req_struct *arg,
1131 struct radio_hci_dev *hdev)
1132{
1133 int ret = 0;
1134 struct hci_fm_trans_conf_req_struct *set_trans_conf = arg;
1135
1136 ret = radio_hci_request(hdev, hci_set_fm_trans_conf_req, (unsigned
1137 long)set_trans_conf, RADIO_HCI_TIMEOUT);
1138
1139 return ret;
1140}
1141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
1143{
1144 int ret = 0;
1145 __u32 tune_freq = *arg;
1146
1147 ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
1148 RADIO_HCI_TIMEOUT);
1149
1150 return ret;
1151}
1152
1153static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
1154 struct radio_hci_dev *hdev)
1155{
1156 int ret = 0;
1157 struct hci_fm_mute_mode_req *set_mute_conf = arg;
1158
1159 ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
1160 long)set_mute_conf, RADIO_HCI_TIMEOUT);
1161
1162 return ret;
1163}
1164
1165static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
1166 struct radio_hci_dev *hdev)
1167{
1168 int ret = 0;
1169 struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
1170
1171 ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
1172 long)set_stereo_conf, RADIO_HCI_TIMEOUT);
1173
1174 return ret;
1175}
1176
1177static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
1178{
1179 int ret = 0;
1180 __u8 antenna = *arg;
1181
1182 ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
1183 RADIO_HCI_TIMEOUT);
1184
1185 return ret;
1186}
1187
1188static int hci_fm_set_signal_threshold(__u8 *arg,
1189 struct radio_hci_dev *hdev)
1190{
1191 int ret = 0;
1192 __u8 sig_threshold = *arg;
1193
1194 ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
1195 sig_threshold, RADIO_HCI_TIMEOUT);
1196
1197 return ret;
1198}
1199
1200static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
1201 struct radio_hci_dev *hdev)
1202{
1203 int ret = 0;
1204 struct hci_fm_search_station_req *srch_stations = arg;
1205
1206 ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
1207 long)srch_stations, RADIO_HCI_TIMEOUT);
1208
1209 return ret;
1210}
1211
1212static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
1213 struct radio_hci_dev *hdev)
1214{
1215 int ret = 0;
1216 struct hci_fm_search_rds_station_req *srch_stations = arg;
1217
1218 ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
1219 long)srch_stations, RADIO_HCI_TIMEOUT);
1220
1221 return ret;
1222}
1223
1224static int hci_fm_search_station_list
1225 (struct hci_fm_search_station_list_req *arg,
1226 struct radio_hci_dev *hdev)
1227{
1228 int ret = 0;
1229 struct hci_fm_search_station_list_req *srch_list = arg;
1230
1231 ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
1232 long)srch_list, RADIO_HCI_TIMEOUT);
1233
1234 return ret;
1235}
1236
1237static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
1238 struct radio_hci_dev *hdev)
1239{
1240 return 0;
1241}
1242
1243static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
1244{
1245 int ret = 0;
1246 __u32 fm_grps_process = *arg;
1247
1248 ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
1249 fm_grps_process, RADIO_HCI_TIMEOUT);
1250
1251 return ret;
1252}
1253
1254int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
1255 struct radio_hci_dev *hdev)
1256{
1257 int ret = 0;
1258 struct hci_fm_def_data_rd_req *def_data_rd = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
1260 long)def_data_rd, RADIO_HCI_TIMEOUT);
1261
1262 return ret;
1263}
1264
1265int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
1266 struct radio_hci_dev *hdev)
1267{
1268 int ret = 0;
1269 struct hci_fm_def_data_wr_req *def_data_wr = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
1271 long)def_data_wr, RADIO_HCI_TIMEOUT);
1272
1273 return ret;
1274}
1275
1276int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
1277{
1278 int ret = 0;
1279 __u8 mode = *arg;
1280
1281 ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
1282 RADIO_HCI_TIMEOUT);
1283
1284 return ret;
1285}
1286
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301287static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001288{
1289 int ret = 0;
1290 __u8 reset_counters = *arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 ret = radio_hci_request(hdev, hci_read_grp_counters_req,
1292 reset_counters, RADIO_HCI_TIMEOUT);
1293
1294 return ret;
1295}
1296
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301297static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
1298{
1299 int ret = 0;
1300 __u8 notch_filter = *arg;
1301 ret = radio_hci_request(hdev, hci_set_notch_filter_req,
1302 notch_filter, RADIO_HCI_TIMEOUT);
1303
1304 return ret;
1305}
1306
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001307static int hci_peek_data(struct hci_fm_riva_data *arg,
1308 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309{
1310 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001311 struct hci_fm_riva_data *peek_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312
1313 ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
1314 long)peek_data, RADIO_HCI_TIMEOUT);
1315
1316 return ret;
1317}
1318
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001319static int hci_poke_data(struct hci_fm_riva_poke *arg,
1320 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321{
1322 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001323 struct hci_fm_riva_poke *poke_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324
1325 ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
1326 long)poke_data, RADIO_HCI_TIMEOUT);
1327
1328 return ret;
1329}
1330
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001331static int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *arg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001332 struct radio_hci_dev *hdev)
1333{
1334 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001335 struct hci_fm_ssbi_peek *ssbi_peek_reg = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336
1337 ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
1338 long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
1339
1340 return ret;
1341}
1342
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001343static int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg,
1344 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345{
1346 int ret = 0;
1347 struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
1348
1349 ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
1350 long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
1351
1352 return ret;
1353}
1354
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301355static int hci_fm_set_cal_req(struct radio_hci_dev *hdev,
1356 unsigned long param)
1357{
1358 u16 opcode = 0;
1359 struct hci_fm_set_cal_req *cal_req =
1360 (struct hci_fm_set_cal_req *)param;
1361
1362 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1363 HCI_OCF_FM_SET_CALIBRATION);
1364 return radio_hci_send_cmd(hdev, opcode, sizeof((*hci_fm_set_cal_req)),
1365 cal_req);
1366
1367}
1368
1369static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
1370 unsigned long param)
1371{
1372 u16 opcode = 0;
1373 u8 cal_mode = param;
1374
1375 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1376 HCI_OCF_FM_DO_CALIBRATION);
1377 return radio_hci_send_cmd(hdev, opcode, sizeof(cal_mode),
1378 &cal_mode);
1379
1380}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1382{
1383 int ret = 0;
1384 unsigned long arg = 0;
1385
Ankur Nandwanid928d542011-08-11 13:15:41 -07001386 if (!hdev)
1387 return -ENODEV;
1388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 switch (cmd) {
1390 case HCI_FM_ENABLE_RECV_CMD:
1391 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1392 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1393 break;
1394
1395 case HCI_FM_DISABLE_RECV_CMD:
1396 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1397 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1398 break;
1399
1400 case HCI_FM_GET_RECV_CONF_CMD:
1401 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1402 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1403 break;
1404
1405 case HCI_FM_GET_STATION_PARAM_CMD:
1406 ret = radio_hci_request(hdev,
1407 hci_fm_get_station_param_req, arg,
1408 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1409 break;
1410
1411 case HCI_FM_GET_SIGNAL_TH_CMD:
1412 ret = radio_hci_request(hdev,
1413 hci_fm_get_sig_threshold_req, arg,
1414 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1415 break;
1416
1417 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1418 ret = radio_hci_request(hdev,
1419 hci_fm_get_program_service_req, arg,
1420 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1421 break;
1422
1423 case HCI_FM_GET_RADIO_TEXT_CMD:
1424 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1425 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1426 break;
1427
1428 case HCI_FM_GET_AF_LIST_CMD:
1429 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1430 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1431 break;
1432
1433 case HCI_FM_CANCEL_SEARCH_CMD:
1434 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1435 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1436 break;
1437
1438 case HCI_FM_RESET_CMD:
1439 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1440 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1441 break;
1442
1443 case HCI_FM_GET_FEATURES_CMD:
1444 ret = radio_hci_request(hdev,
1445 hci_fm_get_feature_lists_req, arg,
1446 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1447 break;
1448
1449 case HCI_FM_STATION_DBG_PARAM_CMD:
1450 ret = radio_hci_request(hdev,
1451 hci_fm_get_station_dbg_param_req, arg,
1452 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1453 break;
1454
Ankur Nandwanid928d542011-08-11 13:15:41 -07001455 case HCI_FM_ENABLE_TRANS_CMD:
1456 ret = radio_hci_request(hdev, hci_fm_enable_trans_req, arg,
1457 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1458 break;
1459
1460 case HCI_FM_DISABLE_TRANS_CMD:
1461 ret = radio_hci_request(hdev, hci_fm_disable_trans_req, arg,
1462 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1463 break;
1464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 default:
1466 ret = -EINVAL;
1467 break;
1468 }
1469
1470 return ret;
1471}
1472
1473static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1474{
1475 hdev->req_result = result;
1476 hdev->req_status = HCI_REQ_DONE;
1477 wake_up_interruptible(&hdev->req_wait_q);
1478}
1479
1480static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1481{
1482 hdev->req_result = result;
1483 hdev->req_status = HCI_REQ_STATUS;
1484 wake_up_interruptible(&hdev->req_wait_q);
1485}
1486
1487static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1488{
1489 __u8 status = *((__u8 *) skb->data);
1490
1491 if (status)
1492 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 radio_hci_req_complete(hdev, status);
1494}
1495
1496static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1497 struct sk_buff *skb)
1498{
1499 __u8 status = *((__u8 *) skb->data);
1500 struct iris_device *radio = video_get_drvdata(video_get_dev());
1501
1502 if (status)
1503 return;
1504
1505 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1506
1507 radio_hci_req_complete(hdev, status);
1508}
1509
1510static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1511{
1512 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1513 struct iris_device *radio = video_get_drvdata(video_get_dev());
1514
1515 if (rsp->status)
1516 return;
1517
1518 radio->recv_conf = rsp->recv_conf_rsp;
1519 radio_hci_req_complete(hdev, rsp->status);
1520}
1521
1522static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1523 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 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1532
1533 radio_hci_req_complete(hdev, rsp->status);
1534}
1535
Ankur Nandwanid928d542011-08-11 13:15:41 -07001536
1537static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
1538 struct sk_buff *skb)
1539{
1540 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1541 struct iris_device *radio = video_get_drvdata(video_get_dev());
1542
1543 if (rsp->status)
1544 return;
1545
1546 iris_q_event(radio, HCI_EV_CMD_COMPLETE);
1547
1548 radio_hci_req_complete(hdev, rsp->status);
1549}
1550
1551
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1553 struct sk_buff *skb)
1554{
1555 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1556 struct iris_device *radio = video_get_drvdata(video_get_dev());
1557 struct v4l2_control *v4l_ctl = radio->g_ctl;
1558
1559 if (rsp->status)
1560 return;
1561
1562 v4l_ctl->value = rsp->sig_threshold;
1563
1564 radio_hci_req_complete(hdev, rsp->status);
1565}
1566
1567static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1568{
1569 struct iris_device *radio = video_get_drvdata(video_get_dev());
1570 struct hci_fm_station_rsp *rsp = (void *)skb->data;
1571 radio->fm_st_rsp = *(rsp);
1572
1573 /* Tune is always succesful */
1574 radio_hci_req_complete(hdev, 0);
1575}
1576
1577static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1578{
1579 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1580
1581 if (rsp->status)
1582 return;
1583
1584 radio_hci_req_complete(hdev, rsp->status);
1585}
1586
1587static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1588{
1589 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1590
1591 if (rsp->status)
1592 return;
1593
1594 radio_hci_req_complete(hdev, rsp->status);
1595}
1596
1597static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1598{
1599 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1600
1601 if (rsp->status)
1602 return;
1603
1604 radio_hci_req_complete(hdev, rsp->status);
1605}
1606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1608 struct sk_buff *skb)
1609{
1610 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1611 struct iris_device *radio = video_get_drvdata(video_get_dev());
1612 struct v4l2_capability *v4l_cap = radio->g_cap;
1613
1614 if (rsp->status)
1615 return;
1616 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1617 (rsp->feature_mask & 0x000001);
1618
1619 radio_hci_req_complete(hdev, rsp->status);
1620}
1621
1622static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1623 struct sk_buff *skb)
1624{
1625 struct iris_device *radio = video_get_drvdata(video_get_dev());
1626 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
1627 radio->st_dbg_param = *(rsp);
1628
1629 if (radio->st_dbg_param.status)
1630 return;
1631
1632 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1633}
1634
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001635static void iris_q_evt_data(struct iris_device *radio,
1636 char *data, int len, int event)
1637{
1638 struct kfifo *data_b = &radio->data_buf[event];
1639 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1640 wake_up_interruptible(&radio->event_queue);
1641}
1642
1643static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1644 struct sk_buff *skb)
1645{
1646 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301647 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001648 int len;
1649 char *data;
1650
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301651 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001652 return;
1653 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1654 data = kmalloc(len, GFP_ATOMIC);
1655
1656 if (!data) {
1657 FMDERR("Memory allocation failed");
1658 return;
1659 }
1660
1661 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1662 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301663 radio_hci_req_complete(hdev, status);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301664 kfree(data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001665
1666}
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301667
1668static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
1669 struct sk_buff *skb)
1670{
1671 struct iris_device *radio = video_get_drvdata(video_get_dev());
1672 __u8 status = *((__u8 *) skb->data);
1673 __u8 len;
1674 char *data;
1675
1676 if (status)
1677 return;
1678 len = skb->data[1];
1679 data = kmalloc(len+2, GFP_ATOMIC);
1680 if (!data) {
1681 FMDERR("Memory allocation failed");
1682 return;
1683 }
1684
1685 data[0] = status;
1686 data[1] = len;
1687 memcpy(&data[2], &skb->data[DEFAULT_DATA_OFFSET], len);
1688 iris_q_evt_data(radio, data, len+2, IRIS_BUF_RD_DEFAULT);
1689 radio_hci_req_complete(hdev, status);
1690 kfree(data);
1691}
1692
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001693static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1694 struct sk_buff *skb)
1695{
1696 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301697 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001698 char *data;
1699
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301700 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001701 return;
1702 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1703 if (!data) {
1704 FMDERR("Memory allocation failed");
1705 return;
1706 }
1707
1708 data[0] = skb->data[PEEK_DATA_OFSET];
1709 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301710 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001711 kfree(data);
1712}
1713
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301714static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
1715 struct sk_buff *skb)
1716{
1717 struct iris_device *radio = video_get_drvdata(video_get_dev());
1718 __u8 status = *((__u8 *) skb->data);
1719 char *data;
1720 if (status)
1721 return;
1722 data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
1723 if (!data) {
1724 FMDERR("memory allocation failed");
1725 return;
1726 }
1727 memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
1728 iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
1729 radio_hci_req_complete(hdev, status);
1730 kfree(data);
1731
1732}
1733
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301734static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
1735 struct sk_buff *skb)
1736{
1737 struct iris_device *radio = video_get_drvdata(video_get_dev());
1738 static struct hci_cc_do_calibration_rsp rsp ;
1739 rsp.status = skb->data[0];
1740 rsp.mode = skb->data[CALIB_MODE_OFSET];
1741
1742 if (rsp.status) {
1743 FMDERR("status = %d", rsp.status);
1744 return;
1745 }
1746 if (rsp.mode == PROCS_CALIB_MODE) {
1747 memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
1748 PROCS_CALIB_SIZE);
1749 } else if (rsp.mode == DC_CALIB_MODE) {
1750 memcpy(&rsp.data[PROCS_CALIB_SIZE],
1751 &skb->data[CALIB_DATA_OFSET], DC_CALIB_SIZE);
1752 iris_q_evt_data(radio, rsp.data, (PROCS_CALIB_SIZE +
1753 DC_CALIB_SIZE), IRIS_BUF_CAL_DATA);
1754 }
1755 radio_hci_req_complete(hdev, rsp.status);
1756}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
1758 struct sk_buff *skb)
1759{
1760 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
1761 __u16 opcode;
1762
1763 skb_pull(skb, sizeof(*cmd_compl_ev));
1764
1765 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
1766
1767 switch (opcode) {
1768 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
1769 hci_cc_fm_enable_rsp(hdev, skb);
1770 break;
1771 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
1772 hci_cc_conf_rsp(hdev, skb);
1773 break;
1774
1775 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
1776 hci_cc_fm_disable_rsp(hdev, skb);
1777 break;
1778
1779 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
1780 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
1781 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
1782 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
1783 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
1784 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
1785 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
1786 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
1787 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
1788 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001789 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
1790 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
1791 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
1792 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301794 hci_cc_rsp(hdev, skb);
1795 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001798 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001799 case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301800 case hci_common_cmd_op_pack(HCI_OCF_FM_SET_CALIBRATION):
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301801 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_EVENT_MASK):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 hci_cc_rsp(hdev, skb);
1803 break;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301804
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001805 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
1806 hci_cc_ssbi_peek_rsp(hdev, skb);
1807 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001808 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
1809 hci_cc_sig_threshold_rsp(hdev, skb);
1810 break;
1811
1812 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
1813 hci_cc_station_rsp(hdev, skb);
1814 break;
1815
1816 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
1817 hci_cc_prg_srv_rsp(hdev, skb);
1818 break;
1819
1820 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
1821 hci_cc_rd_txt_rsp(hdev, skb);
1822 break;
1823
1824 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
1825 hci_cc_af_list_rsp(hdev, skb);
1826 break;
1827
1828 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301829 hci_cc_riva_read_default_rsp(hdev, skb);
1830 break;
1831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001833 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834 break;
1835
1836 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
1837 hci_cc_feature_list_rsp(hdev, skb);
1838 break;
1839
1840 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
1841 hci_cc_dbg_param_rsp(hdev, skb);
1842 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07001843 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_SET_TRANS_CONF_REQ):
1844 hci_cc_fm_trans_set_conf_rsp(hdev, skb);
1845 break;
1846
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301847 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
1848 hci_cc_rds_grp_cntrs_rsp(hdev, skb);
1849 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301850 case hci_common_cmd_op_pack(HCI_OCF_FM_DO_CALIBRATION):
1851 hci_cc_do_calibration_rsp(hdev, skb);
1852 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001854 default:
1855 FMDERR("%s opcode 0x%x", hdev->name, opcode);
1856 break;
1857 }
1858
1859}
1860
1861static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
1862 struct sk_buff *skb)
1863{
1864 struct hci_ev_cmd_status *ev = (void *) skb->data;
1865 radio_hci_status_complete(hdev, ev->status);
1866}
1867
1868static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
1869 struct sk_buff *skb)
1870{
1871 int i;
1872 int len;
1873
1874 struct iris_device *radio = video_get_drvdata(video_get_dev());
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301875 struct hci_fm_station_rsp *rsp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876
1877 len = sizeof(struct hci_fm_station_rsp);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301878 rsp = (struct hci_fm_station_rsp *)skb_pull(skb, len);
1879 if (rsp == NULL)
1880 return;
1881 memcpy(&radio->fm_st_rsp.station_rsp, rsp, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882
1883 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
1884
1885 for (i = 0; i < IRIS_BUF_MAX; i++) {
1886 if (i >= IRIS_BUF_RT_RDS)
1887 kfifo_reset(&radio->data_buf[i]);
1888 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001889 if (radio->fm_st_rsp.station_rsp.rssi)
1890 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1891 else
1892 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1893
1894 if (radio->fm_st_rsp.station_rsp.stereo_prg)
1895 iris_q_event(radio, IRIS_EVT_STEREO);
1896
1897 if (radio->fm_st_rsp.station_rsp.mute_mode)
1898 iris_q_event(radio, IRIS_EVT_MONO);
1899
1900 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
1901 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1902 else
1903 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1904}
1905
1906static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
1907 struct sk_buff *skb)
1908{
1909 struct iris_device *radio = video_get_drvdata(video_get_dev());
1910 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
1911}
1912
1913static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
1914 struct sk_buff *skb)
1915{
1916 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001917 struct hci_ev_srch_list_compl *ev ;
1918 int cnt;
1919 int stn_num;
1920 int rel_freq;
1921 int abs_freq;
1922 int len;
1923
1924 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1925 if (!ev) {
1926 FMDERR("Memory allocation failed");
1927 return ;
1928 }
1929
1930 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
1931 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
1932
1933 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301934 (cnt < len) && (stn_num < ev->num_stations_found)
1935 && (stn_num < ARRAY_SIZE(ev->rel_freq));
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001936 cnt += PARAMS_PER_STATION, stn_num++) {
1937 abs_freq = *((int *)&skb->data[cnt]);
1938 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
1939 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
1940
1941 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
1942 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
1943 }
1944
1945 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
1946 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
1947 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
1948 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001949}
1950
1951static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
1952 struct sk_buff *skb)
1953{
1954 struct iris_device *radio = video_get_drvdata(video_get_dev());
1955 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
1956}
1957
1958static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
1959 struct sk_buff *skb)
1960{
1961 struct iris_device *radio = video_get_drvdata(video_get_dev());
1962 __u8 st_status = *((__u8 *) skb->data);
1963 if (st_status)
1964 iris_q_event(radio, IRIS_EVT_STEREO);
1965 else
1966 iris_q_event(radio, IRIS_EVT_MONO);
1967}
1968
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001969
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001970static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
1971 struct sk_buff *skb)
1972{
1973 struct iris_device *radio = video_get_drvdata(video_get_dev());
1974 int len;
1975 char *data;
1976
1977 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
1978 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
1979 data = kmalloc(len, GFP_ATOMIC);
1980 if (!data) {
1981 FMDERR("Failed to allocate memory");
1982 return;
1983 }
1984
1985 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
1986 data[1] = skb->data[RDS_PTYPE];
1987 data[2] = skb->data[RDS_PID_LOWER];
1988 data[3] = skb->data[RDS_PID_HIGHER];
1989 data[4] = 0;
1990
1991 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
1992
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001993 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001994
1995 kfree(data);
1996}
1997
1998
1999static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
2000 struct sk_buff *skb)
2001{
2002 struct iris_device *radio = video_get_drvdata(video_get_dev());
2003 int len = 0;
2004 char *data;
2005
2006 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
2007
2008 while (skb->data[len+RDS_OFFSET] != 0x0d)
2009 len++;
2010 len++;
2011
2012 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
2013 if (!data) {
2014 FMDERR("Failed to allocate memory");
2015 return;
2016 }
2017
2018 data[0] = len;
2019 data[1] = skb->data[RDS_PTYPE];
2020 data[2] = skb->data[RDS_PID_LOWER];
2021 data[3] = skb->data[RDS_PID_HIGHER];
2022 data[4] = 0;
2023
2024 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
2025 data[len+RDS_OFFSET] = 0x00;
2026
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002027 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002028
2029 kfree(data);
2030}
2031
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302032static void hci_ev_af_list(struct radio_hci_dev *hdev,
2033 struct sk_buff *skb)
2034{
2035 struct iris_device *radio = video_get_drvdata(video_get_dev());
2036 struct hci_ev_af_list ev;
2037
2038 ev.tune_freq = *((int *) &skb->data[0]);
2039 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
2040 ev.af_size = skb->data[AF_SIZE_OFFSET];
2041 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
2042 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
2043 iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
2044}
2045
2046static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
2047 struct sk_buff *skb)
2048{
2049 struct iris_device *radio = video_get_drvdata(video_get_dev());
2050 __u8 rds_status = skb->data[0];
2051
2052 if (rds_status)
2053 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2054 else
2055 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2056}
2057
2058static void hci_ev_service_available(struct radio_hci_dev *hdev,
2059 struct sk_buff *skb)
2060{
2061 struct iris_device *radio = video_get_drvdata(video_get_dev());
2062 if (radio->fm_st_rsp.station_rsp.serv_avble)
2063 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2064 else
2065 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2066}
2067
2068static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
2069 struct sk_buff *skb)
2070{
2071 struct iris_device *radio = video_get_drvdata(video_get_dev());
2072 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
2073}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002074
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
2076{
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302077 struct radio_hci_event_hdr *hdr;
2078 u8 event;
2079
2080 if (skb == NULL) {
2081 FMDERR("Socket buffer is NULL");
2082 return;
2083 }
2084
2085 hdr = (void *) skb->data;
2086 event = hdr->evt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087
2088 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
2089
2090 switch (event) {
2091 case HCI_EV_TUNE_STATUS:
2092 hci_ev_tune_status(hdev, skb);
2093 break;
2094 case HCI_EV_SEARCH_PROGRESS:
2095 case HCI_EV_SEARCH_RDS_PROGRESS:
2096 case HCI_EV_SEARCH_LIST_PROGRESS:
2097 hci_ev_search_next(hdev, skb);
2098 break;
2099 case HCI_EV_STEREO_STATUS:
2100 hci_ev_stereo_status(hdev, skb);
2101 break;
2102 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302103 hci_ev_rds_lock_status(hdev, skb);
2104 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302106 hci_ev_service_available(hdev, skb);
2107 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002108 case HCI_EV_RDS_RX_DATA:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002109 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002110 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002111 hci_ev_program_service(hdev, skb);
2112 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002113 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002114 hci_ev_radio_text(hdev, skb);
2115 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002116 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302117 hci_ev_af_list(hdev, skb);
2118 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302120 hci_ev_rds_grp_complete(hdev, skb);
2121 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002122 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2123 break;
2124
2125 case HCI_EV_CMD_COMPLETE:
2126 hci_cmd_complete_event(hdev, skb);
2127 break;
2128
2129 case HCI_EV_CMD_STATUS:
2130 hci_cmd_status_event(hdev, skb);
2131 break;
2132
2133 case HCI_EV_SEARCH_COMPLETE:
2134 case HCI_EV_SEARCH_RDS_COMPLETE:
2135 hci_ev_search_compl(hdev, skb);
2136 break;
2137
2138 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002139 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002140 break;
2141
2142 default:
2143 break;
2144 }
2145}
2146
2147/*
2148 * fops/IOCTL helper functions
2149 */
2150
2151static int iris_search(struct iris_device *radio, int on, int dir)
2152{
2153 int retval = 0;
2154 enum search_t srch = radio->g_search_mode & SRCH_MODE;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302155 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156
2157 if (on) {
2158 switch (srch) {
2159 case SCAN_FOR_STRONG:
2160 case SCAN_FOR_WEAK:
2161 radio->srch_st_list.srch_list_dir = dir;
2162 radio->srch_st_list.srch_list_mode = srch;
2163 radio->srch_st_list.srch_list_max = 0;
2164 retval = hci_fm_search_station_list(
2165 &radio->srch_st_list, radio->fm_hdev);
2166 break;
2167 case RDS_SEEK_PTY:
2168 case RDS_SCAN_PTY:
2169 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002170 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002171 radio->srch_rds.srch_station.srch_mode = srch;
2172 radio->srch_rds.srch_station.srch_dir = dir;
2173 radio->srch_rds.srch_station.scan_time =
2174 radio->g_scan_time;
2175 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2176 radio->fm_hdev);
2177 break;
2178 default:
2179 radio->srch_st.srch_mode = srch;
2180 radio->srch_st.scan_time = radio->g_scan_time;
2181 radio->srch_st.srch_dir = dir;
2182 retval = hci_fm_search_stations(
2183 &radio->srch_st, radio->fm_hdev);
2184 break;
2185 }
2186
2187 } else {
2188 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2189 }
2190
2191 return retval;
2192}
2193
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302194static int set_low_power_mode(struct iris_device *radio, int power_mode)
2195{
2196
2197 int rds_grps_proc = 0x00;
2198 int retval = 0;
2199 if (radio->power_mode != power_mode) {
2200
2201 if (power_mode) {
2202 radio->event_mask = 0x00;
2203 rds_grps_proc = 0x00 | AF_JUMP_ENABLE ;
2204 retval = hci_fm_rds_grps_process(
2205 &rds_grps_proc,
2206 radio->fm_hdev);
2207 if (retval < 0) {
2208 FMDERR("Disable RDS failed");
2209 return retval;
2210 }
2211 retval = hci_conf_event_mask(&radio->event_mask,
2212 radio->fm_hdev);
2213 } else {
2214
2215 radio->event_mask = SIG_LEVEL_INTR |
2216 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2217 retval = hci_conf_event_mask(&radio->event_mask,
2218 radio->fm_hdev);
2219 if (retval < 0) {
2220 FMDERR("Enable Async events failed");
2221 return retval;
2222 }
2223 retval = hci_fm_rds_grps_process(
2224 &radio->g_rds_grp_proc_ps,
2225 radio->fm_hdev);
2226 }
2227 radio->power_mode = power_mode;
2228 }
2229 return retval;
2230}
Ankur Nandwanid928d542011-08-11 13:15:41 -07002231static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232{
2233 int retval;
2234 radio->region = req_region;
2235
2236 switch (radio->region) {
2237 case IRIS_REGION_US:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002238 radio->recv_conf.band_low_limit =
2239 REGION_US_EU_BAND_LOW;
2240 radio->recv_conf.band_high_limit =
2241 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 break;
2243 case IRIS_REGION_EU:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002244 radio->recv_conf.band_low_limit =
2245 REGION_US_EU_BAND_LOW;
2246 radio->recv_conf.band_high_limit =
2247 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 break;
2249 case IRIS_REGION_JAPAN:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002250 radio->recv_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002251 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302252 radio->recv_conf.band_high_limit =
2253 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002254 break;
2255 case IRIS_REGION_JAPAN_WIDE:
2256 radio->recv_conf.band_low_limit =
2257 REGION_JAPAN_WIDE_BAND_LOW;
2258 radio->recv_conf.band_high_limit =
2259 REGION_JAPAN_WIDE_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260 break;
2261 default:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002262 /* The user specifies the value.
2263 So nothing needs to be done */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264 break;
2265 }
2266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 retval = hci_set_fm_recv_conf(
2268 &radio->recv_conf,
2269 radio->fm_hdev);
2270
2271 return retval;
2272}
2273
Ankur Nandwanid928d542011-08-11 13:15:41 -07002274
2275static int iris_trans_set_region(struct iris_device *radio, int req_region)
2276{
2277 int retval;
2278 radio->region = req_region;
2279
2280 switch (radio->region) {
2281 case IRIS_REGION_US:
2282 radio->trans_conf.band_low_limit =
2283 REGION_US_EU_BAND_LOW;
2284 radio->trans_conf.band_high_limit =
2285 REGION_US_EU_BAND_HIGH;
2286 break;
2287 case IRIS_REGION_EU:
2288 radio->trans_conf.band_low_limit =
2289 REGION_US_EU_BAND_LOW;
2290 radio->trans_conf.band_high_limit =
2291 REGION_US_EU_BAND_HIGH;
2292 break;
2293 case IRIS_REGION_JAPAN:
2294 radio->trans_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002295 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302296 radio->trans_conf.band_high_limit =
2297 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002298 break;
2299 case IRIS_REGION_JAPAN_WIDE:
2300 radio->recv_conf.band_low_limit =
2301 REGION_JAPAN_WIDE_BAND_LOW;
2302 radio->recv_conf.band_high_limit =
2303 REGION_JAPAN_WIDE_BAND_HIGH;
2304 default:
2305 break;
2306 }
2307
2308 retval = hci_set_fm_trans_conf(
2309 &radio->trans_conf,
2310 radio->fm_hdev);
2311 return retval;
2312}
2313
2314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2316{
2317
2318 int retval;
2319 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2320 if (retval < 0)
2321 FMDERR("Error while setting the frequency : %d\n", retval);
2322 return retval;
2323}
2324
2325
2326static int iris_vidioc_queryctrl(struct file *file, void *priv,
2327 struct v4l2_queryctrl *qc)
2328{
2329 unsigned char i;
2330 int retval = -EINVAL;
2331
2332 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2333 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2334 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2335 retval = 0;
2336 break;
2337 }
2338 }
2339
2340 return retval;
2341}
2342
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302343static int iris_do_calibration(struct iris_device *radio)
2344{
2345 char cal_mode = 0x00;
2346 int retval = 0x00;
2347
2348 cal_mode = PROCS_CALIB_MODE;
2349 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2350 radio->fm_hdev);
2351 if (retval < 0) {
2352 FMDERR("Enable failed before calibration %x", retval);
2353 return retval;
2354 }
2355 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2356 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2357 if (retval < 0) {
2358 FMDERR("Do Process calibration failed %x", retval);
2359 return retval;
2360 }
2361 cal_mode = DC_CALIB_MODE;
2362 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2363 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2364 if (retval < 0) {
2365 FMDERR("Do DC calibration failed %x", retval);
2366 return retval;
2367 }
2368 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2369 radio->fm_hdev);
2370 if (retval < 0)
2371 FMDERR("Disable Failed after calibration %d", retval);
2372 return retval;
2373}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002374static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2375 struct v4l2_control *ctrl)
2376{
2377 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2378 int retval = 0;
2379
2380 switch (ctrl->id) {
2381 case V4L2_CID_AUDIO_VOLUME:
2382 break;
2383 case V4L2_CID_AUDIO_MUTE:
2384 ctrl->value = radio->mute_mode.hard_mute;
2385 break;
2386 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2387 ctrl->value = radio->g_search_mode;
2388 break;
2389 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2390 ctrl->value = radio->g_scan_time;
2391 break;
2392 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302393 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394 break;
2395 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302396 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002397 break;
2398 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2399 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2400 if (retval < 0)
2401 return retval;
2402 ctrl->value = radio->st_dbg_param.io_verc;
2403 break;
2404 case V4L2_CID_PRIVATE_IRIS_INTDET:
2405 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2406 if (retval < 0)
2407 return retval;
2408 ctrl->value = radio->st_dbg_param.in_det_out;
2409 break;
2410 case V4L2_CID_PRIVATE_IRIS_REGION:
2411 ctrl->value = radio->region;
2412 break;
2413 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2414 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
2415 break;
2416 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302417 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418 break;
2419 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302420 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002421 break;
2422 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302423 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002424 break;
2425 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002426 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002428 } else if (radio->mode == FM_TRANS) {
2429 ctrl->value = radio->trans_conf.emphasis;
2430 } else {
2431 FMDERR("Error in radio mode"
2432 " %d\n", retval);
2433 return -EINVAL;
2434 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002435 break;
2436 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002437 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002438 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002439 } else if (radio->mode == FM_TRANS) {
2440 ctrl->value = radio->trans_conf.rds_std;
2441 } else {
2442 FMDERR("Error in radio mode"
2443 " %d\n", retval);
2444 return -EINVAL;
2445 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002446 break;
2447 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002448 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002449 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002450 } else {
2451 FMDERR("Error in radio mode"
2452 " %d\n", retval);
2453 return -EINVAL;
2454 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455 break;
2456 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002457 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002459 } else {
2460 FMDERR("Error in radio mode"
2461 " %d\n", retval);
2462 return -EINVAL;
2463 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464 break;
2465 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2466 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2467 break;
2468 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002469 case V4L2_CID_PRIVATE_IRIS_PSALL:
2470 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471 break;
2472 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2473 ctrl->value = radio->rds_grp.rds_buf_size;
2474 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302476 ctrl->value = radio->power_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002477 break;
2478 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2479 ctrl->value = radio->g_antenna;
2480 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002481 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2482 ctrl->value = radio->mute_mode.soft_mute;
2483 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302484 case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
2485 retval = iris_do_calibration(radio);
2486 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 default:
2488 retval = -EINVAL;
2489 }
2490 if (retval < 0)
2491 FMDERR("get control failed with %d, id: %d\n",
2492 retval, ctrl->id);
2493 return retval;
2494}
2495
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302496static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
2497 struct v4l2_ext_controls *ctrl)
2498{
2499 int retval = 0;
2500 char *data = NULL;
2501 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2502 struct hci_fm_def_data_rd_req default_data_rd;
2503
2504 switch ((ctrl->controls[0]).id) {
2505 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
2506 data = (ctrl->controls[0]).string;
2507 memset(&default_data_rd, 0, sizeof(default_data_rd));
2508 if (copy_from_user(&default_data_rd.mode, data,
2509 sizeof(default_data_rd)))
2510 return -EFAULT;
2511 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
2512 break;
2513 default:
2514 retval = -EINVAL;
2515 }
2516
2517 return retval;
2518}
2519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002520static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2521 struct v4l2_ext_controls *ctrl)
2522{
Ankur Nandwanid928d542011-08-11 13:15:41 -07002523 int retval = 0;
2524 int bytes_to_copy;
2525 struct hci_fm_tx_ps tx_ps;
2526 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302527 struct hci_fm_def_data_wr_req default_data;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302528 struct hci_fm_set_cal_req cal_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002529
2530 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2531 char *data = NULL;
2532
2533 switch ((ctrl->controls[0]).id) {
2534 case V4L2_CID_RDS_TX_PS_NAME:
2535 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2536 /*Pass a sample PS string */
2537
2538 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
2539 bytes_to_copy = min((int)(ctrl->controls[0]).size,
2540 MAX_PS_LENGTH);
2541 data = (ctrl->controls[0]).string;
2542
2543 if (copy_from_user(tx_ps.ps_data,
2544 data, bytes_to_copy))
2545 return -EFAULT;
2546 tx_ps.ps_control = 0x01;
2547 tx_ps.pi = radio->pi;
2548 tx_ps.pty = radio->pty;
2549 tx_ps.ps_repeatcount = radio->ps_repeatcount;
2550 tx_ps.ps_len = bytes_to_copy;
2551
2552 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2553 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
2554 break;
2555 case V4L2_CID_RDS_TX_RADIO_TEXT:
2556 bytes_to_copy =
2557 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2558 data = (ctrl->controls[0]).string;
2559
2560 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
2561
2562 if (copy_from_user(tx_rt.rt_data,
2563 data, bytes_to_copy))
2564 return -EFAULT;
2565
2566 tx_rt.rt_control = 0x01;
2567 tx_rt.pi = radio->pi;
2568 tx_rt.pty = radio->pty;
2569 tx_rt.ps_len = bytes_to_copy;
2570
2571 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2572 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
2573 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302574 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
2575 data = (ctrl->controls[0]).string;
2576 memset(&default_data, 0, sizeof(default_data));
2577 if (copy_from_user(&default_data, data, sizeof(default_data)))
2578 return -EFAULT;
2579 retval = hci_def_data_write(&default_data, radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302580 break;
2581 case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
2582 FMDERR("In Set Calibration");
2583 data = (ctrl->controls[0]).string;
2584 bytes_to_copy = (ctrl->controls[0]).size;
2585 memset(cal_req.data, 0, MAX_CALIB_SIZE);
2586 cal_req.mode = PROCS_CALIB_MODE;
2587 if (copy_from_user(&cal_req.data[0],
2588 data, PROCS_CALIB_SIZE))
2589 return -EFAULT;
2590 retval = radio_hci_request(radio->fm_hdev, hci_fm_set_cal_req,
2591 (unsigned long)&cal_req, RADIO_HCI_TIMEOUT);
2592 if (retval < 0)
2593 FMDERR("Set Process calibration failed %d", retval);
2594 if (copy_from_user(&cal_req.data[PROCS_CALIB_SIZE],
2595 data, DC_CALIB_SIZE))
2596 return -EFAULT;
2597 cal_req.mode = DC_CALIB_MODE;
2598 retval = radio_hci_request(radio->fm_hdev, hci_fm_set_cal_req,
2599 (unsigned long)&cal_req, RADIO_HCI_TIMEOUT);
2600 if (retval < 0)
2601 FMDERR("Set DC calibration failed %d", retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302602 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002603 default:
2604 FMDBG("Shouldn't reach here\n");
2605 retval = -1;
2606 }
2607 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002608}
2609
2610static int iris_vidioc_s_ctrl(struct file *file, void *priv,
2611 struct v4l2_control *ctrl)
2612{
2613 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2614 int retval = 0;
2615 unsigned int rds_grps_proc = 0;
2616 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002617 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302618 struct hci_fm_tx_ps tx_ps = {0};
2619 struct hci_fm_tx_rt tx_rt = {0};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620
2621 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302622 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002623 radio->tone_freq = ctrl->value;
2624 retval = radio_hci_request(radio->fm_hdev,
2625 hci_fm_tone_generator, arg,
2626 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
2627 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628 case V4L2_CID_AUDIO_VOLUME:
2629 break;
2630 case V4L2_CID_AUDIO_MUTE:
2631 radio->mute_mode.hard_mute = ctrl->value;
2632 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
2633 retval = hci_set_fm_mute_mode(
2634 &radio->mute_mode,
2635 radio->fm_hdev);
2636 if (retval < 0)
2637 FMDERR("Error while set FM hard mute"" %d\n",
2638 retval);
2639 break;
2640 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2641 radio->g_search_mode = ctrl->value;
2642 break;
2643 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2644 radio->g_scan_time = ctrl->value;
2645 break;
2646 case V4L2_CID_PRIVATE_IRIS_SRCHON:
2647 iris_search(radio, ctrl->value, SRCH_DIR_UP);
2648 break;
2649 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002650 switch (ctrl->value) {
2651 case FM_RECV:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2653 radio->fm_hdev);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002654
2655 radio->mode = FM_RECV;
2656
2657 if (retval < 0)
2658 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002659 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002660 radio->mute_mode.soft_mute = CTRL_ON;
2661 retval = hci_set_fm_mute_mode(
2662 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002663 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302664 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002665 FMDERR("Failed to enable Smute\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302666 return retval;
2667 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002668 radio->stereo_mode.stereo_mode = CTRL_OFF;
2669 radio->stereo_mode.sig_blend = CTRL_ON;
2670 radio->stereo_mode.intf_blend = CTRL_ON;
2671 radio->stereo_mode.most_switch = CTRL_ON;
2672 retval = hci_set_fm_stereo_mode(
2673 &radio->stereo_mode,
2674 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302675 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002676 FMDERR("Failed to set stereo mode\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302677 return retval;
2678 }
Srinivasa Rao Uppalaf0d13742011-09-08 10:13:13 +05302679 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2680 radio->fm_hdev);
2681 if (retval < 0)
2682 FMDERR("Failed to get the Recv Config\n");
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002683 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002684 case FM_TRANS:
2685 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
2686 radio->fm_hdev);
2687 radio->mode = FM_TRANS;
2688
2689 if (retval < 0)
2690 FMDERR("Error while enabling TRANS FM"
2691 " %d\n", retval);
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002692 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002693 case FM_OFF:
2694 switch (radio->mode) {
2695 case FM_RECV:
2696 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2697 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002698 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002699 FMDERR("Err on disable recv FM"
2700 " %d\n", retval);
2701 break;
2702 case FM_TRANS:
2703 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
2704 radio->fm_hdev);
2705
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002706 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002707 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002708 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002709 break;
2710 default:
2711 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302713 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002714 default:
2715 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002716 }
2717 break;
2718 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002719 if (radio->mode == FM_RECV) {
2720 retval = iris_recv_set_region(radio, ctrl->value);
2721 } else {
2722 if (radio->mode == FM_TRANS)
2723 retval = iris_trans_set_region(radio,
2724 ctrl->value);
2725 else
2726 retval = -EINVAL;
2727 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728 break;
2729 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2730 temp_val = ctrl->value;
2731 retval = hci_fm_set_signal_threshold(
2732 &temp_val,
2733 radio->fm_hdev);
2734 if (retval < 0) {
2735 FMDERR("Error while setting signal threshold\n");
2736 break;
2737 }
2738 break;
2739 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
2740 radio->srch_rds.srch_pty = ctrl->value;
2741 radio->srch_st_list.srch_pty = ctrl->value;
2742 break;
2743 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
2744 radio->srch_rds.srch_pi = ctrl->value;
2745 break;
2746 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
2747 break;
2748 case V4L2_CID_PRIVATE_IRIS_SPACING:
2749 radio->recv_conf.ch_spacing = ctrl->value;
2750 break;
2751 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002752 switch (radio->mode) {
2753 case FM_RECV:
2754 radio->recv_conf.emphasis = ctrl->value;
2755 retval = hci_set_fm_recv_conf(
2756 &radio->recv_conf,
2757 radio->fm_hdev);
2758 if (retval < 0)
2759 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002760 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002761 case FM_TRANS:
2762 radio->trans_conf.emphasis = ctrl->value;
2763 retval = hci_set_fm_trans_conf(
2764 &radio->trans_conf,
2765 radio->fm_hdev);
2766 if (retval < 0)
2767 FMDERR("Error in setting emphasis");
2768 break;
2769 default:
2770 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002771 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772 break;
2773 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002774 switch (radio->mode) {
2775 case FM_RECV:
2776 radio->recv_conf.rds_std = ctrl->value;
2777 retval = hci_set_fm_recv_conf(
2778 &radio->recv_conf,
2779 radio->fm_hdev);
2780 if (retval < 0)
2781 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002782 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002783 case FM_TRANS:
2784 radio->trans_conf.rds_std = ctrl->value;
2785 retval = hci_set_fm_trans_conf(
2786 &radio->trans_conf,
2787 radio->fm_hdev);
2788 if (retval < 0)
2789 FMDERR("Error in rds_Std");
2790 break;
2791 default:
2792 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002793 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794 break;
2795 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002796 switch (radio->mode) {
2797 case FM_RECV:
2798 radio->recv_conf.rds_std = ctrl->value;
2799 retval = hci_set_fm_recv_conf(
2800 &radio->recv_conf,
2801 radio->fm_hdev);
2802 if (retval < 0)
2803 FMDERR("Error in rds_std");
2804 break;
2805 case FM_TRANS:
2806 radio->trans_conf.rds_std = ctrl->value;
2807 retval = hci_set_fm_trans_conf(
2808 &radio->trans_conf,
2809 radio->fm_hdev);
2810 if (retval < 0)
2811 FMDERR("Error in rds_Std");
2812 break;
2813 default:
2814 retval = -EINVAL;
2815 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002816 break;
2817 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2818 radio->rds_grp.rds_grp_enable_mask = ctrl->value;
2819 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
2820 break;
2821 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
2822 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002823 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002824 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002825 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002826 radio->fm_hdev);
2827 break;
2828 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2829 radio->rds_grp.rds_buf_size = ctrl->value;
2830 break;
2831 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002832 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
2833 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2834 retval = hci_fm_rds_grps_process(
2835 &radio->g_rds_grp_proc_ps,
2836 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002837 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302838 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
2839 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_OFFSET);
2840 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2841 retval = hci_fm_rds_grps_process(
2842 &radio->g_rds_grp_proc_ps,
2843 radio->fm_hdev);
2844 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002845 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302846 set_low_power_mode(radio, ctrl->value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002847 break;
2848 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2849 temp_val = ctrl->value;
2850 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
2851 break;
2852 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002853 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854 break;
2855 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002856 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002857 break;
2858 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302859 tx_ps.ps_control = 0x00;
2860 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2861 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002862 break;
2863 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302864 tx_rt.rt_control = 0x00;
2865 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2866 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867 break;
2868 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002869 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002870 break;
2871 case V4L2_CID_TUNE_POWER_LEVEL:
2872 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002873 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2874 radio->mute_mode.soft_mute = ctrl->value;
2875 retval = hci_set_fm_mute_mode(
2876 &radio->mute_mode,
2877 radio->fm_hdev);
2878 if (retval < 0)
2879 FMDERR("Error while setting FM soft mute"" %d\n",
2880 retval);
2881 break;
2882 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
2883 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
2884 break;
2885 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
2886 radio->riva_data_req.cmd_params.length = ctrl->value;
2887 break;
2888 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
2889 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
2890 radio->riva_data_req.cmd_params.length);
2891 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
2892 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
2893 break;
2894 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
2895 radio->ssbi_data_accs.start_addr = ctrl->value;
2896 break;
2897 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
2898 radio->ssbi_data_accs.data = ctrl->value;
2899 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
2900 radio->fm_hdev);
2901 break;
2902 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
2903 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
2904 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
2905 radio->fm_hdev);
2906 break;
2907 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
2908 radio->ssbi_peek_reg.start_address = ctrl->value;
2909 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
2910 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302911 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
2912 temp_val = ctrl->value;
2913 hci_read_grp_counters(&temp_val, radio->fm_hdev);
2914 break;
2915 case V4L2_CID_PRIVATE_IRIS_HLSI:
2916 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2917 radio->fm_hdev);
2918 if (retval)
2919 break;
2920 radio->recv_conf.hlsi = ctrl->value;
2921 retval = hci_set_fm_recv_conf(
2922 &radio->recv_conf,
2923 radio->fm_hdev);
2924 break;
2925 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
2926 temp_val = ctrl->value;
2927 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
2928 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002930 default:
2931 retval = -EINVAL;
2932 }
2933 return retval;
2934}
2935
2936static int iris_vidioc_g_tuner(struct file *file, void *priv,
2937 struct v4l2_tuner *tuner)
2938{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002939 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002940 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941 if (tuner->index > 0)
2942 return -EINVAL;
2943
2944 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
2945 if (retval < 0)
2946 return retval;
2947
2948 tuner->type = V4L2_TUNER_RADIO;
2949 tuner->rangelow = radio->recv_conf.band_low_limit * TUNE_PARAM;
2950 tuner->rangehigh = radio->recv_conf.band_high_limit * TUNE_PARAM;
2951 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
2952 tuner->capability = V4L2_TUNER_CAP_LOW;
2953 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
2954 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
2955 tuner->afc = 0;
2956
2957 return 0;
2958}
2959
2960static int iris_vidioc_s_tuner(struct file *file, void *priv,
2961 struct v4l2_tuner *tuner)
2962{
2963 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07002964 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002965 if (tuner->index > 0)
2966 return -EINVAL;
2967
Ankur Nandwanid928d542011-08-11 13:15:41 -07002968 if (radio->mode == FM_RECV) {
2969 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
2970 radio->recv_conf.band_high_limit =
2971 tuner->rangehigh / TUNE_PARAM;
2972 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
2973 radio->stereo_mode.stereo_mode = 0x01;
2974 retval = hci_set_fm_stereo_mode(
2975 &radio->stereo_mode,
2976 radio->fm_hdev);
2977 } else {
2978 radio->stereo_mode.stereo_mode = 0x00;
2979 retval = hci_set_fm_stereo_mode(
2980 &radio->stereo_mode,
2981 radio->fm_hdev);
2982 }
2983 if (retval < 0)
2984 FMDERR(": set tuner failed with %d\n", retval);
2985 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002986 } else {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002987 if (radio->mode == FM_TRANS) {
2988 radio->trans_conf.band_low_limit =
2989 tuner->rangelow / TUNE_PARAM;
2990 radio->trans_conf.band_high_limit =
2991 tuner->rangehigh / TUNE_PARAM;
2992 } else {
2993 return -EINVAL;
2994 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002995 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002997 return retval;
2998}
2999
3000static int iris_vidioc_g_frequency(struct file *file, void *priv,
3001 struct v4l2_frequency *freq)
3002{
3003 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3004 int retval;
3005
3006 freq->type = V4L2_TUNER_RADIO;
3007 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3008 if (retval < 0)
3009 FMDERR("get frequency failed %d\n", retval);
3010 else
3011 freq->frequency =
3012 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
3013 return retval;
3014}
3015
3016static int iris_vidioc_s_frequency(struct file *file, void *priv,
3017 struct v4l2_frequency *freq)
3018{
3019 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3020 int retval = -1;
3021 freq->frequency = freq->frequency / TUNE_PARAM;
3022
3023 if (freq->type != V4L2_TUNER_RADIO)
3024 return -EINVAL;
3025
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003026 /* We turn off RDS prior to tuning to a new station.
3027 because of a bug in SoC which prevents tuning
3028 during RDS transmission.
3029 */
3030 if (radio->mode == FM_TRANS
3031 && (radio->trans_conf.rds_std == 0 ||
3032 radio->trans_conf.rds_std == 1)) {
3033 radio->prev_trans_rds = radio->trans_conf.rds_std;
3034 radio->trans_conf.rds_std = 2;
3035 hci_set_fm_trans_conf(&radio->trans_conf,
3036 radio->fm_hdev);
3037 }
3038
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003039 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003040
3041 if (radio->mode == FM_TRANS
3042 && radio->trans_conf.rds_std == 2
3043 && (radio->prev_trans_rds == 1
3044 || radio->prev_trans_rds == 0)) {
3045 radio->trans_conf.rds_std = radio->prev_trans_rds;
3046 hci_set_fm_trans_conf(&radio->trans_conf,
3047 radio->fm_hdev);
3048 }
3049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003050 if (retval < 0)
3051 FMDERR(" set frequency failed with %d\n", retval);
3052 return retval;
3053}
3054
3055static int iris_vidioc_dqbuf(struct file *file, void *priv,
3056 struct v4l2_buffer *buffer)
3057{
3058 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3059 enum iris_buf_t buf_type = buffer->index;
3060 struct kfifo *data_fifo;
3061 unsigned char *buf = (unsigned char *)buffer->m.userptr;
3062 unsigned int len = buffer->length;
3063 if (!access_ok(VERIFY_WRITE, buf, len))
3064 return -EFAULT;
3065 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
3066 data_fifo = &radio->data_buf[buf_type];
3067 if (buf_type == IRIS_BUF_EVENTS)
3068 if (wait_event_interruptible(radio->event_queue,
3069 kfifo_len(data_fifo)) < 0)
3070 return -EINTR;
3071 } else {
3072 FMDERR("invalid buffer type\n");
3073 return -EINVAL;
3074 }
3075 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3076 &radio->buf_lock[buf_type]);
3077
3078 return 0;
3079}
3080
3081static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
3082 struct v4l2_format *f)
3083{
3084 return 0;
3085
3086}
3087
3088static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3089 struct v4l2_hw_freq_seek *seek)
3090{
3091 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3092 int dir;
3093 if (seek->seek_upward)
3094 dir = SRCH_DIR_UP;
3095 else
3096 dir = SRCH_DIR_DOWN;
3097 return iris_search(radio, CTRL_ON, dir);
3098}
3099
3100static int iris_vidioc_querycap(struct file *file, void *priv,
3101 struct v4l2_capability *capability)
3102{
3103 struct iris_device *radio;
3104 radio = video_get_drvdata(video_devdata(file));
3105 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
3106 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
3107 radio->g_cap = capability;
3108 return 0;
3109}
3110
3111
3112static const struct v4l2_ioctl_ops iris_ioctl_ops = {
3113 .vidioc_querycap = iris_vidioc_querycap,
3114 .vidioc_queryctrl = iris_vidioc_queryctrl,
3115 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
3116 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
3117 .vidioc_g_tuner = iris_vidioc_g_tuner,
3118 .vidioc_s_tuner = iris_vidioc_s_tuner,
3119 .vidioc_g_frequency = iris_vidioc_g_frequency,
3120 .vidioc_s_frequency = iris_vidioc_s_frequency,
3121 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
3122 .vidioc_dqbuf = iris_vidioc_dqbuf,
3123 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
3124 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303125 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003126};
3127
3128static const struct v4l2_file_operations iris_fops = {
3129 .owner = THIS_MODULE,
3130 .unlocked_ioctl = video_ioctl2,
3131};
3132
3133static struct video_device iris_viddev_template = {
3134 .fops = &iris_fops,
3135 .ioctl_ops = &iris_ioctl_ops,
3136 .name = DRIVER_NAME,
3137 .release = video_device_release,
3138};
3139
3140static struct video_device *video_get_dev(void)
3141{
3142 return priv_videodev;
3143}
3144
3145static int __init iris_probe(struct platform_device *pdev)
3146{
3147 struct iris_device *radio;
3148 int retval;
3149 int radio_nr = -1;
3150 int i;
3151
3152 if (!pdev) {
3153 FMDERR(": pdev is null\n");
3154 return -ENOMEM;
3155 }
3156
3157 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
3158 if (!radio) {
3159 FMDERR(": Could not allocate radio device\n");
3160 return -ENOMEM;
3161 }
3162
3163 radio->dev = &pdev->dev;
3164 platform_set_drvdata(pdev, radio);
3165
3166 radio->videodev = video_device_alloc();
3167 if (!radio->videodev) {
3168 FMDERR(": Could not allocate V4L device\n");
3169 kfree(radio);
3170 return -ENOMEM;
3171 }
3172
3173 memcpy(radio->videodev, &iris_viddev_template,
3174 sizeof(iris_viddev_template));
3175
3176 for (i = 0; i < IRIS_BUF_MAX; i++) {
3177 int kfifo_alloc_rc = 0;
3178 spin_lock_init(&radio->buf_lock[i]);
3179
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07003180 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3182 rds_buf*3, GFP_KERNEL);
3183 else
3184 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3185 STD_BUF_SIZE, GFP_KERNEL);
3186
3187 if (kfifo_alloc_rc != 0) {
3188 FMDERR("failed allocating buffers %d\n",
3189 kfifo_alloc_rc);
3190 for (; i > -1; i--) {
3191 kfifo_free(&radio->data_buf[i]);
3192 kfree(radio);
3193 return -ENOMEM;
3194 }
3195 }
3196 }
3197
3198 mutex_init(&radio->lock);
3199 init_completion(&radio->sync_xfr_start);
3200 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003201 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202 init_waitqueue_head(&radio->event_queue);
3203 init_waitqueue_head(&radio->read_queue);
3204
3205 video_set_drvdata(radio->videodev, radio);
3206
3207 if (NULL == video_get_drvdata(radio->videodev))
3208 FMDERR(": video_get_drvdata failed\n");
3209
3210 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
3211 radio_nr);
3212 if (retval) {
3213 FMDERR(": Could not register video device\n");
3214 video_device_release(radio->videodev);
3215 for (; i > -1; i--)
3216 kfifo_free(&radio->data_buf[i]);
3217 kfree(radio);
3218 return retval;
3219 } else {
3220 priv_videodev = kzalloc(sizeof(struct video_device),
3221 GFP_KERNEL);
3222 memcpy(priv_videodev, radio->videodev,
3223 sizeof(struct video_device));
3224 }
3225 return 0;
3226}
3227
3228
3229static int __devexit iris_remove(struct platform_device *pdev)
3230{
3231 int i;
3232 struct iris_device *radio = platform_get_drvdata(pdev);
3233
3234 video_unregister_device(radio->videodev);
3235
3236 for (i = 0; i < IRIS_BUF_MAX; i++)
3237 kfifo_free(&radio->data_buf[i]);
3238
3239 kfree(radio);
3240
3241 platform_set_drvdata(pdev, NULL);
3242
3243 return 0;
3244}
3245
3246static struct platform_driver iris_driver = {
3247 .driver = {
3248 .owner = THIS_MODULE,
3249 .name = "iris_fm",
3250 },
3251 .remove = __devexit_p(iris_remove),
3252};
3253
3254static int __init iris_radio_init(void)
3255{
3256 return platform_driver_probe(&iris_driver, iris_probe);
3257}
3258module_init(iris_radio_init);
3259
3260static void __exit iris_radio_exit(void)
3261{
3262 platform_driver_unregister(&iris_driver);
3263}
3264module_exit(iris_radio_exit);
3265
3266MODULE_LICENSE("GPL v2");
3267MODULE_AUTHOR(DRIVER_AUTHOR);
3268MODULE_DESCRIPTION(DRIVER_DESC);