blob: 0ab22f8c5f251f7f310f6db68dc7276994ff1844 [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
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301355static int hci_fm_set_cal_req_proc(struct radio_hci_dev *hdev,
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301356 unsigned long param)
1357{
1358 u16 opcode = 0;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301359 struct hci_fm_set_cal_req_proc *cal_req =
1360 (struct hci_fm_set_cal_req_proc *)param;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301361
1362 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1363 HCI_OCF_FM_SET_CALIBRATION);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301364 return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301365 cal_req);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301366}
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301367
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301368static int hci_fm_set_cal_req_dc(struct radio_hci_dev *hdev,
1369 unsigned long param)
1370{
1371 u16 opcode = 0;
1372 struct hci_fm_set_cal_req_dc *cal_req =
1373 (struct hci_fm_set_cal_req_dc *)param;
1374
1375 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1376 HCI_OCF_FM_SET_CALIBRATION);
1377 return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
1378 cal_req);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301379}
1380
1381static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
1382 unsigned long param)
1383{
1384 u16 opcode = 0;
1385 u8 cal_mode = param;
1386
1387 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1388 HCI_OCF_FM_DO_CALIBRATION);
1389 return radio_hci_send_cmd(hdev, opcode, sizeof(cal_mode),
1390 &cal_mode);
1391
1392}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1394{
1395 int ret = 0;
1396 unsigned long arg = 0;
1397
Ankur Nandwanid928d542011-08-11 13:15:41 -07001398 if (!hdev)
1399 return -ENODEV;
1400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401 switch (cmd) {
1402 case HCI_FM_ENABLE_RECV_CMD:
1403 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1404 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1405 break;
1406
1407 case HCI_FM_DISABLE_RECV_CMD:
1408 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1409 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1410 break;
1411
1412 case HCI_FM_GET_RECV_CONF_CMD:
1413 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1414 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1415 break;
1416
1417 case HCI_FM_GET_STATION_PARAM_CMD:
1418 ret = radio_hci_request(hdev,
1419 hci_fm_get_station_param_req, arg,
1420 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1421 break;
1422
1423 case HCI_FM_GET_SIGNAL_TH_CMD:
1424 ret = radio_hci_request(hdev,
1425 hci_fm_get_sig_threshold_req, arg,
1426 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1427 break;
1428
1429 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1430 ret = radio_hci_request(hdev,
1431 hci_fm_get_program_service_req, arg,
1432 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1433 break;
1434
1435 case HCI_FM_GET_RADIO_TEXT_CMD:
1436 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1437 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1438 break;
1439
1440 case HCI_FM_GET_AF_LIST_CMD:
1441 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1442 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1443 break;
1444
1445 case HCI_FM_CANCEL_SEARCH_CMD:
1446 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1447 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1448 break;
1449
1450 case HCI_FM_RESET_CMD:
1451 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1452 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1453 break;
1454
1455 case HCI_FM_GET_FEATURES_CMD:
1456 ret = radio_hci_request(hdev,
1457 hci_fm_get_feature_lists_req, arg,
1458 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1459 break;
1460
1461 case HCI_FM_STATION_DBG_PARAM_CMD:
1462 ret = radio_hci_request(hdev,
1463 hci_fm_get_station_dbg_param_req, arg,
1464 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1465 break;
1466
Ankur Nandwanid928d542011-08-11 13:15:41 -07001467 case HCI_FM_ENABLE_TRANS_CMD:
1468 ret = radio_hci_request(hdev, hci_fm_enable_trans_req, arg,
1469 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1470 break;
1471
1472 case HCI_FM_DISABLE_TRANS_CMD:
1473 ret = radio_hci_request(hdev, hci_fm_disable_trans_req, arg,
1474 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1475 break;
1476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 default:
1478 ret = -EINVAL;
1479 break;
1480 }
1481
1482 return ret;
1483}
1484
1485static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1486{
1487 hdev->req_result = result;
1488 hdev->req_status = HCI_REQ_DONE;
1489 wake_up_interruptible(&hdev->req_wait_q);
1490}
1491
1492static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1493{
1494 hdev->req_result = result;
1495 hdev->req_status = HCI_REQ_STATUS;
1496 wake_up_interruptible(&hdev->req_wait_q);
1497}
1498
1499static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1500{
1501 __u8 status = *((__u8 *) skb->data);
1502
1503 if (status)
1504 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001505 radio_hci_req_complete(hdev, status);
1506}
1507
1508static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1509 struct sk_buff *skb)
1510{
1511 __u8 status = *((__u8 *) skb->data);
1512 struct iris_device *radio = video_get_drvdata(video_get_dev());
1513
1514 if (status)
1515 return;
1516
1517 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1518
1519 radio_hci_req_complete(hdev, status);
1520}
1521
1522static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1523{
1524 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1525 struct iris_device *radio = video_get_drvdata(video_get_dev());
1526
1527 if (rsp->status)
1528 return;
1529
1530 radio->recv_conf = rsp->recv_conf_rsp;
1531 radio_hci_req_complete(hdev, rsp->status);
1532}
1533
1534static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1535 struct sk_buff *skb)
1536{
1537 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1538 struct iris_device *radio = video_get_drvdata(video_get_dev());
1539
1540 if (rsp->status)
1541 return;
1542
1543 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1544
1545 radio_hci_req_complete(hdev, rsp->status);
1546}
1547
Ankur Nandwanid928d542011-08-11 13:15:41 -07001548
1549static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
1550 struct sk_buff *skb)
1551{
1552 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1553 struct iris_device *radio = video_get_drvdata(video_get_dev());
1554
1555 if (rsp->status)
1556 return;
1557
1558 iris_q_event(radio, HCI_EV_CMD_COMPLETE);
1559
1560 radio_hci_req_complete(hdev, rsp->status);
1561}
1562
1563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1565 struct sk_buff *skb)
1566{
1567 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1568 struct iris_device *radio = video_get_drvdata(video_get_dev());
1569 struct v4l2_control *v4l_ctl = radio->g_ctl;
1570
1571 if (rsp->status)
1572 return;
1573
1574 v4l_ctl->value = rsp->sig_threshold;
1575
1576 radio_hci_req_complete(hdev, rsp->status);
1577}
1578
1579static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1580{
1581 struct iris_device *radio = video_get_drvdata(video_get_dev());
1582 struct hci_fm_station_rsp *rsp = (void *)skb->data;
1583 radio->fm_st_rsp = *(rsp);
1584
1585 /* Tune is always succesful */
1586 radio_hci_req_complete(hdev, 0);
1587}
1588
1589static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1590{
1591 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1592
1593 if (rsp->status)
1594 return;
1595
1596 radio_hci_req_complete(hdev, rsp->status);
1597}
1598
1599static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1600{
1601 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1602
1603 if (rsp->status)
1604 return;
1605
1606 radio_hci_req_complete(hdev, rsp->status);
1607}
1608
1609static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1610{
1611 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1612
1613 if (rsp->status)
1614 return;
1615
1616 radio_hci_req_complete(hdev, rsp->status);
1617}
1618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1620 struct sk_buff *skb)
1621{
1622 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1623 struct iris_device *radio = video_get_drvdata(video_get_dev());
1624 struct v4l2_capability *v4l_cap = radio->g_cap;
1625
1626 if (rsp->status)
1627 return;
1628 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1629 (rsp->feature_mask & 0x000001);
1630
1631 radio_hci_req_complete(hdev, rsp->status);
1632}
1633
1634static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1635 struct sk_buff *skb)
1636{
1637 struct iris_device *radio = video_get_drvdata(video_get_dev());
1638 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
1639 radio->st_dbg_param = *(rsp);
1640
1641 if (radio->st_dbg_param.status)
1642 return;
1643
1644 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1645}
1646
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001647static void iris_q_evt_data(struct iris_device *radio,
1648 char *data, int len, int event)
1649{
1650 struct kfifo *data_b = &radio->data_buf[event];
1651 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1652 wake_up_interruptible(&radio->event_queue);
1653}
1654
1655static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1656 struct sk_buff *skb)
1657{
1658 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301659 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001660 int len;
1661 char *data;
1662
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301663 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001664 return;
1665 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1666 data = kmalloc(len, GFP_ATOMIC);
1667
1668 if (!data) {
1669 FMDERR("Memory allocation failed");
1670 return;
1671 }
1672
1673 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1674 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301675 radio_hci_req_complete(hdev, status);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301676 kfree(data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001677
1678}
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301679
1680static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
1681 struct sk_buff *skb)
1682{
1683 struct iris_device *radio = video_get_drvdata(video_get_dev());
1684 __u8 status = *((__u8 *) skb->data);
1685 __u8 len;
1686 char *data;
1687
1688 if (status)
1689 return;
1690 len = skb->data[1];
1691 data = kmalloc(len+2, GFP_ATOMIC);
1692 if (!data) {
1693 FMDERR("Memory allocation failed");
1694 return;
1695 }
1696
1697 data[0] = status;
1698 data[1] = len;
1699 memcpy(&data[2], &skb->data[DEFAULT_DATA_OFFSET], len);
1700 iris_q_evt_data(radio, data, len+2, IRIS_BUF_RD_DEFAULT);
1701 radio_hci_req_complete(hdev, status);
1702 kfree(data);
1703}
1704
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001705static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1706 struct sk_buff *skb)
1707{
1708 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301709 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001710 char *data;
1711
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301712 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001713 return;
1714 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1715 if (!data) {
1716 FMDERR("Memory allocation failed");
1717 return;
1718 }
1719
1720 data[0] = skb->data[PEEK_DATA_OFSET];
1721 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301722 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001723 kfree(data);
1724}
1725
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301726static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
1727 struct sk_buff *skb)
1728{
1729 struct iris_device *radio = video_get_drvdata(video_get_dev());
1730 __u8 status = *((__u8 *) skb->data);
1731 char *data;
1732 if (status)
1733 return;
1734 data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
1735 if (!data) {
1736 FMDERR("memory allocation failed");
1737 return;
1738 }
1739 memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
1740 iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
1741 radio_hci_req_complete(hdev, status);
1742 kfree(data);
1743
1744}
1745
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301746static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
1747 struct sk_buff *skb)
1748{
1749 struct iris_device *radio = video_get_drvdata(video_get_dev());
1750 static struct hci_cc_do_calibration_rsp rsp ;
1751 rsp.status = skb->data[0];
1752 rsp.mode = skb->data[CALIB_MODE_OFSET];
1753
1754 if (rsp.status) {
1755 FMDERR("status = %d", rsp.status);
1756 return;
1757 }
1758 if (rsp.mode == PROCS_CALIB_MODE) {
1759 memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
1760 PROCS_CALIB_SIZE);
1761 } else if (rsp.mode == DC_CALIB_MODE) {
1762 memcpy(&rsp.data[PROCS_CALIB_SIZE],
1763 &skb->data[CALIB_DATA_OFSET], DC_CALIB_SIZE);
1764 iris_q_evt_data(radio, rsp.data, (PROCS_CALIB_SIZE +
1765 DC_CALIB_SIZE), IRIS_BUF_CAL_DATA);
1766 }
1767 radio_hci_req_complete(hdev, rsp.status);
1768}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
1770 struct sk_buff *skb)
1771{
1772 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
1773 __u16 opcode;
1774
1775 skb_pull(skb, sizeof(*cmd_compl_ev));
1776
1777 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
1778
1779 switch (opcode) {
1780 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
1781 hci_cc_fm_enable_rsp(hdev, skb);
1782 break;
1783 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
1784 hci_cc_conf_rsp(hdev, skb);
1785 break;
1786
1787 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
1788 hci_cc_fm_disable_rsp(hdev, skb);
1789 break;
1790
1791 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
1792 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
1793 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
1794 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
1795 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
1796 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
1797 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
1798 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
1799 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
1800 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001801 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
1802 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
1803 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
1804 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301806 hci_cc_rsp(hdev, skb);
1807 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001808 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001810 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001811 case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301812 case hci_common_cmd_op_pack(HCI_OCF_FM_SET_CALIBRATION):
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301813 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_EVENT_MASK):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814 hci_cc_rsp(hdev, skb);
1815 break;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301816
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001817 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
1818 hci_cc_ssbi_peek_rsp(hdev, skb);
1819 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
1821 hci_cc_sig_threshold_rsp(hdev, skb);
1822 break;
1823
1824 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
1825 hci_cc_station_rsp(hdev, skb);
1826 break;
1827
1828 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
1829 hci_cc_prg_srv_rsp(hdev, skb);
1830 break;
1831
1832 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
1833 hci_cc_rd_txt_rsp(hdev, skb);
1834 break;
1835
1836 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
1837 hci_cc_af_list_rsp(hdev, skb);
1838 break;
1839
1840 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301841 hci_cc_riva_read_default_rsp(hdev, skb);
1842 break;
1843
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001845 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001846 break;
1847
1848 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
1849 hci_cc_feature_list_rsp(hdev, skb);
1850 break;
1851
1852 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
1853 hci_cc_dbg_param_rsp(hdev, skb);
1854 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07001855 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_SET_TRANS_CONF_REQ):
1856 hci_cc_fm_trans_set_conf_rsp(hdev, skb);
1857 break;
1858
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301859 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
1860 hci_cc_rds_grp_cntrs_rsp(hdev, skb);
1861 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301862 case hci_common_cmd_op_pack(HCI_OCF_FM_DO_CALIBRATION):
1863 hci_cc_do_calibration_rsp(hdev, skb);
1864 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866 default:
1867 FMDERR("%s opcode 0x%x", hdev->name, opcode);
1868 break;
1869 }
1870
1871}
1872
1873static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
1874 struct sk_buff *skb)
1875{
1876 struct hci_ev_cmd_status *ev = (void *) skb->data;
1877 radio_hci_status_complete(hdev, ev->status);
1878}
1879
1880static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
1881 struct sk_buff *skb)
1882{
1883 int i;
1884 int len;
1885
1886 struct iris_device *radio = video_get_drvdata(video_get_dev());
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301887 struct hci_fm_station_rsp *rsp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001888
1889 len = sizeof(struct hci_fm_station_rsp);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301890 rsp = (struct hci_fm_station_rsp *)skb_pull(skb, len);
1891 if (rsp == NULL)
1892 return;
1893 memcpy(&radio->fm_st_rsp.station_rsp, rsp, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001894
1895 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
1896
1897 for (i = 0; i < IRIS_BUF_MAX; i++) {
1898 if (i >= IRIS_BUF_RT_RDS)
1899 kfifo_reset(&radio->data_buf[i]);
1900 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901 if (radio->fm_st_rsp.station_rsp.rssi)
1902 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1903 else
1904 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1905
1906 if (radio->fm_st_rsp.station_rsp.stereo_prg)
1907 iris_q_event(radio, IRIS_EVT_STEREO);
1908
1909 if (radio->fm_st_rsp.station_rsp.mute_mode)
1910 iris_q_event(radio, IRIS_EVT_MONO);
1911
1912 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
1913 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1914 else
1915 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1916}
1917
1918static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
1919 struct sk_buff *skb)
1920{
1921 struct iris_device *radio = video_get_drvdata(video_get_dev());
1922 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
1923}
1924
1925static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
1926 struct sk_buff *skb)
1927{
1928 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001929 struct hci_ev_srch_list_compl *ev ;
1930 int cnt;
1931 int stn_num;
1932 int rel_freq;
1933 int abs_freq;
1934 int len;
1935
1936 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1937 if (!ev) {
1938 FMDERR("Memory allocation failed");
1939 return ;
1940 }
1941
1942 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
1943 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
1944
1945 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301946 (cnt < len) && (stn_num < ev->num_stations_found)
1947 && (stn_num < ARRAY_SIZE(ev->rel_freq));
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001948 cnt += PARAMS_PER_STATION, stn_num++) {
1949 abs_freq = *((int *)&skb->data[cnt]);
1950 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
1951 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
1952
1953 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
1954 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
1955 }
1956
1957 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
1958 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
1959 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
1960 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961}
1962
1963static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
1964 struct sk_buff *skb)
1965{
1966 struct iris_device *radio = video_get_drvdata(video_get_dev());
1967 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
1968}
1969
1970static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
1971 struct sk_buff *skb)
1972{
1973 struct iris_device *radio = video_get_drvdata(video_get_dev());
1974 __u8 st_status = *((__u8 *) skb->data);
1975 if (st_status)
1976 iris_q_event(radio, IRIS_EVT_STEREO);
1977 else
1978 iris_q_event(radio, IRIS_EVT_MONO);
1979}
1980
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001981
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001982static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
1983 struct sk_buff *skb)
1984{
1985 struct iris_device *radio = video_get_drvdata(video_get_dev());
1986 int len;
1987 char *data;
1988
1989 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
1990 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
1991 data = kmalloc(len, GFP_ATOMIC);
1992 if (!data) {
1993 FMDERR("Failed to allocate memory");
1994 return;
1995 }
1996
1997 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
1998 data[1] = skb->data[RDS_PTYPE];
1999 data[2] = skb->data[RDS_PID_LOWER];
2000 data[3] = skb->data[RDS_PID_HIGHER];
2001 data[4] = 0;
2002
2003 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
2004
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002005 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002006
2007 kfree(data);
2008}
2009
2010
2011static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
2012 struct sk_buff *skb)
2013{
2014 struct iris_device *radio = video_get_drvdata(video_get_dev());
2015 int len = 0;
2016 char *data;
2017
2018 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
2019
2020 while (skb->data[len+RDS_OFFSET] != 0x0d)
2021 len++;
2022 len++;
2023
2024 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
2025 if (!data) {
2026 FMDERR("Failed to allocate memory");
2027 return;
2028 }
2029
2030 data[0] = len;
2031 data[1] = skb->data[RDS_PTYPE];
2032 data[2] = skb->data[RDS_PID_LOWER];
2033 data[3] = skb->data[RDS_PID_HIGHER];
2034 data[4] = 0;
2035
2036 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
2037 data[len+RDS_OFFSET] = 0x00;
2038
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002039 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002040
2041 kfree(data);
2042}
2043
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302044static void hci_ev_af_list(struct radio_hci_dev *hdev,
2045 struct sk_buff *skb)
2046{
2047 struct iris_device *radio = video_get_drvdata(video_get_dev());
2048 struct hci_ev_af_list ev;
2049
2050 ev.tune_freq = *((int *) &skb->data[0]);
2051 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
2052 ev.af_size = skb->data[AF_SIZE_OFFSET];
2053 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
2054 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
2055 iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
2056}
2057
2058static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
2059 struct sk_buff *skb)
2060{
2061 struct iris_device *radio = video_get_drvdata(video_get_dev());
2062 __u8 rds_status = skb->data[0];
2063
2064 if (rds_status)
2065 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2066 else
2067 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2068}
2069
2070static void hci_ev_service_available(struct radio_hci_dev *hdev,
2071 struct sk_buff *skb)
2072{
2073 struct iris_device *radio = video_get_drvdata(video_get_dev());
2074 if (radio->fm_st_rsp.station_rsp.serv_avble)
2075 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2076 else
2077 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2078}
2079
2080static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
2081 struct sk_buff *skb)
2082{
2083 struct iris_device *radio = video_get_drvdata(video_get_dev());
2084 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
2085}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002086
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
2088{
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302089 struct radio_hci_event_hdr *hdr;
2090 u8 event;
2091
2092 if (skb == NULL) {
2093 FMDERR("Socket buffer is NULL");
2094 return;
2095 }
2096
2097 hdr = (void *) skb->data;
2098 event = hdr->evt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099
2100 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
2101
2102 switch (event) {
2103 case HCI_EV_TUNE_STATUS:
2104 hci_ev_tune_status(hdev, skb);
2105 break;
2106 case HCI_EV_SEARCH_PROGRESS:
2107 case HCI_EV_SEARCH_RDS_PROGRESS:
2108 case HCI_EV_SEARCH_LIST_PROGRESS:
2109 hci_ev_search_next(hdev, skb);
2110 break;
2111 case HCI_EV_STEREO_STATUS:
2112 hci_ev_stereo_status(hdev, skb);
2113 break;
2114 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302115 hci_ev_rds_lock_status(hdev, skb);
2116 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302118 hci_ev_service_available(hdev, skb);
2119 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002120 case HCI_EV_RDS_RX_DATA:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002121 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002122 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002123 hci_ev_program_service(hdev, skb);
2124 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002125 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002126 hci_ev_radio_text(hdev, skb);
2127 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302129 hci_ev_af_list(hdev, skb);
2130 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302132 hci_ev_rds_grp_complete(hdev, skb);
2133 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002134 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2135 break;
2136
2137 case HCI_EV_CMD_COMPLETE:
2138 hci_cmd_complete_event(hdev, skb);
2139 break;
2140
2141 case HCI_EV_CMD_STATUS:
2142 hci_cmd_status_event(hdev, skb);
2143 break;
2144
2145 case HCI_EV_SEARCH_COMPLETE:
2146 case HCI_EV_SEARCH_RDS_COMPLETE:
2147 hci_ev_search_compl(hdev, skb);
2148 break;
2149
2150 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002151 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002152 break;
2153
2154 default:
2155 break;
2156 }
2157}
2158
2159/*
2160 * fops/IOCTL helper functions
2161 */
2162
2163static int iris_search(struct iris_device *radio, int on, int dir)
2164{
2165 int retval = 0;
2166 enum search_t srch = radio->g_search_mode & SRCH_MODE;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302167 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168
2169 if (on) {
2170 switch (srch) {
2171 case SCAN_FOR_STRONG:
2172 case SCAN_FOR_WEAK:
2173 radio->srch_st_list.srch_list_dir = dir;
2174 radio->srch_st_list.srch_list_mode = srch;
2175 radio->srch_st_list.srch_list_max = 0;
2176 retval = hci_fm_search_station_list(
2177 &radio->srch_st_list, radio->fm_hdev);
2178 break;
2179 case RDS_SEEK_PTY:
2180 case RDS_SCAN_PTY:
2181 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002182 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002183 radio->srch_rds.srch_station.srch_mode = srch;
2184 radio->srch_rds.srch_station.srch_dir = dir;
2185 radio->srch_rds.srch_station.scan_time =
2186 radio->g_scan_time;
2187 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2188 radio->fm_hdev);
2189 break;
2190 default:
2191 radio->srch_st.srch_mode = srch;
2192 radio->srch_st.scan_time = radio->g_scan_time;
2193 radio->srch_st.srch_dir = dir;
2194 retval = hci_fm_search_stations(
2195 &radio->srch_st, radio->fm_hdev);
2196 break;
2197 }
2198
2199 } else {
2200 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2201 }
2202
2203 return retval;
2204}
2205
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302206static int set_low_power_mode(struct iris_device *radio, int power_mode)
2207{
2208
2209 int rds_grps_proc = 0x00;
2210 int retval = 0;
2211 if (radio->power_mode != power_mode) {
2212
2213 if (power_mode) {
2214 radio->event_mask = 0x00;
2215 rds_grps_proc = 0x00 | AF_JUMP_ENABLE ;
2216 retval = hci_fm_rds_grps_process(
2217 &rds_grps_proc,
2218 radio->fm_hdev);
2219 if (retval < 0) {
2220 FMDERR("Disable RDS failed");
2221 return retval;
2222 }
2223 retval = hci_conf_event_mask(&radio->event_mask,
2224 radio->fm_hdev);
2225 } else {
2226
2227 radio->event_mask = SIG_LEVEL_INTR |
2228 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2229 retval = hci_conf_event_mask(&radio->event_mask,
2230 radio->fm_hdev);
2231 if (retval < 0) {
2232 FMDERR("Enable Async events failed");
2233 return retval;
2234 }
2235 retval = hci_fm_rds_grps_process(
2236 &radio->g_rds_grp_proc_ps,
2237 radio->fm_hdev);
2238 }
2239 radio->power_mode = power_mode;
2240 }
2241 return retval;
2242}
Ankur Nandwanid928d542011-08-11 13:15:41 -07002243static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244{
2245 int retval;
2246 radio->region = req_region;
2247
2248 switch (radio->region) {
2249 case IRIS_REGION_US:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002250 radio->recv_conf.band_low_limit =
2251 REGION_US_EU_BAND_LOW;
2252 radio->recv_conf.band_high_limit =
2253 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 break;
2255 case IRIS_REGION_EU:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002256 radio->recv_conf.band_low_limit =
2257 REGION_US_EU_BAND_LOW;
2258 radio->recv_conf.band_high_limit =
2259 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260 break;
2261 case IRIS_REGION_JAPAN:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002262 radio->recv_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002263 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302264 radio->recv_conf.band_high_limit =
2265 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002266 break;
2267 case IRIS_REGION_JAPAN_WIDE:
2268 radio->recv_conf.band_low_limit =
2269 REGION_JAPAN_WIDE_BAND_LOW;
2270 radio->recv_conf.band_high_limit =
2271 REGION_JAPAN_WIDE_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 break;
2273 default:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002274 /* The user specifies the value.
2275 So nothing needs to be done */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 break;
2277 }
2278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 retval = hci_set_fm_recv_conf(
2280 &radio->recv_conf,
2281 radio->fm_hdev);
2282
2283 return retval;
2284}
2285
Ankur Nandwanid928d542011-08-11 13:15:41 -07002286
2287static int iris_trans_set_region(struct iris_device *radio, int req_region)
2288{
2289 int retval;
2290 radio->region = req_region;
2291
2292 switch (radio->region) {
2293 case IRIS_REGION_US:
2294 radio->trans_conf.band_low_limit =
2295 REGION_US_EU_BAND_LOW;
2296 radio->trans_conf.band_high_limit =
2297 REGION_US_EU_BAND_HIGH;
2298 break;
2299 case IRIS_REGION_EU:
2300 radio->trans_conf.band_low_limit =
2301 REGION_US_EU_BAND_LOW;
2302 radio->trans_conf.band_high_limit =
2303 REGION_US_EU_BAND_HIGH;
2304 break;
2305 case IRIS_REGION_JAPAN:
2306 radio->trans_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002307 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302308 radio->trans_conf.band_high_limit =
2309 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002310 break;
2311 case IRIS_REGION_JAPAN_WIDE:
2312 radio->recv_conf.band_low_limit =
2313 REGION_JAPAN_WIDE_BAND_LOW;
2314 radio->recv_conf.band_high_limit =
2315 REGION_JAPAN_WIDE_BAND_HIGH;
2316 default:
2317 break;
2318 }
2319
2320 retval = hci_set_fm_trans_conf(
2321 &radio->trans_conf,
2322 radio->fm_hdev);
2323 return retval;
2324}
2325
2326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002327static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2328{
2329
2330 int retval;
2331 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2332 if (retval < 0)
2333 FMDERR("Error while setting the frequency : %d\n", retval);
2334 return retval;
2335}
2336
2337
2338static int iris_vidioc_queryctrl(struct file *file, void *priv,
2339 struct v4l2_queryctrl *qc)
2340{
2341 unsigned char i;
2342 int retval = -EINVAL;
2343
2344 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2345 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2346 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2347 retval = 0;
2348 break;
2349 }
2350 }
2351
2352 return retval;
2353}
2354
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302355static int iris_do_calibration(struct iris_device *radio)
2356{
2357 char cal_mode = 0x00;
2358 int retval = 0x00;
2359
2360 cal_mode = PROCS_CALIB_MODE;
2361 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2362 radio->fm_hdev);
2363 if (retval < 0) {
2364 FMDERR("Enable failed before calibration %x", retval);
2365 return retval;
2366 }
2367 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2368 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2369 if (retval < 0) {
2370 FMDERR("Do Process calibration failed %x", retval);
2371 return retval;
2372 }
2373 cal_mode = DC_CALIB_MODE;
2374 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2375 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2376 if (retval < 0) {
2377 FMDERR("Do DC calibration failed %x", retval);
2378 return retval;
2379 }
2380 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2381 radio->fm_hdev);
2382 if (retval < 0)
2383 FMDERR("Disable Failed after calibration %d", retval);
2384 return retval;
2385}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2387 struct v4l2_control *ctrl)
2388{
2389 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2390 int retval = 0;
2391
2392 switch (ctrl->id) {
2393 case V4L2_CID_AUDIO_VOLUME:
2394 break;
2395 case V4L2_CID_AUDIO_MUTE:
2396 ctrl->value = radio->mute_mode.hard_mute;
2397 break;
2398 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2399 ctrl->value = radio->g_search_mode;
2400 break;
2401 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2402 ctrl->value = radio->g_scan_time;
2403 break;
2404 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302405 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002406 break;
2407 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302408 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409 break;
2410 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2411 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2412 if (retval < 0)
2413 return retval;
2414 ctrl->value = radio->st_dbg_param.io_verc;
2415 break;
2416 case V4L2_CID_PRIVATE_IRIS_INTDET:
2417 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2418 if (retval < 0)
2419 return retval;
2420 ctrl->value = radio->st_dbg_param.in_det_out;
2421 break;
2422 case V4L2_CID_PRIVATE_IRIS_REGION:
2423 ctrl->value = radio->region;
2424 break;
2425 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2426 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
2427 break;
2428 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302429 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002430 break;
2431 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302432 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002433 break;
2434 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302435 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436 break;
2437 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002438 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002440 } else if (radio->mode == FM_TRANS) {
2441 ctrl->value = radio->trans_conf.emphasis;
2442 } else {
2443 FMDERR("Error in radio mode"
2444 " %d\n", retval);
2445 return -EINVAL;
2446 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 break;
2448 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002449 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002451 } else if (radio->mode == FM_TRANS) {
2452 ctrl->value = radio->trans_conf.rds_std;
2453 } else {
2454 FMDERR("Error in radio mode"
2455 " %d\n", retval);
2456 return -EINVAL;
2457 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 break;
2459 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002460 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002462 } else {
2463 FMDERR("Error in radio mode"
2464 " %d\n", retval);
2465 return -EINVAL;
2466 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467 break;
2468 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002469 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002471 } else {
2472 FMDERR("Error in radio mode"
2473 " %d\n", retval);
2474 return -EINVAL;
2475 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002476 break;
2477 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2478 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2479 break;
2480 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002481 case V4L2_CID_PRIVATE_IRIS_PSALL:
2482 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002483 break;
2484 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2485 ctrl->value = radio->rds_grp.rds_buf_size;
2486 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302488 ctrl->value = radio->power_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002489 break;
2490 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2491 ctrl->value = radio->g_antenna;
2492 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002493 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2494 ctrl->value = radio->mute_mode.soft_mute;
2495 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302496 case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
2497 retval = iris_do_calibration(radio);
2498 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002499 default:
2500 retval = -EINVAL;
2501 }
2502 if (retval < 0)
2503 FMDERR("get control failed with %d, id: %d\n",
2504 retval, ctrl->id);
2505 return retval;
2506}
2507
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302508static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
2509 struct v4l2_ext_controls *ctrl)
2510{
2511 int retval = 0;
2512 char *data = NULL;
2513 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2514 struct hci_fm_def_data_rd_req default_data_rd;
2515
2516 switch ((ctrl->controls[0]).id) {
2517 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
2518 data = (ctrl->controls[0]).string;
2519 memset(&default_data_rd, 0, sizeof(default_data_rd));
2520 if (copy_from_user(&default_data_rd.mode, data,
2521 sizeof(default_data_rd)))
2522 return -EFAULT;
2523 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
2524 break;
2525 default:
2526 retval = -EINVAL;
2527 }
2528
2529 return retval;
2530}
2531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002532static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2533 struct v4l2_ext_controls *ctrl)
2534{
Ankur Nandwanid928d542011-08-11 13:15:41 -07002535 int retval = 0;
2536 int bytes_to_copy;
2537 struct hci_fm_tx_ps tx_ps;
2538 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302539 struct hci_fm_def_data_wr_req default_data;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302540 struct hci_fm_set_cal_req_proc proc_cal_req;
2541 struct hci_fm_set_cal_req_dc dc_cal_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002542
2543 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2544 char *data = NULL;
2545
2546 switch ((ctrl->controls[0]).id) {
2547 case V4L2_CID_RDS_TX_PS_NAME:
2548 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2549 /*Pass a sample PS string */
2550
2551 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
2552 bytes_to_copy = min((int)(ctrl->controls[0]).size,
2553 MAX_PS_LENGTH);
2554 data = (ctrl->controls[0]).string;
2555
2556 if (copy_from_user(tx_ps.ps_data,
2557 data, bytes_to_copy))
2558 return -EFAULT;
2559 tx_ps.ps_control = 0x01;
2560 tx_ps.pi = radio->pi;
2561 tx_ps.pty = radio->pty;
2562 tx_ps.ps_repeatcount = radio->ps_repeatcount;
2563 tx_ps.ps_len = bytes_to_copy;
2564
2565 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2566 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
2567 break;
2568 case V4L2_CID_RDS_TX_RADIO_TEXT:
2569 bytes_to_copy =
2570 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2571 data = (ctrl->controls[0]).string;
2572
2573 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
2574
2575 if (copy_from_user(tx_rt.rt_data,
2576 data, bytes_to_copy))
2577 return -EFAULT;
2578
2579 tx_rt.rt_control = 0x01;
2580 tx_rt.pi = radio->pi;
2581 tx_rt.pty = radio->pty;
2582 tx_rt.ps_len = bytes_to_copy;
2583
2584 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2585 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
2586 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302587 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
2588 data = (ctrl->controls[0]).string;
2589 memset(&default_data, 0, sizeof(default_data));
2590 if (copy_from_user(&default_data, data, sizeof(default_data)))
2591 return -EFAULT;
2592 retval = hci_def_data_write(&default_data, radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302593 break;
2594 case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302595 data = (ctrl->controls[0]).string;
2596 bytes_to_copy = (ctrl->controls[0]).size;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302597 if (bytes_to_copy < (PROCS_CALIB_SIZE + DC_CALIB_SIZE)) {
2598 FMDERR("data is less than required size");
2599 return -EFAULT;
2600 }
2601 memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
2602 proc_cal_req.mode = PROCS_CALIB_MODE;
2603 if (copy_from_user(&proc_cal_req.data[0],
2604 data, sizeof(proc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302605 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302606 retval = radio_hci_request(radio->fm_hdev,
2607 hci_fm_set_cal_req_proc,
2608 (unsigned long)&proc_cal_req,
2609 RADIO_HCI_TIMEOUT);
2610 if (retval < 0) {
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302611 FMDERR("Set Process calibration failed %d", retval);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302612 return retval;
2613 }
2614 memset(dc_cal_req.data, 0, DC_CALIB_SIZE);
2615 if (copy_from_user(&dc_cal_req.data[0], &data[PROCS_CALIB_SIZE],
2616 sizeof(dc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302617 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05302618 dc_cal_req.mode = DC_CALIB_MODE;
2619 retval = radio_hci_request(radio->fm_hdev,
2620 hci_fm_set_cal_req_dc,
2621 (unsigned long)&dc_cal_req, RADIO_HCI_TIMEOUT);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302622 if (retval < 0)
2623 FMDERR("Set DC calibration failed %d", retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302624 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002625 default:
2626 FMDBG("Shouldn't reach here\n");
2627 retval = -1;
2628 }
2629 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630}
2631
2632static int iris_vidioc_s_ctrl(struct file *file, void *priv,
2633 struct v4l2_control *ctrl)
2634{
2635 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2636 int retval = 0;
2637 unsigned int rds_grps_proc = 0;
2638 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002639 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302640 struct hci_fm_tx_ps tx_ps = {0};
2641 struct hci_fm_tx_rt tx_rt = {0};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002642
2643 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302644 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002645 radio->tone_freq = ctrl->value;
2646 retval = radio_hci_request(radio->fm_hdev,
2647 hci_fm_tone_generator, arg,
2648 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
2649 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002650 case V4L2_CID_AUDIO_VOLUME:
2651 break;
2652 case V4L2_CID_AUDIO_MUTE:
2653 radio->mute_mode.hard_mute = ctrl->value;
2654 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
2655 retval = hci_set_fm_mute_mode(
2656 &radio->mute_mode,
2657 radio->fm_hdev);
2658 if (retval < 0)
2659 FMDERR("Error while set FM hard mute"" %d\n",
2660 retval);
2661 break;
2662 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2663 radio->g_search_mode = ctrl->value;
2664 break;
2665 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2666 radio->g_scan_time = ctrl->value;
2667 break;
2668 case V4L2_CID_PRIVATE_IRIS_SRCHON:
2669 iris_search(radio, ctrl->value, SRCH_DIR_UP);
2670 break;
2671 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002672 switch (ctrl->value) {
2673 case FM_RECV:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2675 radio->fm_hdev);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002676
2677 radio->mode = FM_RECV;
2678
2679 if (retval < 0)
2680 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002681 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002682 radio->mute_mode.soft_mute = CTRL_ON;
2683 retval = hci_set_fm_mute_mode(
2684 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002685 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302686 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002687 FMDERR("Failed to enable Smute\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302688 return retval;
2689 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002690 radio->stereo_mode.stereo_mode = CTRL_OFF;
2691 radio->stereo_mode.sig_blend = CTRL_ON;
2692 radio->stereo_mode.intf_blend = CTRL_ON;
2693 radio->stereo_mode.most_switch = CTRL_ON;
2694 retval = hci_set_fm_stereo_mode(
2695 &radio->stereo_mode,
2696 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302697 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002698 FMDERR("Failed to set stereo mode\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302699 return retval;
2700 }
Srinivasa Rao Uppalaf1febce2011-11-09 10:30:16 +05302701 radio->event_mask = SIG_LEVEL_INTR |
2702 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2703 retval = hci_conf_event_mask(&radio->event_mask,
2704 radio->fm_hdev);
2705 if (retval < 0) {
2706 FMDERR("Enable Async events failed");
2707 return retval;
2708 }
Srinivasa Rao Uppalaf0d13742011-09-08 10:13:13 +05302709 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2710 radio->fm_hdev);
2711 if (retval < 0)
2712 FMDERR("Failed to get the Recv Config\n");
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002713 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002714 case FM_TRANS:
2715 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
2716 radio->fm_hdev);
2717 radio->mode = FM_TRANS;
2718
2719 if (retval < 0)
2720 FMDERR("Error while enabling TRANS FM"
2721 " %d\n", retval);
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002722 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002723 case FM_OFF:
2724 switch (radio->mode) {
2725 case FM_RECV:
2726 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2727 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002729 FMDERR("Err on disable recv FM"
2730 " %d\n", retval);
2731 break;
2732 case FM_TRANS:
2733 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
2734 radio->fm_hdev);
2735
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002736 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002737 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002738 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002739 break;
2740 default:
2741 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002742 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302743 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002744 default:
2745 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002746 }
2747 break;
2748 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002749 if (radio->mode == FM_RECV) {
2750 retval = iris_recv_set_region(radio, ctrl->value);
2751 } else {
2752 if (radio->mode == FM_TRANS)
2753 retval = iris_trans_set_region(radio,
2754 ctrl->value);
2755 else
2756 retval = -EINVAL;
2757 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758 break;
2759 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2760 temp_val = ctrl->value;
2761 retval = hci_fm_set_signal_threshold(
2762 &temp_val,
2763 radio->fm_hdev);
2764 if (retval < 0) {
2765 FMDERR("Error while setting signal threshold\n");
2766 break;
2767 }
2768 break;
2769 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
2770 radio->srch_rds.srch_pty = ctrl->value;
2771 radio->srch_st_list.srch_pty = ctrl->value;
2772 break;
2773 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
2774 radio->srch_rds.srch_pi = ctrl->value;
2775 break;
2776 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
2777 break;
2778 case V4L2_CID_PRIVATE_IRIS_SPACING:
Venkateshwarlu Domakonda45496f12011-11-23 12:51:13 +05302779 if (radio->mode == FM_RECV) {
2780 radio->recv_conf.ch_spacing = ctrl->value;
2781 retval = hci_set_fm_recv_conf(
2782 &radio->recv_conf,
2783 radio->fm_hdev);
2784 if (retval < 0)
2785 FMDERR("Error in setting channel spacing");
2786 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002787 break;
2788 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002789 switch (radio->mode) {
2790 case FM_RECV:
2791 radio->recv_conf.emphasis = ctrl->value;
2792 retval = hci_set_fm_recv_conf(
2793 &radio->recv_conf,
2794 radio->fm_hdev);
2795 if (retval < 0)
2796 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002797 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002798 case FM_TRANS:
2799 radio->trans_conf.emphasis = ctrl->value;
2800 retval = hci_set_fm_trans_conf(
2801 &radio->trans_conf,
2802 radio->fm_hdev);
2803 if (retval < 0)
2804 FMDERR("Error in setting emphasis");
2805 break;
2806 default:
2807 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002808 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002809 break;
2810 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002811 switch (radio->mode) {
2812 case FM_RECV:
2813 radio->recv_conf.rds_std = ctrl->value;
2814 retval = hci_set_fm_recv_conf(
2815 &radio->recv_conf,
2816 radio->fm_hdev);
2817 if (retval < 0)
2818 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002819 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002820 case FM_TRANS:
2821 radio->trans_conf.rds_std = ctrl->value;
2822 retval = hci_set_fm_trans_conf(
2823 &radio->trans_conf,
2824 radio->fm_hdev);
2825 if (retval < 0)
2826 FMDERR("Error in rds_Std");
2827 break;
2828 default:
2829 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002830 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002831 break;
2832 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002833 switch (radio->mode) {
2834 case FM_RECV:
2835 radio->recv_conf.rds_std = ctrl->value;
2836 retval = hci_set_fm_recv_conf(
2837 &radio->recv_conf,
2838 radio->fm_hdev);
2839 if (retval < 0)
2840 FMDERR("Error in rds_std");
2841 break;
2842 case FM_TRANS:
2843 radio->trans_conf.rds_std = ctrl->value;
2844 retval = hci_set_fm_trans_conf(
2845 &radio->trans_conf,
2846 radio->fm_hdev);
2847 if (retval < 0)
2848 FMDERR("Error in rds_Std");
2849 break;
2850 default:
2851 retval = -EINVAL;
2852 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002853 break;
2854 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2855 radio->rds_grp.rds_grp_enable_mask = ctrl->value;
2856 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
2857 break;
2858 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
2859 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002860 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002861 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002862 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002863 radio->fm_hdev);
2864 break;
2865 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2866 radio->rds_grp.rds_buf_size = ctrl->value;
2867 break;
2868 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002869 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
2870 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2871 retval = hci_fm_rds_grps_process(
2872 &radio->g_rds_grp_proc_ps,
2873 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002874 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302875 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
2876 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_OFFSET);
2877 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2878 retval = hci_fm_rds_grps_process(
2879 &radio->g_rds_grp_proc_ps,
2880 radio->fm_hdev);
2881 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002882 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302883 set_low_power_mode(radio, ctrl->value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002884 break;
2885 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2886 temp_val = ctrl->value;
2887 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
2888 break;
2889 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002890 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891 break;
2892 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002893 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002894 break;
2895 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302896 tx_ps.ps_control = 0x00;
2897 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2898 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002899 break;
2900 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302901 tx_rt.rt_control = 0x00;
2902 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2903 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002904 break;
2905 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002906 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002907 break;
2908 case V4L2_CID_TUNE_POWER_LEVEL:
2909 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002910 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2911 radio->mute_mode.soft_mute = ctrl->value;
2912 retval = hci_set_fm_mute_mode(
2913 &radio->mute_mode,
2914 radio->fm_hdev);
2915 if (retval < 0)
2916 FMDERR("Error while setting FM soft mute"" %d\n",
2917 retval);
2918 break;
2919 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
2920 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
2921 break;
2922 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
2923 radio->riva_data_req.cmd_params.length = ctrl->value;
2924 break;
2925 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
2926 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
2927 radio->riva_data_req.cmd_params.length);
2928 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
2929 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
2930 break;
2931 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
2932 radio->ssbi_data_accs.start_addr = ctrl->value;
2933 break;
2934 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
2935 radio->ssbi_data_accs.data = ctrl->value;
2936 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
2937 radio->fm_hdev);
2938 break;
2939 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
2940 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
2941 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
2942 radio->fm_hdev);
2943 break;
2944 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
2945 radio->ssbi_peek_reg.start_address = ctrl->value;
2946 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
2947 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302948 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
2949 temp_val = ctrl->value;
2950 hci_read_grp_counters(&temp_val, radio->fm_hdev);
2951 break;
2952 case V4L2_CID_PRIVATE_IRIS_HLSI:
2953 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2954 radio->fm_hdev);
2955 if (retval)
2956 break;
2957 radio->recv_conf.hlsi = ctrl->value;
2958 retval = hci_set_fm_recv_conf(
2959 &radio->recv_conf,
2960 radio->fm_hdev);
2961 break;
2962 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
2963 temp_val = ctrl->value;
2964 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
2965 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002966
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002967 default:
2968 retval = -EINVAL;
2969 }
2970 return retval;
2971}
2972
2973static int iris_vidioc_g_tuner(struct file *file, void *priv,
2974 struct v4l2_tuner *tuner)
2975{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002977 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978 if (tuner->index > 0)
2979 return -EINVAL;
2980
2981 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
2982 if (retval < 0)
2983 return retval;
2984
2985 tuner->type = V4L2_TUNER_RADIO;
2986 tuner->rangelow = radio->recv_conf.band_low_limit * TUNE_PARAM;
2987 tuner->rangehigh = radio->recv_conf.band_high_limit * TUNE_PARAM;
2988 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
2989 tuner->capability = V4L2_TUNER_CAP_LOW;
2990 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
2991 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
2992 tuner->afc = 0;
2993
2994 return 0;
2995}
2996
2997static int iris_vidioc_s_tuner(struct file *file, void *priv,
2998 struct v4l2_tuner *tuner)
2999{
3000 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07003001 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003002 if (tuner->index > 0)
3003 return -EINVAL;
3004
Ankur Nandwanid928d542011-08-11 13:15:41 -07003005 if (radio->mode == FM_RECV) {
3006 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
3007 radio->recv_conf.band_high_limit =
3008 tuner->rangehigh / TUNE_PARAM;
3009 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
3010 radio->stereo_mode.stereo_mode = 0x01;
3011 retval = hci_set_fm_stereo_mode(
3012 &radio->stereo_mode,
3013 radio->fm_hdev);
3014 } else {
3015 radio->stereo_mode.stereo_mode = 0x00;
3016 retval = hci_set_fm_stereo_mode(
3017 &radio->stereo_mode,
3018 radio->fm_hdev);
3019 }
3020 if (retval < 0)
3021 FMDERR(": set tuner failed with %d\n", retval);
3022 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023 } else {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003024 if (radio->mode == FM_TRANS) {
3025 radio->trans_conf.band_low_limit =
3026 tuner->rangelow / TUNE_PARAM;
3027 radio->trans_conf.band_high_limit =
3028 tuner->rangehigh / TUNE_PARAM;
3029 } else {
3030 return -EINVAL;
3031 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003032 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07003033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 return retval;
3035}
3036
3037static int iris_vidioc_g_frequency(struct file *file, void *priv,
3038 struct v4l2_frequency *freq)
3039{
3040 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3041 int retval;
3042
3043 freq->type = V4L2_TUNER_RADIO;
3044 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3045 if (retval < 0)
3046 FMDERR("get frequency failed %d\n", retval);
3047 else
3048 freq->frequency =
3049 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
3050 return retval;
3051}
3052
3053static int iris_vidioc_s_frequency(struct file *file, void *priv,
3054 struct v4l2_frequency *freq)
3055{
3056 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3057 int retval = -1;
3058 freq->frequency = freq->frequency / TUNE_PARAM;
3059
3060 if (freq->type != V4L2_TUNER_RADIO)
3061 return -EINVAL;
3062
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003063 /* We turn off RDS prior to tuning to a new station.
3064 because of a bug in SoC which prevents tuning
3065 during RDS transmission.
3066 */
3067 if (radio->mode == FM_TRANS
3068 && (radio->trans_conf.rds_std == 0 ||
3069 radio->trans_conf.rds_std == 1)) {
3070 radio->prev_trans_rds = radio->trans_conf.rds_std;
3071 radio->trans_conf.rds_std = 2;
3072 hci_set_fm_trans_conf(&radio->trans_conf,
3073 radio->fm_hdev);
3074 }
3075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003077
3078 if (radio->mode == FM_TRANS
3079 && radio->trans_conf.rds_std == 2
3080 && (radio->prev_trans_rds == 1
3081 || radio->prev_trans_rds == 0)) {
3082 radio->trans_conf.rds_std = radio->prev_trans_rds;
3083 hci_set_fm_trans_conf(&radio->trans_conf,
3084 radio->fm_hdev);
3085 }
3086
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003087 if (retval < 0)
3088 FMDERR(" set frequency failed with %d\n", retval);
3089 return retval;
3090}
3091
3092static int iris_vidioc_dqbuf(struct file *file, void *priv,
3093 struct v4l2_buffer *buffer)
3094{
3095 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3096 enum iris_buf_t buf_type = buffer->index;
3097 struct kfifo *data_fifo;
3098 unsigned char *buf = (unsigned char *)buffer->m.userptr;
3099 unsigned int len = buffer->length;
3100 if (!access_ok(VERIFY_WRITE, buf, len))
3101 return -EFAULT;
3102 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
3103 data_fifo = &radio->data_buf[buf_type];
3104 if (buf_type == IRIS_BUF_EVENTS)
3105 if (wait_event_interruptible(radio->event_queue,
3106 kfifo_len(data_fifo)) < 0)
3107 return -EINTR;
3108 } else {
3109 FMDERR("invalid buffer type\n");
3110 return -EINVAL;
3111 }
3112 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3113 &radio->buf_lock[buf_type]);
3114
3115 return 0;
3116}
3117
3118static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
3119 struct v4l2_format *f)
3120{
3121 return 0;
3122
3123}
3124
3125static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3126 struct v4l2_hw_freq_seek *seek)
3127{
3128 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3129 int dir;
3130 if (seek->seek_upward)
3131 dir = SRCH_DIR_UP;
3132 else
3133 dir = SRCH_DIR_DOWN;
3134 return iris_search(radio, CTRL_ON, dir);
3135}
3136
3137static int iris_vidioc_querycap(struct file *file, void *priv,
3138 struct v4l2_capability *capability)
3139{
3140 struct iris_device *radio;
3141 radio = video_get_drvdata(video_devdata(file));
3142 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
3143 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
3144 radio->g_cap = capability;
3145 return 0;
3146}
3147
3148
3149static const struct v4l2_ioctl_ops iris_ioctl_ops = {
3150 .vidioc_querycap = iris_vidioc_querycap,
3151 .vidioc_queryctrl = iris_vidioc_queryctrl,
3152 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
3153 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
3154 .vidioc_g_tuner = iris_vidioc_g_tuner,
3155 .vidioc_s_tuner = iris_vidioc_s_tuner,
3156 .vidioc_g_frequency = iris_vidioc_g_frequency,
3157 .vidioc_s_frequency = iris_vidioc_s_frequency,
3158 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
3159 .vidioc_dqbuf = iris_vidioc_dqbuf,
3160 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
3161 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303162 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163};
3164
3165static const struct v4l2_file_operations iris_fops = {
3166 .owner = THIS_MODULE,
3167 .unlocked_ioctl = video_ioctl2,
3168};
3169
3170static struct video_device iris_viddev_template = {
3171 .fops = &iris_fops,
3172 .ioctl_ops = &iris_ioctl_ops,
3173 .name = DRIVER_NAME,
3174 .release = video_device_release,
3175};
3176
3177static struct video_device *video_get_dev(void)
3178{
3179 return priv_videodev;
3180}
3181
3182static int __init iris_probe(struct platform_device *pdev)
3183{
3184 struct iris_device *radio;
3185 int retval;
3186 int radio_nr = -1;
3187 int i;
3188
3189 if (!pdev) {
3190 FMDERR(": pdev is null\n");
3191 return -ENOMEM;
3192 }
3193
3194 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
3195 if (!radio) {
3196 FMDERR(": Could not allocate radio device\n");
3197 return -ENOMEM;
3198 }
3199
3200 radio->dev = &pdev->dev;
3201 platform_set_drvdata(pdev, radio);
3202
3203 radio->videodev = video_device_alloc();
3204 if (!radio->videodev) {
3205 FMDERR(": Could not allocate V4L device\n");
3206 kfree(radio);
3207 return -ENOMEM;
3208 }
3209
3210 memcpy(radio->videodev, &iris_viddev_template,
3211 sizeof(iris_viddev_template));
3212
3213 for (i = 0; i < IRIS_BUF_MAX; i++) {
3214 int kfifo_alloc_rc = 0;
3215 spin_lock_init(&radio->buf_lock[i]);
3216
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07003217 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3219 rds_buf*3, GFP_KERNEL);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05303220 else if (i == IRIS_BUF_CAL_DATA)
3221 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3222 STD_BUF_SIZE*2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003223 else
3224 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3225 STD_BUF_SIZE, GFP_KERNEL);
3226
3227 if (kfifo_alloc_rc != 0) {
3228 FMDERR("failed allocating buffers %d\n",
3229 kfifo_alloc_rc);
3230 for (; i > -1; i--) {
3231 kfifo_free(&radio->data_buf[i]);
3232 kfree(radio);
3233 return -ENOMEM;
3234 }
3235 }
3236 }
3237
3238 mutex_init(&radio->lock);
3239 init_completion(&radio->sync_xfr_start);
3240 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003241 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 init_waitqueue_head(&radio->event_queue);
3243 init_waitqueue_head(&radio->read_queue);
3244
3245 video_set_drvdata(radio->videodev, radio);
3246
3247 if (NULL == video_get_drvdata(radio->videodev))
3248 FMDERR(": video_get_drvdata failed\n");
3249
3250 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
3251 radio_nr);
3252 if (retval) {
3253 FMDERR(": Could not register video device\n");
3254 video_device_release(radio->videodev);
3255 for (; i > -1; i--)
3256 kfifo_free(&radio->data_buf[i]);
3257 kfree(radio);
3258 return retval;
3259 } else {
3260 priv_videodev = kzalloc(sizeof(struct video_device),
3261 GFP_KERNEL);
3262 memcpy(priv_videodev, radio->videodev,
3263 sizeof(struct video_device));
3264 }
3265 return 0;
3266}
3267
3268
3269static int __devexit iris_remove(struct platform_device *pdev)
3270{
3271 int i;
3272 struct iris_device *radio = platform_get_drvdata(pdev);
3273
3274 video_unregister_device(radio->videodev);
3275
3276 for (i = 0; i < IRIS_BUF_MAX; i++)
3277 kfifo_free(&radio->data_buf[i]);
3278
3279 kfree(radio);
3280
3281 platform_set_drvdata(pdev, NULL);
3282
3283 return 0;
3284}
3285
3286static struct platform_driver iris_driver = {
3287 .driver = {
3288 .owner = THIS_MODULE,
3289 .name = "iris_fm",
3290 },
3291 .remove = __devexit_p(iris_remove),
3292};
3293
3294static int __init iris_radio_init(void)
3295{
3296 return platform_driver_probe(&iris_driver, iris_probe);
3297}
3298module_init(iris_radio_init);
3299
3300static void __exit iris_radio_exit(void)
3301{
3302 platform_driver_unregister(&iris_driver);
3303}
3304module_exit(iris_radio_exit);
3305
3306MODULE_LICENSE("GPL v2");
3307MODULE_AUTHOR(DRIVER_AUTHOR);
3308MODULE_DESCRIPTION(DRIVER_DESC);