blob: e8e97702dc6d16359fe0cf30873ae61dc2bbaaab [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define DRIVER_AUTHOR "Archana Ramchandran <archanar@codeaurora.org>"
14#define DRIVER_NAME "radio-iris"
15#define DRIVER_CARD "Qualcomm FM Radio Transceiver"
16#define DRIVER_DESC "Driver for Qualcomm FM Radio Transceiver "
17
18#include <linux/version.h>
19#include <linux/init.h>
20#include <linux/delay.h>
21#include <linux/uaccess.h>
22#include <linux/kfifo.h>
23#include <linux/param.h>
24#include <linux/interrupt.h>
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/version.h>
28#include <linux/videodev2.h>
29#include <linux/mutex.h>
30#include <linux/unistd.h>
31#include <linux/atomic.h>
32#include <linux/platform_device.h>
33#include <linux/workqueue.h>
34#include <linux/slab.h>
35#include <media/v4l2-common.h>
36#include <media/v4l2-ioctl.h>
37#include <media/radio-iris.h>
38#include <asm/unaligned.h>
39
40static unsigned int rds_buf = 100;
41module_param(rds_buf, uint, 0);
42MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
43
44static void radio_hci_cmd_task(unsigned long arg);
45static void radio_hci_rx_task(unsigned long arg);
46static struct video_device *video_get_dev(void);
47static DEFINE_RWLOCK(hci_task_lock);
48
49struct iris_device {
50 struct device *dev;
51 struct kfifo data_buf[IRIS_BUF_MAX];
52
53 int pending_xfrs[IRIS_XFR_MAX];
54 int xfr_bytes_left;
55 int xfr_in_progress;
56 struct completion sync_xfr_start;
57 int tune_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -070058 unsigned int mode;
59
60 __u16 pi;
61 __u8 pty;
62 __u8 ps_repeatcount;
Ankur Nandwani8f972e52011-08-24 11:48:32 -070063 __u8 prev_trans_rds;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064
65 struct video_device *videodev;
66
67 struct mutex lock;
68 spinlock_t buf_lock[IRIS_BUF_MAX];
69 wait_queue_head_t event_queue;
70 wait_queue_head_t read_queue;
71
72 struct radio_hci_dev *fm_hdev;
73
74 struct v4l2_capability *g_cap;
75 struct v4l2_control *g_ctl;
76
77 struct hci_fm_mute_mode_req mute_mode;
78 struct hci_fm_stereo_mode_req stereo_mode;
79 struct hci_fm_station_rsp fm_st_rsp;
80 struct hci_fm_search_station_req srch_st;
81 struct hci_fm_search_rds_station_req srch_rds;
82 struct hci_fm_search_station_list_req srch_st_list;
83 struct hci_fm_recv_conf_req recv_conf;
Ankur Nandwanid928d542011-08-11 13:15:41 -070084 struct hci_fm_trans_conf_req_struct trans_conf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085 struct hci_fm_rds_grp_req rds_grp;
86 unsigned char g_search_mode;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +053087 int search_on;
Ankur Nandwanid928d542011-08-11 13:15:41 -070088 unsigned int tone_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089 unsigned char g_scan_time;
90 unsigned int g_antenna;
91 unsigned int g_rds_grp_proc_ps;
92 enum iris_region_t region;
93 struct hci_fm_dbg_param_rsp st_dbg_param;
94 struct hci_ev_srch_list_compl srch_st_result;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -070095 struct hci_fm_riva_poke riva_data_req;
96 struct hci_fm_ssbi_req ssbi_data_accs;
97 struct hci_fm_ssbi_peek ssbi_peek_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098};
99
100static struct video_device *priv_videodev;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530101static int iris_do_calibration(struct iris_device *radio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102
103static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
104 {
105 .id = V4L2_CID_AUDIO_VOLUME,
106 .type = V4L2_CTRL_TYPE_INTEGER,
107 .name = "Volume",
108 .minimum = 0,
109 .maximum = 15,
110 .step = 1,
111 .default_value = 15,
112 },
113 {
114 .id = V4L2_CID_AUDIO_BALANCE,
115 .flags = V4L2_CTRL_FLAG_DISABLED,
116 },
117 {
118 .id = V4L2_CID_AUDIO_BASS,
119 .flags = V4L2_CTRL_FLAG_DISABLED,
120 },
121 {
122 .id = V4L2_CID_AUDIO_TREBLE,
123 .flags = V4L2_CTRL_FLAG_DISABLED,
124 },
125 {
126 .id = V4L2_CID_AUDIO_MUTE,
127 .type = V4L2_CTRL_TYPE_BOOLEAN,
128 .name = "Mute",
129 .minimum = 0,
130 .maximum = 1,
131 .step = 1,
132 .default_value = 1,
133 },
134 {
135 .id = V4L2_CID_AUDIO_LOUDNESS,
136 .flags = V4L2_CTRL_FLAG_DISABLED,
137 },
138 {
139 .id = V4L2_CID_PRIVATE_IRIS_SRCHMODE,
140 .type = V4L2_CTRL_TYPE_INTEGER,
141 .name = "Search mode",
142 .minimum = 0,
143 .maximum = 7,
144 .step = 1,
145 .default_value = 0,
146 },
147 {
148 .id = V4L2_CID_PRIVATE_IRIS_SCANDWELL,
149 .type = V4L2_CTRL_TYPE_INTEGER,
150 .name = "Search dwell time",
151 .minimum = 0,
152 .maximum = 7,
153 .step = 1,
154 .default_value = 0,
155 },
156 {
157 .id = V4L2_CID_PRIVATE_IRIS_SRCHON,
158 .type = V4L2_CTRL_TYPE_BOOLEAN,
159 .name = "Search on/off",
160 .minimum = 0,
161 .maximum = 1,
162 .step = 1,
163 .default_value = 1,
164
165 },
166 {
167 .id = V4L2_CID_PRIVATE_IRIS_STATE,
168 .type = V4L2_CTRL_TYPE_INTEGER,
169 .name = "radio 0ff/rx/tx/reset",
170 .minimum = 0,
171 .maximum = 3,
172 .step = 1,
173 .default_value = 1,
174
175 },
176 {
177 .id = V4L2_CID_PRIVATE_IRIS_REGION,
178 .type = V4L2_CTRL_TYPE_INTEGER,
179 .name = "radio standard",
180 .minimum = 0,
181 .maximum = 2,
182 .step = 1,
183 .default_value = 0,
184 },
185 {
186 .id = V4L2_CID_PRIVATE_IRIS_SIGNAL_TH,
187 .type = V4L2_CTRL_TYPE_INTEGER,
188 .name = "Signal Threshold",
189 .minimum = 0x80,
190 .maximum = 0x7F,
191 .step = 1,
192 .default_value = 0,
193 },
194 {
195 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PTY,
196 .type = V4L2_CTRL_TYPE_INTEGER,
197 .name = "Search PTY",
198 .minimum = 0,
199 .maximum = 31,
200 .default_value = 0,
201 },
202 {
203 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PI,
204 .type = V4L2_CTRL_TYPE_INTEGER,
205 .name = "Search PI",
206 .minimum = 0,
207 .maximum = 0xFF,
208 .default_value = 0,
209 },
210 {
211 .id = V4L2_CID_PRIVATE_IRIS_SRCH_CNT,
212 .type = V4L2_CTRL_TYPE_INTEGER,
213 .name = "Preset num",
214 .minimum = 0,
215 .maximum = 12,
216 .default_value = 0,
217 },
218 {
219 .id = V4L2_CID_PRIVATE_IRIS_EMPHASIS,
220 .type = V4L2_CTRL_TYPE_BOOLEAN,
221 .name = "Emphasis",
222 .minimum = 0,
223 .maximum = 1,
224 .default_value = 0,
225 },
226 {
227 .id = V4L2_CID_PRIVATE_IRIS_RDS_STD,
228 .type = V4L2_CTRL_TYPE_BOOLEAN,
229 .name = "RDS standard",
230 .minimum = 0,
231 .maximum = 1,
232 .default_value = 0,
233 },
234 {
235 .id = V4L2_CID_PRIVATE_IRIS_SPACING,
236 .type = V4L2_CTRL_TYPE_INTEGER,
237 .name = "Channel spacing",
238 .minimum = 0,
239 .maximum = 2,
240 .default_value = 0,
241 },
242 {
243 .id = V4L2_CID_PRIVATE_IRIS_RDSON,
244 .type = V4L2_CTRL_TYPE_BOOLEAN,
245 .name = "RDS on/off",
246 .minimum = 0,
247 .maximum = 1,
248 .default_value = 0,
249 },
250 {
251 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK,
252 .type = V4L2_CTRL_TYPE_INTEGER,
253 .name = "RDS group mask",
254 .minimum = 0,
255 .maximum = 0xFFFFFFFF,
256 .default_value = 0,
257 },
258 {
259 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC,
260 .type = V4L2_CTRL_TYPE_INTEGER,
261 .name = "RDS processing",
262 .minimum = 0,
263 .maximum = 0xFF,
264 .default_value = 0,
265 },
266 {
267 .id = V4L2_CID_PRIVATE_IRIS_RDSD_BUF,
268 .type = V4L2_CTRL_TYPE_INTEGER,
269 .name = "RDS data groups to buffer",
270 .minimum = 1,
271 .maximum = 21,
272 .default_value = 0,
273 },
274 {
275 .id = V4L2_CID_PRIVATE_IRIS_PSALL,
276 .type = V4L2_CTRL_TYPE_BOOLEAN,
277 .name = "pass all ps strings",
278 .minimum = 0,
279 .maximum = 1,
280 .default_value = 0,
281 },
282 {
283 .id = V4L2_CID_PRIVATE_IRIS_LP_MODE,
284 .type = V4L2_CTRL_TYPE_BOOLEAN,
285 .name = "Low power mode",
286 .minimum = 0,
287 .maximum = 1,
288 .default_value = 0,
289 },
290 {
291 .id = V4L2_CID_PRIVATE_IRIS_ANTENNA,
292 .type = V4L2_CTRL_TYPE_BOOLEAN,
293 .name = "headset/internal",
294 .minimum = 0,
295 .maximum = 1,
296 .default_value = 0,
297 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 {
299 .id = V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT,
300 .type = V4L2_CTRL_TYPE_INTEGER,
301 .name = "Set PS REPEATCOUNT",
302 .minimum = 0,
303 .maximum = 15,
304 },
305 {
306 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME,
307 .type = V4L2_CTRL_TYPE_BOOLEAN,
308 .name = "Stop PS NAME",
309 .minimum = 0,
310 .maximum = 1,
311 },
312 {
313 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT,
314 .type = V4L2_CTRL_TYPE_BOOLEAN,
315 .name = "Stop RT",
316 .minimum = 0,
317 .maximum = 1,
318 },
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700319 {
320 .id = V4L2_CID_PRIVATE_IRIS_SOFT_MUTE,
321 .type = V4L2_CTRL_TYPE_BOOLEAN,
322 .name = "Soft Mute",
323 .minimum = 0,
324 .maximum = 1,
325 },
326 {
327 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR,
328 .type = V4L2_CTRL_TYPE_BOOLEAN,
329 .name = "Riva addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530330 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700331 .maximum = 0x31E0004,
332 },
333 {
334 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN,
335 .type = V4L2_CTRL_TYPE_INTEGER,
336 .name = "Data len",
337 .minimum = 0,
338 .maximum = 0xFF,
339 },
340 {
341 .id = V4L2_CID_PRIVATE_IRIS_RIVA_PEEK,
342 .type = V4L2_CTRL_TYPE_BOOLEAN,
343 .name = "Riva peek",
344 .minimum = 0,
345 .maximum = 1,
346 },
347 {
348 .id = V4L2_CID_PRIVATE_IRIS_RIVA_POKE,
349 .type = V4L2_CTRL_TYPE_INTEGER,
350 .name = "Riva poke",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530351 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700352 .maximum = 0x31E0004,
353 },
354 {
355 .id = V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR,
356 .type = V4L2_CTRL_TYPE_INTEGER,
357 .name = "Ssbi addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530358 .minimum = 0x280,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700359 .maximum = 0x37F,
360 },
361 {
362 .id = V4L2_CID_PRIVATE_IRIS_SSBI_PEEK,
363 .type = V4L2_CTRL_TYPE_INTEGER,
364 .name = "Ssbi peek",
365 .minimum = 0,
366 .maximum = 0x37F,
367 },
368 {
369 .id = V4L2_CID_PRIVATE_IRIS_SSBI_POKE,
370 .type = V4L2_CTRL_TYPE_INTEGER,
371 .name = "ssbi poke",
372 .minimum = 0x01,
373 .maximum = 0xFF,
374 },
375 {
376 .id = V4L2_CID_PRIVATE_IRIS_HLSI,
377 .type = V4L2_CTRL_TYPE_INTEGER,
378 .name = "set hlsi",
379 .minimum = 0,
380 .maximum = 2,
381 },
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530382 {
383 .id = V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS,
384 .type = V4L2_CTRL_TYPE_BOOLEAN,
385 .name = "RDS grp",
386 .minimum = 0,
387 .maximum = 1,
388 },
389 {
390 .id = V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER,
391 .type = V4L2_CTRL_TYPE_INTEGER,
392 .name = "Notch filter",
393 .minimum = 0,
394 .maximum = 2,
395 },
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530396 {
397 .id = V4L2_CID_PRIVATE_IRIS_READ_DEFAULT,
398 .type = V4L2_CTRL_TYPE_INTEGER,
399 .name = "Read default",
400 },
401 {
402 .id = V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT,
403 .type = V4L2_CTRL_TYPE_INTEGER,
404 .name = "Write default",
405 },
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530406 {
407 .id = V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION,
408 .type = V4L2_CTRL_TYPE_BOOLEAN,
409 .name = "SET Calibration",
410 .minimum = 0,
411 .maximum = 1,
412 },
413 {
414 .id = V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION,
415 .type = V4L2_CTRL_TYPE_BOOLEAN,
416 .name = "SET Calibration",
417 .minimum = 0,
418 .maximum = 1,
419 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420};
421
422static void iris_q_event(struct iris_device *radio,
423 enum iris_evt_t event)
424{
425 struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
426 unsigned char evt = event;
427 if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
428 wake_up_interruptible(&radio->event_queue);
429}
430
431static int hci_send_frame(struct sk_buff *skb)
432{
433 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
434
435 if (!hdev) {
436 kfree_skb(skb);
437 return -ENODEV;
438 }
439
440 __net_timestamp(skb);
441
442 skb_orphan(skb);
443 return hdev->send(skb);
444}
445
446static void radio_hci_cmd_task(unsigned long arg)
447{
448 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
449 struct sk_buff *skb;
450 if (!(atomic_read(&hdev->cmd_cnt))
451 && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
452 FMDERR("%s command tx timeout", hdev->name);
453 atomic_set(&hdev->cmd_cnt, 1);
454 }
455
456 skb = skb_dequeue(&hdev->cmd_q);
457 if (atomic_read(&hdev->cmd_cnt) && skb) {
458 kfree_skb(hdev->sent_cmd);
459 hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
460 if (hdev->sent_cmd) {
461 atomic_dec(&hdev->cmd_cnt);
462 hci_send_frame(skb);
463 hdev->cmd_last_tx = jiffies;
464 } else {
465 skb_queue_head(&hdev->cmd_q, skb);
466 tasklet_schedule(&hdev->cmd_task);
467 }
468 }
469
470}
471
472static void radio_hci_rx_task(unsigned long arg)
473{
474 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
475 struct sk_buff *skb;
476
477 read_lock(&hci_task_lock);
478
479 skb = skb_dequeue(&hdev->rx_q);
480 radio_hci_event_packet(hdev, skb);
481
482 read_unlock(&hci_task_lock);
483}
484
485int radio_hci_register_dev(struct radio_hci_dev *hdev)
486{
487 struct iris_device *radio = video_get_drvdata(video_get_dev());
488 if (!radio) {
489 FMDERR(":radio is null");
490 return -EINVAL;
491 }
492
493 if (!hdev) {
494 FMDERR("hdev is null");
495 return -EINVAL;
496 }
497
498 hdev->flags = 0;
499
500 tasklet_init(&hdev->cmd_task, radio_hci_cmd_task, (unsigned long)
501 hdev);
502 tasklet_init(&hdev->rx_task, radio_hci_rx_task, (unsigned long)
503 hdev);
504
505 init_waitqueue_head(&hdev->req_wait_q);
506
507 skb_queue_head_init(&hdev->rx_q);
508 skb_queue_head_init(&hdev->cmd_q);
509 skb_queue_head_init(&hdev->raw_q);
510
511 if (!radio)
512 FMDERR(":radio is null");
513
514 radio->fm_hdev = hdev;
515
516 return 0;
517}
518EXPORT_SYMBOL(radio_hci_register_dev);
519
520int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
521{
522 struct iris_device *radio = video_get_drvdata(video_get_dev());
523 if (!radio) {
524 FMDERR(":radio is null");
525 return -EINVAL;
526 }
527
528 tasklet_kill(&hdev->rx_task);
529 tasklet_kill(&hdev->cmd_task);
530 skb_queue_purge(&hdev->rx_q);
531 skb_queue_purge(&hdev->cmd_q);
532 skb_queue_purge(&hdev->raw_q);
533 kfree(radio->fm_hdev);
534 kfree(radio->videodev);
535
536 return 0;
537}
538EXPORT_SYMBOL(radio_hci_unregister_dev);
539
540int radio_hci_recv_frame(struct sk_buff *skb)
541{
542 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
543 if (!hdev) {
544 FMDERR("%s hdev is null while receiving frame", hdev->name);
545 kfree_skb(skb);
546 return -ENXIO;
547 }
548
549 __net_timestamp(skb);
550
551 radio_hci_event_packet(hdev, skb);
Srinivasa Rao Uppalacf3a8112011-09-22 21:02:02 +0530552 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553 return 0;
554}
555EXPORT_SYMBOL(radio_hci_recv_frame);
556
557int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
558 void *param)
559{
560 int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
561 struct radio_hci_command_hdr *hdr;
562 struct sk_buff *skb;
563 int ret = 0;
564
565 skb = alloc_skb(len, GFP_ATOMIC);
566 if (!skb) {
567 FMDERR("%s no memory for command", hdev->name);
568 return -ENOMEM;
569 }
570
571 hdr = (struct radio_hci_command_hdr *) skb_put(skb,
572 RADIO_HCI_COMMAND_HDR_SIZE);
573 hdr->opcode = cpu_to_le16(opcode);
574 hdr->plen = plen;
575
576 if (plen)
577 memcpy(skb_put(skb, plen), param, plen);
578
579 skb->dev = (void *) hdev;
580
581 ret = hci_send_frame(skb);
582
583 return ret;
584}
585EXPORT_SYMBOL(radio_hci_send_cmd);
586
587static int hci_fm_enable_recv_req(struct radio_hci_dev *hdev,
588 unsigned long param)
589{
590 __u16 opcode = 0;
591
592 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
593 HCI_OCF_FM_ENABLE_RECV_REQ);
594 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
595}
596
Ankur Nandwanid928d542011-08-11 13:15:41 -0700597static int hci_fm_tone_generator(struct radio_hci_dev *hdev,
598 unsigned long param)
599{
600 struct iris_device *radio = video_get_drvdata(video_get_dev());
601 __u16 opcode = 0;
602
603 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
604 HCI_FM_SET_INTERNAL_TONE_GENRATOR);
605 return radio_hci_send_cmd(hdev, opcode,
606 sizeof(radio->tone_freq), &radio->tone_freq);
607}
608
609static int hci_fm_enable_trans_req(struct radio_hci_dev *hdev,
610 unsigned long param)
611{
612 __u16 opcode = 0;
613
614 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
615 HCI_OCF_FM_ENABLE_TRANS_REQ);
616 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
617}
618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619static int hci_fm_disable_recv_req(struct radio_hci_dev *hdev,
620 unsigned long param)
621{
622 __u16 opcode = 0;
623
624 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
625 HCI_OCF_FM_DISABLE_RECV_REQ);
626 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
627}
628
Ankur Nandwanid928d542011-08-11 13:15:41 -0700629static int hci_fm_disable_trans_req(struct radio_hci_dev *hdev,
630 unsigned long param)
631{
632 __u16 opcode = 0;
633
634 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
635 HCI_OCF_FM_DISABLE_TRANS_REQ);
636 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
637}
638
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639static int hci_get_fm_recv_conf_req(struct radio_hci_dev *hdev,
640 unsigned long param)
641{
642 __u16 opcode = 0;
643
644 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
645 HCI_OCF_FM_GET_RECV_CONF_REQ);
646 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
647}
648
649static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
650 unsigned long param)
651{
652 __u16 opcode = 0;
653
654 struct hci_fm_recv_conf_req *recv_conf_req =
655 (struct hci_fm_recv_conf_req *) param;
656
657 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
658 HCI_OCF_FM_SET_RECV_CONF_REQ);
659 return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
660 recv_conf_req);
661}
662
Ankur Nandwanid928d542011-08-11 13:15:41 -0700663static int hci_set_fm_trans_conf_req(struct radio_hci_dev *hdev,
664 unsigned long param)
665{
666 __u16 opcode = 0;
667
668 struct hci_fm_trans_conf_req_struct *trans_conf_req =
669 (struct hci_fm_trans_conf_req_struct *) param;
670
671 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
672 HCI_OCF_FM_SET_TRANS_CONF_REQ);
673 return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
674 trans_conf_req);
675}
676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
678 unsigned long param)
679{
680 __u16 opcode = 0;
681
682 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
683 HCI_OCF_FM_GET_STATION_PARAM_REQ);
684 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
685}
686
687static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
688 unsigned long param)
689{
690 __u16 opcode = 0;
691 struct hci_fm_mute_mode_req *mute_mode_req =
692 (struct hci_fm_mute_mode_req *) param;
693
694 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
695 HCI_OCF_FM_SET_MUTE_MODE_REQ);
696 return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
697 mute_mode_req);
698}
699
Ankur Nandwanid928d542011-08-11 13:15:41 -0700700
701static int hci_trans_ps_req(struct radio_hci_dev *hdev,
702 unsigned long param)
703{
704 __u16 opcode = 0;
705 struct hci_fm_tx_ps *tx_ps_req =
706 (struct hci_fm_tx_ps *) param;
707
708 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
709 HCI_OCF_FM_RDS_PS_REQ);
710
711 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_ps_req)),
712 tx_ps_req);
713}
714
715static int hci_trans_rt_req(struct radio_hci_dev *hdev,
716 unsigned long param)
717{
718 __u16 opcode = 0;
719 struct hci_fm_tx_rt *tx_rt_req =
720 (struct hci_fm_tx_rt *) param;
721
722 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
723 HCI_OCF_FM_RDS_RT_REQ);
724
725 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_rt_req)),
726 tx_rt_req);
727}
728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
730 unsigned long param)
731{
732 __u16 opcode = 0;
733 struct hci_fm_stereo_mode_req *stereo_mode_req =
734 (struct hci_fm_stereo_mode_req *) param;
735 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
736 HCI_OCF_FM_SET_STEREO_MODE_REQ);
737 return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
738 stereo_mode_req);
739}
740
741static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
742 unsigned long param)
743{
744 __u16 opcode = 0;
745
746 __u8 antenna = param;
747
748 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
749 HCI_OCF_FM_SET_ANTENNA);
750 return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
751}
752
753static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
754 unsigned long param)
755{
756 __u16 opcode = 0;
757
758 __u8 sig_threshold = param;
759
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530760 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761 HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
762 return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
763 &sig_threshold);
764}
765
766static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
767 unsigned long param)
768{
769 __u16 opcode = 0;
770
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530771 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
773 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
774}
775
776static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
777 unsigned long param)
778{
779 __u16 opcode = 0;
780
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530781 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700782 HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
783 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
784}
785
786static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
787 unsigned long param)
788{
789 __u16 opcode = 0;
790
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530791 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 HCI_OCF_FM_GET_RADIO_TEXT_REQ);
793 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
794}
795
796static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
797 unsigned long param)
798{
799 __u16 opcode = 0;
800
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530801 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 HCI_OCF_FM_GET_AF_LIST_REQ);
803 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
804}
805
806static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
807 unsigned long param)
808{
809 __u16 opcode = 0;
810 struct hci_fm_search_station_req *srch_stations =
811 (struct hci_fm_search_station_req *) param;
812
813 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
814 HCI_OCF_FM_SEARCH_STATIONS);
815 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
816 srch_stations);
817}
818
819static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
820 unsigned long param)
821{
822 __u16 opcode = 0;
823 struct hci_fm_search_rds_station_req *srch_stations =
824 (struct hci_fm_search_rds_station_req *) param;
825
826 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
827 HCI_OCF_FM_SEARCH_RDS_STATIONS);
828 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
829 srch_stations);
830}
831
832static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
833 unsigned long param)
834{
835 __u16 opcode = 0;
836 struct hci_fm_search_station_list_req *srch_list =
837 (struct hci_fm_search_station_list_req *) param;
838
839 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
840 HCI_OCF_FM_SEARCH_STATIONS_LIST);
841 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
842 srch_list);
843}
844
845static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
846 unsigned long param)
847{
848 __u16 opcode = 0;
849
850 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
851 HCI_OCF_FM_CANCEL_SEARCH);
852 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
853}
854
855static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
856 unsigned long param)
857{
858 __u16 opcode = 0;
859
860 __u32 fm_grps_process = param;
861
862 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
863 HCI_OCF_FM_RDS_GRP_PROCESS);
864 return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
865 &fm_grps_process);
866}
867
868static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
869 unsigned long param)
870{
871 __u16 opcode = 0;
872
873 __u32 tune_freq = param;
874
875 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
876 HCI_OCF_FM_TUNE_STATION_REQ);
877 return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
878}
879
880static int hci_def_data_read_req(struct radio_hci_dev *hdev,
881 unsigned long param)
882{
883 __u16 opcode = 0;
884 struct hci_fm_def_data_rd_req *def_data_rd =
885 (struct hci_fm_def_data_rd_req *) param;
886
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530887 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700888 HCI_OCF_FM_DEFAULT_DATA_READ);
889 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
890 def_data_rd);
891}
892
893static int hci_def_data_write_req(struct radio_hci_dev *hdev,
894 unsigned long param)
895{
896 __u16 opcode = 0;
897 struct hci_fm_def_data_wr_req *def_data_wr =
898 (struct hci_fm_def_data_wr_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_WRITE);
902 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
903 def_data_wr);
904}
905
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530906static int hci_set_notch_filter_req(struct radio_hci_dev *hdev,
907 unsigned long param)
908{
909 __u16 opcode = 0;
910 __u8 notch_filter_val = param;
911
912 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
913 HCI_OCF_FM_EN_NOTCH_CTRL);
914 return radio_hci_send_cmd(hdev, opcode, sizeof(notch_filter_val),
915 &notch_filter_val);
916}
917
918
919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
921{
922 __u16 opcode = 0;
923
924 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
925 HCI_OCF_FM_RESET);
926 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
927}
928
929static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
930 unsigned long param)
931{
932 __u16 opcode = 0;
933
934 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
935 HCI_OCF_FM_GET_FEATURE_LIST);
936 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
937}
938
939static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
940 unsigned long param)
941{
942 __u16 opcode = 0;
943
944 __u8 mode = param;
945
946 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
947 HCI_OCF_FM_DO_CALIBRATION);
948 return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
949}
950
951static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
952 unsigned long param)
953{
954 __u16 opcode = 0;
955
956 __u8 reset_counters = param;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530957 opcode = hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958 HCI_OCF_FM_READ_GRP_COUNTERS);
959 return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
960 &reset_counters);
961}
962
963static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
964{
965 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700966 struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700968 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969 HCI_OCF_FM_PEEK_DATA);
970 return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
971 peek_data);
972}
973
974static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
975{
976 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700977 struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -0700979 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700980 HCI_OCF_FM_POKE_DATA);
981 return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
982 poke_data);
983}
984
985static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
986 unsigned long param)
987{
988 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700989 struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700991 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 HCI_OCF_FM_SSBI_PEEK_REG);
993 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
994 ssbi_peek);
995}
996
997static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
998 unsigned long param)
999{
1000 __u16 opcode = 0;
1001 struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
1002
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001003 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004 HCI_OCF_FM_SSBI_POKE_REG);
1005 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
1006 ssbi_poke);
1007}
1008
1009static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
1010 unsigned long param)
1011{
1012 __u16 opcode = 0;
1013
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +05301014 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015 HCI_OCF_FM_STATION_DBG_PARAM);
1016 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1017}
1018
1019static int radio_hci_err(__u16 code)
1020{
1021 switch (code) {
1022 case 0:
1023 return 0;
1024 case 0x01:
1025 return -EBADRQC;
1026 case 0x02:
1027 return -ENOTCONN;
1028 case 0x03:
1029 return -EIO;
1030 case 0x07:
1031 return -ENOMEM;
1032 case 0x0c:
1033 return -EBUSY;
1034 case 0x11:
1035 return -EOPNOTSUPP;
1036 case 0x12:
1037 return -EINVAL;
1038 default:
1039 return -ENOSYS;
1040 }
1041}
1042
1043static int __radio_hci_request(struct radio_hci_dev *hdev,
1044 int (*req)(struct radio_hci_dev *hdev,
1045 unsigned long param),
1046 unsigned long param, __u32 timeout)
1047{
1048 int err = 0;
1049
1050 DECLARE_WAITQUEUE(wait, current);
1051
1052 hdev->req_status = HCI_REQ_PEND;
1053
1054 add_wait_queue(&hdev->req_wait_q, &wait);
1055 set_current_state(TASK_INTERRUPTIBLE);
1056
1057 err = req(hdev, param);
1058
1059 schedule_timeout(timeout);
1060
1061 remove_wait_queue(&hdev->req_wait_q, &wait);
1062
1063 if (signal_pending(current))
1064 return -EINTR;
1065
1066 switch (hdev->req_status) {
1067 case HCI_REQ_DONE:
1068 case HCI_REQ_STATUS:
1069 err = radio_hci_err(hdev->req_result);
1070 break;
1071
1072 case HCI_REQ_CANCELED:
1073 err = -hdev->req_result;
1074 break;
1075
1076 default:
1077 err = -ETIMEDOUT;
1078 break;
1079 }
1080
1081 hdev->req_status = hdev->req_result = 0;
1082
1083 return err;
1084}
1085
1086static inline int radio_hci_request(struct radio_hci_dev *hdev,
1087 int (*req)(struct
1088 radio_hci_dev * hdev, unsigned long param),
1089 unsigned long param, __u32 timeout)
1090{
1091 int ret = 0;
1092
1093 ret = __radio_hci_request(hdev, req, param, timeout);
1094
1095 return ret;
1096}
1097
1098static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
1099 struct radio_hci_dev *hdev)
1100{
1101 int ret = 0;
1102 struct hci_fm_recv_conf_req *set_recv_conf = arg;
1103
1104 ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
1105 long)set_recv_conf, RADIO_HCI_TIMEOUT);
1106
1107 return ret;
1108}
1109
Ankur Nandwanid928d542011-08-11 13:15:41 -07001110static int hci_set_fm_trans_conf(struct hci_fm_trans_conf_req_struct *arg,
1111 struct radio_hci_dev *hdev)
1112{
1113 int ret = 0;
1114 struct hci_fm_trans_conf_req_struct *set_trans_conf = arg;
1115
1116 ret = radio_hci_request(hdev, hci_set_fm_trans_conf_req, (unsigned
1117 long)set_trans_conf, RADIO_HCI_TIMEOUT);
1118
1119 return ret;
1120}
1121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
1123{
1124 int ret = 0;
1125 __u32 tune_freq = *arg;
1126
1127 ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
1128 RADIO_HCI_TIMEOUT);
1129
1130 return ret;
1131}
1132
1133static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
1134 struct radio_hci_dev *hdev)
1135{
1136 int ret = 0;
1137 struct hci_fm_mute_mode_req *set_mute_conf = arg;
1138
1139 ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
1140 long)set_mute_conf, RADIO_HCI_TIMEOUT);
1141
1142 return ret;
1143}
1144
1145static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
1146 struct radio_hci_dev *hdev)
1147{
1148 int ret = 0;
1149 struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
1150
1151 ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
1152 long)set_stereo_conf, RADIO_HCI_TIMEOUT);
1153
1154 return ret;
1155}
1156
1157static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
1158{
1159 int ret = 0;
1160 __u8 antenna = *arg;
1161
1162 ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
1163 RADIO_HCI_TIMEOUT);
1164
1165 return ret;
1166}
1167
1168static int hci_fm_set_signal_threshold(__u8 *arg,
1169 struct radio_hci_dev *hdev)
1170{
1171 int ret = 0;
1172 __u8 sig_threshold = *arg;
1173
1174 ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
1175 sig_threshold, RADIO_HCI_TIMEOUT);
1176
1177 return ret;
1178}
1179
1180static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
1181 struct radio_hci_dev *hdev)
1182{
1183 int ret = 0;
1184 struct hci_fm_search_station_req *srch_stations = arg;
1185
1186 ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
1187 long)srch_stations, RADIO_HCI_TIMEOUT);
1188
1189 return ret;
1190}
1191
1192static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
1193 struct radio_hci_dev *hdev)
1194{
1195 int ret = 0;
1196 struct hci_fm_search_rds_station_req *srch_stations = arg;
1197
1198 ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
1199 long)srch_stations, RADIO_HCI_TIMEOUT);
1200
1201 return ret;
1202}
1203
1204static int hci_fm_search_station_list
1205 (struct hci_fm_search_station_list_req *arg,
1206 struct radio_hci_dev *hdev)
1207{
1208 int ret = 0;
1209 struct hci_fm_search_station_list_req *srch_list = arg;
1210
1211 ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
1212 long)srch_list, RADIO_HCI_TIMEOUT);
1213
1214 return ret;
1215}
1216
1217static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
1218 struct radio_hci_dev *hdev)
1219{
1220 return 0;
1221}
1222
1223static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
1224{
1225 int ret = 0;
1226 __u32 fm_grps_process = *arg;
1227
1228 ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
1229 fm_grps_process, RADIO_HCI_TIMEOUT);
1230
1231 return ret;
1232}
1233
1234int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
1235 struct radio_hci_dev *hdev)
1236{
1237 int ret = 0;
1238 struct hci_fm_def_data_rd_req *def_data_rd = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
1240 long)def_data_rd, RADIO_HCI_TIMEOUT);
1241
1242 return ret;
1243}
1244
1245int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
1246 struct radio_hci_dev *hdev)
1247{
1248 int ret = 0;
1249 struct hci_fm_def_data_wr_req *def_data_wr = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
1251 long)def_data_wr, RADIO_HCI_TIMEOUT);
1252
1253 return ret;
1254}
1255
1256int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
1257{
1258 int ret = 0;
1259 __u8 mode = *arg;
1260
1261 ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
1262 RADIO_HCI_TIMEOUT);
1263
1264 return ret;
1265}
1266
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301267static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268{
1269 int ret = 0;
1270 __u8 reset_counters = *arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 ret = radio_hci_request(hdev, hci_read_grp_counters_req,
1272 reset_counters, RADIO_HCI_TIMEOUT);
1273
1274 return ret;
1275}
1276
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301277static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
1278{
1279 int ret = 0;
1280 __u8 notch_filter = *arg;
1281 ret = radio_hci_request(hdev, hci_set_notch_filter_req,
1282 notch_filter, RADIO_HCI_TIMEOUT);
1283
1284 return ret;
1285}
1286
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001287static int hci_peek_data(struct hci_fm_riva_data *arg,
1288 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289{
1290 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001291 struct hci_fm_riva_data *peek_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292
1293 ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
1294 long)peek_data, RADIO_HCI_TIMEOUT);
1295
1296 return ret;
1297}
1298
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001299static int hci_poke_data(struct hci_fm_riva_poke *arg,
1300 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301{
1302 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001303 struct hci_fm_riva_poke *poke_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304
1305 ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
1306 long)poke_data, RADIO_HCI_TIMEOUT);
1307
1308 return ret;
1309}
1310
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001311static int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *arg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 struct radio_hci_dev *hdev)
1313{
1314 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001315 struct hci_fm_ssbi_peek *ssbi_peek_reg = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316
1317 ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
1318 long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
1319
1320 return ret;
1321}
1322
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001323static int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg,
1324 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325{
1326 int ret = 0;
1327 struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
1328
1329 ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
1330 long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
1331
1332 return ret;
1333}
1334
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301335static int hci_fm_set_cal_req(struct radio_hci_dev *hdev,
1336 unsigned long param)
1337{
1338 u16 opcode = 0;
1339 struct hci_fm_set_cal_req *cal_req =
1340 (struct hci_fm_set_cal_req *)param;
1341
1342 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1343 HCI_OCF_FM_SET_CALIBRATION);
1344 return radio_hci_send_cmd(hdev, opcode, sizeof((*hci_fm_set_cal_req)),
1345 cal_req);
1346
1347}
1348
1349static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
1350 unsigned long param)
1351{
1352 u16 opcode = 0;
1353 u8 cal_mode = param;
1354
1355 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1356 HCI_OCF_FM_DO_CALIBRATION);
1357 return radio_hci_send_cmd(hdev, opcode, sizeof(cal_mode),
1358 &cal_mode);
1359
1360}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1362{
1363 int ret = 0;
1364 unsigned long arg = 0;
1365
Ankur Nandwanid928d542011-08-11 13:15:41 -07001366 if (!hdev)
1367 return -ENODEV;
1368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 switch (cmd) {
1370 case HCI_FM_ENABLE_RECV_CMD:
1371 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1372 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1373 break;
1374
1375 case HCI_FM_DISABLE_RECV_CMD:
1376 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1377 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1378 break;
1379
1380 case HCI_FM_GET_RECV_CONF_CMD:
1381 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1382 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1383 break;
1384
1385 case HCI_FM_GET_STATION_PARAM_CMD:
1386 ret = radio_hci_request(hdev,
1387 hci_fm_get_station_param_req, arg,
1388 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1389 break;
1390
1391 case HCI_FM_GET_SIGNAL_TH_CMD:
1392 ret = radio_hci_request(hdev,
1393 hci_fm_get_sig_threshold_req, arg,
1394 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1395 break;
1396
1397 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1398 ret = radio_hci_request(hdev,
1399 hci_fm_get_program_service_req, arg,
1400 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1401 break;
1402
1403 case HCI_FM_GET_RADIO_TEXT_CMD:
1404 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1405 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1406 break;
1407
1408 case HCI_FM_GET_AF_LIST_CMD:
1409 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1410 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1411 break;
1412
1413 case HCI_FM_CANCEL_SEARCH_CMD:
1414 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1415 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1416 break;
1417
1418 case HCI_FM_RESET_CMD:
1419 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1420 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1421 break;
1422
1423 case HCI_FM_GET_FEATURES_CMD:
1424 ret = radio_hci_request(hdev,
1425 hci_fm_get_feature_lists_req, arg,
1426 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1427 break;
1428
1429 case HCI_FM_STATION_DBG_PARAM_CMD:
1430 ret = radio_hci_request(hdev,
1431 hci_fm_get_station_dbg_param_req, arg,
1432 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1433 break;
1434
Ankur Nandwanid928d542011-08-11 13:15:41 -07001435 case HCI_FM_ENABLE_TRANS_CMD:
1436 ret = radio_hci_request(hdev, hci_fm_enable_trans_req, arg,
1437 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1438 break;
1439
1440 case HCI_FM_DISABLE_TRANS_CMD:
1441 ret = radio_hci_request(hdev, hci_fm_disable_trans_req, arg,
1442 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1443 break;
1444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 default:
1446 ret = -EINVAL;
1447 break;
1448 }
1449
1450 return ret;
1451}
1452
1453static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1454{
1455 hdev->req_result = result;
1456 hdev->req_status = HCI_REQ_DONE;
1457 wake_up_interruptible(&hdev->req_wait_q);
1458}
1459
1460static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1461{
1462 hdev->req_result = result;
1463 hdev->req_status = HCI_REQ_STATUS;
1464 wake_up_interruptible(&hdev->req_wait_q);
1465}
1466
1467static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1468{
1469 __u8 status = *((__u8 *) skb->data);
1470
1471 if (status)
1472 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 radio_hci_req_complete(hdev, status);
1474}
1475
1476static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1477 struct sk_buff *skb)
1478{
1479 __u8 status = *((__u8 *) skb->data);
1480 struct iris_device *radio = video_get_drvdata(video_get_dev());
1481
1482 if (status)
1483 return;
1484
1485 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1486
1487 radio_hci_req_complete(hdev, status);
1488}
1489
1490static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1491{
1492 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1493 struct iris_device *radio = video_get_drvdata(video_get_dev());
1494
1495 if (rsp->status)
1496 return;
1497
1498 radio->recv_conf = rsp->recv_conf_rsp;
1499 radio_hci_req_complete(hdev, rsp->status);
1500}
1501
1502static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1503 struct sk_buff *skb)
1504{
1505 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1506 struct iris_device *radio = video_get_drvdata(video_get_dev());
1507
1508 if (rsp->status)
1509 return;
1510
1511 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1512
1513 radio_hci_req_complete(hdev, rsp->status);
1514}
1515
Ankur Nandwanid928d542011-08-11 13:15:41 -07001516
1517static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
1518 struct sk_buff *skb)
1519{
1520 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1521 struct iris_device *radio = video_get_drvdata(video_get_dev());
1522
1523 if (rsp->status)
1524 return;
1525
1526 iris_q_event(radio, HCI_EV_CMD_COMPLETE);
1527
1528 radio_hci_req_complete(hdev, rsp->status);
1529}
1530
1531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1533 struct sk_buff *skb)
1534{
1535 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1536 struct iris_device *radio = video_get_drvdata(video_get_dev());
1537 struct v4l2_control *v4l_ctl = radio->g_ctl;
1538
1539 if (rsp->status)
1540 return;
1541
1542 v4l_ctl->value = rsp->sig_threshold;
1543
1544 radio_hci_req_complete(hdev, rsp->status);
1545}
1546
1547static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1548{
1549 struct iris_device *radio = video_get_drvdata(video_get_dev());
1550 struct hci_fm_station_rsp *rsp = (void *)skb->data;
1551 radio->fm_st_rsp = *(rsp);
1552
1553 /* Tune is always succesful */
1554 radio_hci_req_complete(hdev, 0);
1555}
1556
1557static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1558{
1559 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1560
1561 if (rsp->status)
1562 return;
1563
1564 radio_hci_req_complete(hdev, rsp->status);
1565}
1566
1567static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1568{
1569 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1570
1571 if (rsp->status)
1572 return;
1573
1574 radio_hci_req_complete(hdev, rsp->status);
1575}
1576
1577static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1578{
1579 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1580
1581 if (rsp->status)
1582 return;
1583
1584 radio_hci_req_complete(hdev, rsp->status);
1585}
1586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001587static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1588 struct sk_buff *skb)
1589{
1590 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1591 struct iris_device *radio = video_get_drvdata(video_get_dev());
1592 struct v4l2_capability *v4l_cap = radio->g_cap;
1593
1594 if (rsp->status)
1595 return;
1596 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1597 (rsp->feature_mask & 0x000001);
1598
1599 radio_hci_req_complete(hdev, rsp->status);
1600}
1601
1602static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1603 struct sk_buff *skb)
1604{
1605 struct iris_device *radio = video_get_drvdata(video_get_dev());
1606 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
1607 radio->st_dbg_param = *(rsp);
1608
1609 if (radio->st_dbg_param.status)
1610 return;
1611
1612 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1613}
1614
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001615static void iris_q_evt_data(struct iris_device *radio,
1616 char *data, int len, int event)
1617{
1618 struct kfifo *data_b = &radio->data_buf[event];
1619 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1620 wake_up_interruptible(&radio->event_queue);
1621}
1622
1623static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1624 struct sk_buff *skb)
1625{
1626 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301627 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001628 int len;
1629 char *data;
1630
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301631 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001632 return;
1633 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1634 data = kmalloc(len, GFP_ATOMIC);
1635
1636 if (!data) {
1637 FMDERR("Memory allocation failed");
1638 return;
1639 }
1640
1641 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1642 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301643 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001644
1645
1646}
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301647
1648static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
1649 struct sk_buff *skb)
1650{
1651 struct iris_device *radio = video_get_drvdata(video_get_dev());
1652 __u8 status = *((__u8 *) skb->data);
1653 __u8 len;
1654 char *data;
1655
1656 if (status)
1657 return;
1658 len = skb->data[1];
1659 data = kmalloc(len+2, GFP_ATOMIC);
1660 if (!data) {
1661 FMDERR("Memory allocation failed");
1662 return;
1663 }
1664
1665 data[0] = status;
1666 data[1] = len;
1667 memcpy(&data[2], &skb->data[DEFAULT_DATA_OFFSET], len);
1668 iris_q_evt_data(radio, data, len+2, IRIS_BUF_RD_DEFAULT);
1669 radio_hci_req_complete(hdev, status);
1670 kfree(data);
1671}
1672
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001673static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1674 struct sk_buff *skb)
1675{
1676 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301677 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001678 char *data;
1679
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301680 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001681 return;
1682 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1683 if (!data) {
1684 FMDERR("Memory allocation failed");
1685 return;
1686 }
1687
1688 data[0] = skb->data[PEEK_DATA_OFSET];
1689 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301690 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001691 kfree(data);
1692}
1693
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301694static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
1695 struct sk_buff *skb)
1696{
1697 struct iris_device *radio = video_get_drvdata(video_get_dev());
1698 __u8 status = *((__u8 *) skb->data);
1699 char *data;
1700 if (status)
1701 return;
1702 data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
1703 if (!data) {
1704 FMDERR("memory allocation failed");
1705 return;
1706 }
1707 memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
1708 iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
1709 radio_hci_req_complete(hdev, status);
1710 kfree(data);
1711
1712}
1713
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301714static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
1715 struct sk_buff *skb)
1716{
1717 struct iris_device *radio = video_get_drvdata(video_get_dev());
1718 static struct hci_cc_do_calibration_rsp rsp ;
1719 rsp.status = skb->data[0];
1720 rsp.mode = skb->data[CALIB_MODE_OFSET];
1721
1722 if (rsp.status) {
1723 FMDERR("status = %d", rsp.status);
1724 return;
1725 }
1726 if (rsp.mode == PROCS_CALIB_MODE) {
1727 memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
1728 PROCS_CALIB_SIZE);
1729 } else if (rsp.mode == DC_CALIB_MODE) {
1730 memcpy(&rsp.data[PROCS_CALIB_SIZE],
1731 &skb->data[CALIB_DATA_OFSET], DC_CALIB_SIZE);
1732 iris_q_evt_data(radio, rsp.data, (PROCS_CALIB_SIZE +
1733 DC_CALIB_SIZE), IRIS_BUF_CAL_DATA);
1734 }
1735 radio_hci_req_complete(hdev, rsp.status);
1736}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
1738 struct sk_buff *skb)
1739{
1740 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
1741 __u16 opcode;
1742
1743 skb_pull(skb, sizeof(*cmd_compl_ev));
1744
1745 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
1746
1747 switch (opcode) {
1748 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
1749 hci_cc_fm_enable_rsp(hdev, skb);
1750 break;
1751 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
1752 hci_cc_conf_rsp(hdev, skb);
1753 break;
1754
1755 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
1756 hci_cc_fm_disable_rsp(hdev, skb);
1757 break;
1758
1759 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
1760 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
1761 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
1762 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
1763 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
1764 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
1765 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
1766 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
1767 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
1768 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001769 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
1770 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
1771 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
1772 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301774 hci_cc_rsp(hdev, skb);
1775 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001778 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
Ankur Nandwanid928d542011-08-11 13:15:41 -07001779 case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301780 case hci_common_cmd_op_pack(HCI_OCF_FM_SET_CALIBRATION):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781 hci_cc_rsp(hdev, skb);
1782 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001783 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
1784 hci_cc_ssbi_peek_rsp(hdev, skb);
1785 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
1787 hci_cc_sig_threshold_rsp(hdev, skb);
1788 break;
1789
1790 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
1791 hci_cc_station_rsp(hdev, skb);
1792 break;
1793
1794 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
1795 hci_cc_prg_srv_rsp(hdev, skb);
1796 break;
1797
1798 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
1799 hci_cc_rd_txt_rsp(hdev, skb);
1800 break;
1801
1802 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
1803 hci_cc_af_list_rsp(hdev, skb);
1804 break;
1805
1806 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301807 hci_cc_riva_read_default_rsp(hdev, skb);
1808 break;
1809
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001810 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001811 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001812 break;
1813
1814 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
1815 hci_cc_feature_list_rsp(hdev, skb);
1816 break;
1817
1818 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
1819 hci_cc_dbg_param_rsp(hdev, skb);
1820 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07001821 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_SET_TRANS_CONF_REQ):
1822 hci_cc_fm_trans_set_conf_rsp(hdev, skb);
1823 break;
1824
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301825 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
1826 hci_cc_rds_grp_cntrs_rsp(hdev, skb);
1827 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301828 case hci_common_cmd_op_pack(HCI_OCF_FM_DO_CALIBRATION):
1829 hci_cc_do_calibration_rsp(hdev, skb);
1830 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 default:
1833 FMDERR("%s opcode 0x%x", hdev->name, opcode);
1834 break;
1835 }
1836
1837}
1838
1839static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
1840 struct sk_buff *skb)
1841{
1842 struct hci_ev_cmd_status *ev = (void *) skb->data;
1843 radio_hci_status_complete(hdev, ev->status);
1844}
1845
1846static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
1847 struct sk_buff *skb)
1848{
1849 int i;
1850 int len;
1851
1852 struct iris_device *radio = video_get_drvdata(video_get_dev());
1853
1854 len = sizeof(struct hci_fm_station_rsp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855 memcpy(&radio->fm_st_rsp.station_rsp, skb_pull(skb, len), len);
1856
1857 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
1858
1859 for (i = 0; i < IRIS_BUF_MAX; i++) {
1860 if (i >= IRIS_BUF_RT_RDS)
1861 kfifo_reset(&radio->data_buf[i]);
1862 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 if (radio->fm_st_rsp.station_rsp.rssi)
1864 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1865 else
1866 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1867
1868 if (radio->fm_st_rsp.station_rsp.stereo_prg)
1869 iris_q_event(radio, IRIS_EVT_STEREO);
1870
1871 if (radio->fm_st_rsp.station_rsp.mute_mode)
1872 iris_q_event(radio, IRIS_EVT_MONO);
1873
1874 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
1875 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1876 else
1877 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1878}
1879
1880static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
1881 struct sk_buff *skb)
1882{
1883 struct iris_device *radio = video_get_drvdata(video_get_dev());
1884 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
1885}
1886
1887static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
1888 struct sk_buff *skb)
1889{
1890 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001891 struct hci_ev_srch_list_compl *ev ;
1892 int cnt;
1893 int stn_num;
1894 int rel_freq;
1895 int abs_freq;
1896 int len;
1897
1898 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1899 if (!ev) {
1900 FMDERR("Memory allocation failed");
1901 return ;
1902 }
1903
1904 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
1905 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
1906
1907 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
1908 (cnt < len) && (stn_num < ev->num_stations_found);
1909 cnt += PARAMS_PER_STATION, stn_num++) {
1910 abs_freq = *((int *)&skb->data[cnt]);
1911 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
1912 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
1913
1914 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
1915 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
1916 }
1917
1918 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
1919 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
1920 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
1921 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001922}
1923
1924static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
1925 struct sk_buff *skb)
1926{
1927 struct iris_device *radio = video_get_drvdata(video_get_dev());
1928 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
1929}
1930
1931static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
1932 struct sk_buff *skb)
1933{
1934 struct iris_device *radio = video_get_drvdata(video_get_dev());
1935 __u8 st_status = *((__u8 *) skb->data);
1936 if (st_status)
1937 iris_q_event(radio, IRIS_EVT_STEREO);
1938 else
1939 iris_q_event(radio, IRIS_EVT_MONO);
1940}
1941
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001942
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001943static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
1944 struct sk_buff *skb)
1945{
1946 struct iris_device *radio = video_get_drvdata(video_get_dev());
1947 int len;
1948 char *data;
1949
1950 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
1951 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
1952 data = kmalloc(len, GFP_ATOMIC);
1953 if (!data) {
1954 FMDERR("Failed to allocate memory");
1955 return;
1956 }
1957
1958 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
1959 data[1] = skb->data[RDS_PTYPE];
1960 data[2] = skb->data[RDS_PID_LOWER];
1961 data[3] = skb->data[RDS_PID_HIGHER];
1962 data[4] = 0;
1963
1964 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
1965
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001966 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001967
1968 kfree(data);
1969}
1970
1971
1972static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
1973 struct sk_buff *skb)
1974{
1975 struct iris_device *radio = video_get_drvdata(video_get_dev());
1976 int len = 0;
1977 char *data;
1978
1979 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
1980
1981 while (skb->data[len+RDS_OFFSET] != 0x0d)
1982 len++;
1983 len++;
1984
1985 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
1986 if (!data) {
1987 FMDERR("Failed to allocate memory");
1988 return;
1989 }
1990
1991 data[0] = len;
1992 data[1] = skb->data[RDS_PTYPE];
1993 data[2] = skb->data[RDS_PID_LOWER];
1994 data[3] = skb->data[RDS_PID_HIGHER];
1995 data[4] = 0;
1996
1997 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
1998 data[len+RDS_OFFSET] = 0x00;
1999
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002000 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002001
2002 kfree(data);
2003}
2004
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302005static void hci_ev_af_list(struct radio_hci_dev *hdev,
2006 struct sk_buff *skb)
2007{
2008 struct iris_device *radio = video_get_drvdata(video_get_dev());
2009 struct hci_ev_af_list ev;
2010
2011 ev.tune_freq = *((int *) &skb->data[0]);
2012 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
2013 ev.af_size = skb->data[AF_SIZE_OFFSET];
2014 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
2015 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
2016 iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
2017}
2018
2019static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
2020 struct sk_buff *skb)
2021{
2022 struct iris_device *radio = video_get_drvdata(video_get_dev());
2023 __u8 rds_status = skb->data[0];
2024
2025 if (rds_status)
2026 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2027 else
2028 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2029}
2030
2031static void hci_ev_service_available(struct radio_hci_dev *hdev,
2032 struct sk_buff *skb)
2033{
2034 struct iris_device *radio = video_get_drvdata(video_get_dev());
2035 if (radio->fm_st_rsp.station_rsp.serv_avble)
2036 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2037 else
2038 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2039}
2040
2041static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
2042 struct sk_buff *skb)
2043{
2044 struct iris_device *radio = video_get_drvdata(video_get_dev());
2045 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
2046}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
2049{
2050 struct radio_hci_event_hdr *hdr = (void *) skb->data;
2051 __u8 event = hdr->evt;
2052
2053 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
2054
2055 switch (event) {
2056 case HCI_EV_TUNE_STATUS:
2057 hci_ev_tune_status(hdev, skb);
2058 break;
2059 case HCI_EV_SEARCH_PROGRESS:
2060 case HCI_EV_SEARCH_RDS_PROGRESS:
2061 case HCI_EV_SEARCH_LIST_PROGRESS:
2062 hci_ev_search_next(hdev, skb);
2063 break;
2064 case HCI_EV_STEREO_STATUS:
2065 hci_ev_stereo_status(hdev, skb);
2066 break;
2067 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302068 hci_ev_rds_lock_status(hdev, skb);
2069 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002070 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302071 hci_ev_service_available(hdev, skb);
2072 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002073 case HCI_EV_RDS_RX_DATA:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002074 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002076 hci_ev_program_service(hdev, skb);
2077 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002078 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002079 hci_ev_radio_text(hdev, skb);
2080 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302082 hci_ev_af_list(hdev, skb);
2083 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302085 hci_ev_rds_grp_complete(hdev, skb);
2086 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2088 break;
2089
2090 case HCI_EV_CMD_COMPLETE:
2091 hci_cmd_complete_event(hdev, skb);
2092 break;
2093
2094 case HCI_EV_CMD_STATUS:
2095 hci_cmd_status_event(hdev, skb);
2096 break;
2097
2098 case HCI_EV_SEARCH_COMPLETE:
2099 case HCI_EV_SEARCH_RDS_COMPLETE:
2100 hci_ev_search_compl(hdev, skb);
2101 break;
2102
2103 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002104 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 break;
2106
2107 default:
2108 break;
2109 }
2110}
2111
2112/*
2113 * fops/IOCTL helper functions
2114 */
2115
2116static int iris_search(struct iris_device *radio, int on, int dir)
2117{
2118 int retval = 0;
2119 enum search_t srch = radio->g_search_mode & SRCH_MODE;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302120 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121
2122 if (on) {
2123 switch (srch) {
2124 case SCAN_FOR_STRONG:
2125 case SCAN_FOR_WEAK:
2126 radio->srch_st_list.srch_list_dir = dir;
2127 radio->srch_st_list.srch_list_mode = srch;
2128 radio->srch_st_list.srch_list_max = 0;
2129 retval = hci_fm_search_station_list(
2130 &radio->srch_st_list, radio->fm_hdev);
2131 break;
2132 case RDS_SEEK_PTY:
2133 case RDS_SCAN_PTY:
2134 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002135 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 radio->srch_rds.srch_station.srch_mode = srch;
2137 radio->srch_rds.srch_station.srch_dir = dir;
2138 radio->srch_rds.srch_station.scan_time =
2139 radio->g_scan_time;
2140 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2141 radio->fm_hdev);
2142 break;
2143 default:
2144 radio->srch_st.srch_mode = srch;
2145 radio->srch_st.scan_time = radio->g_scan_time;
2146 radio->srch_st.srch_dir = dir;
2147 retval = hci_fm_search_stations(
2148 &radio->srch_st, radio->fm_hdev);
2149 break;
2150 }
2151
2152 } else {
2153 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2154 }
2155
2156 return retval;
2157}
2158
Ankur Nandwanid928d542011-08-11 13:15:41 -07002159static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002160{
2161 int retval;
2162 radio->region = req_region;
2163
2164 switch (radio->region) {
2165 case IRIS_REGION_US:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002166 radio->recv_conf.band_low_limit =
2167 REGION_US_EU_BAND_LOW;
2168 radio->recv_conf.band_high_limit =
2169 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002170 break;
2171 case IRIS_REGION_EU:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002172 radio->recv_conf.band_low_limit =
2173 REGION_US_EU_BAND_LOW;
2174 radio->recv_conf.band_high_limit =
2175 REGION_US_EU_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002176 break;
2177 case IRIS_REGION_JAPAN:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002178 radio->recv_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002179 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302180 radio->recv_conf.band_high_limit =
2181 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002182 break;
2183 case IRIS_REGION_JAPAN_WIDE:
2184 radio->recv_conf.band_low_limit =
2185 REGION_JAPAN_WIDE_BAND_LOW;
2186 radio->recv_conf.band_high_limit =
2187 REGION_JAPAN_WIDE_BAND_HIGH;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002188 break;
2189 default:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002190 /* The user specifies the value.
2191 So nothing needs to be done */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192 break;
2193 }
2194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 retval = hci_set_fm_recv_conf(
2196 &radio->recv_conf,
2197 radio->fm_hdev);
2198
2199 return retval;
2200}
2201
Ankur Nandwanid928d542011-08-11 13:15:41 -07002202
2203static int iris_trans_set_region(struct iris_device *radio, int req_region)
2204{
2205 int retval;
2206 radio->region = req_region;
2207
2208 switch (radio->region) {
2209 case IRIS_REGION_US:
2210 radio->trans_conf.band_low_limit =
2211 REGION_US_EU_BAND_LOW;
2212 radio->trans_conf.band_high_limit =
2213 REGION_US_EU_BAND_HIGH;
2214 break;
2215 case IRIS_REGION_EU:
2216 radio->trans_conf.band_low_limit =
2217 REGION_US_EU_BAND_LOW;
2218 radio->trans_conf.band_high_limit =
2219 REGION_US_EU_BAND_HIGH;
2220 break;
2221 case IRIS_REGION_JAPAN:
2222 radio->trans_conf.band_low_limit =
Ankur Nandwanid928d542011-08-11 13:15:41 -07002223 REGION_JAPAN_STANDARD_BAND_LOW;
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302224 radio->trans_conf.band_high_limit =
2225 REGION_JAPAN_STANDARD_BAND_HIGH;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002226 break;
2227 case IRIS_REGION_JAPAN_WIDE:
2228 radio->recv_conf.band_low_limit =
2229 REGION_JAPAN_WIDE_BAND_LOW;
2230 radio->recv_conf.band_high_limit =
2231 REGION_JAPAN_WIDE_BAND_HIGH;
2232 default:
2233 break;
2234 }
2235
2236 retval = hci_set_fm_trans_conf(
2237 &radio->trans_conf,
2238 radio->fm_hdev);
2239 return retval;
2240}
2241
2242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002243static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2244{
2245
2246 int retval;
2247 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2248 if (retval < 0)
2249 FMDERR("Error while setting the frequency : %d\n", retval);
2250 return retval;
2251}
2252
2253
2254static int iris_vidioc_queryctrl(struct file *file, void *priv,
2255 struct v4l2_queryctrl *qc)
2256{
2257 unsigned char i;
2258 int retval = -EINVAL;
2259
2260 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2261 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2262 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2263 retval = 0;
2264 break;
2265 }
2266 }
2267
2268 return retval;
2269}
2270
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302271static int iris_do_calibration(struct iris_device *radio)
2272{
2273 char cal_mode = 0x00;
2274 int retval = 0x00;
2275
2276 cal_mode = PROCS_CALIB_MODE;
2277 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2278 radio->fm_hdev);
2279 if (retval < 0) {
2280 FMDERR("Enable failed before calibration %x", retval);
2281 return retval;
2282 }
2283 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2284 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2285 if (retval < 0) {
2286 FMDERR("Do Process calibration failed %x", retval);
2287 return retval;
2288 }
2289 cal_mode = DC_CALIB_MODE;
2290 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2291 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2292 if (retval < 0) {
2293 FMDERR("Do DC calibration failed %x", retval);
2294 return retval;
2295 }
2296 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2297 radio->fm_hdev);
2298 if (retval < 0)
2299 FMDERR("Disable Failed after calibration %d", retval);
2300 return retval;
2301}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2303 struct v4l2_control *ctrl)
2304{
2305 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2306 int retval = 0;
2307
2308 switch (ctrl->id) {
2309 case V4L2_CID_AUDIO_VOLUME:
2310 break;
2311 case V4L2_CID_AUDIO_MUTE:
2312 ctrl->value = radio->mute_mode.hard_mute;
2313 break;
2314 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2315 ctrl->value = radio->g_search_mode;
2316 break;
2317 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2318 ctrl->value = radio->g_scan_time;
2319 break;
2320 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302321 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 break;
2323 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302324 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002325 break;
2326 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2327 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2328 if (retval < 0)
2329 return retval;
2330 ctrl->value = radio->st_dbg_param.io_verc;
2331 break;
2332 case V4L2_CID_PRIVATE_IRIS_INTDET:
2333 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2334 if (retval < 0)
2335 return retval;
2336 ctrl->value = radio->st_dbg_param.in_det_out;
2337 break;
2338 case V4L2_CID_PRIVATE_IRIS_REGION:
2339 ctrl->value = radio->region;
2340 break;
2341 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2342 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
2343 break;
2344 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302345 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 break;
2347 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302348 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349 break;
2350 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302351 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352 break;
2353 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002354 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002356 } else if (radio->mode == FM_TRANS) {
2357 ctrl->value = radio->trans_conf.emphasis;
2358 } else {
2359 FMDERR("Error in radio mode"
2360 " %d\n", retval);
2361 return -EINVAL;
2362 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363 break;
2364 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002365 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002367 } else if (radio->mode == FM_TRANS) {
2368 ctrl->value = radio->trans_conf.rds_std;
2369 } else {
2370 FMDERR("Error in radio mode"
2371 " %d\n", retval);
2372 return -EINVAL;
2373 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002374 break;
2375 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002376 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002378 } else {
2379 FMDERR("Error in radio mode"
2380 " %d\n", retval);
2381 return -EINVAL;
2382 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383 break;
2384 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002385 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002387 } else {
2388 FMDERR("Error in radio mode"
2389 " %d\n", retval);
2390 return -EINVAL;
2391 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 break;
2393 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2394 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2395 break;
2396 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002397 case V4L2_CID_PRIVATE_IRIS_PSALL:
2398 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399 break;
2400 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2401 ctrl->value = radio->rds_grp.rds_buf_size;
2402 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002403 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
2404 break;
2405 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2406 ctrl->value = radio->g_antenna;
2407 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002408 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2409 ctrl->value = radio->mute_mode.soft_mute;
2410 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302411 case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
2412 retval = iris_do_calibration(radio);
2413 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002414 default:
2415 retval = -EINVAL;
2416 }
2417 if (retval < 0)
2418 FMDERR("get control failed with %d, id: %d\n",
2419 retval, ctrl->id);
2420 return retval;
2421}
2422
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302423static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
2424 struct v4l2_ext_controls *ctrl)
2425{
2426 int retval = 0;
2427 char *data = NULL;
2428 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2429 struct hci_fm_def_data_rd_req default_data_rd;
2430
2431 switch ((ctrl->controls[0]).id) {
2432 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
2433 data = (ctrl->controls[0]).string;
2434 memset(&default_data_rd, 0, sizeof(default_data_rd));
2435 if (copy_from_user(&default_data_rd.mode, data,
2436 sizeof(default_data_rd)))
2437 return -EFAULT;
2438 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
2439 break;
2440 default:
2441 retval = -EINVAL;
2442 }
2443
2444 return retval;
2445}
2446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2448 struct v4l2_ext_controls *ctrl)
2449{
Ankur Nandwanid928d542011-08-11 13:15:41 -07002450 int retval = 0;
2451 int bytes_to_copy;
2452 struct hci_fm_tx_ps tx_ps;
2453 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302454 struct hci_fm_def_data_wr_req default_data;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302455 struct hci_fm_set_cal_req cal_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002456
2457 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2458 char *data = NULL;
2459
2460 switch ((ctrl->controls[0]).id) {
2461 case V4L2_CID_RDS_TX_PS_NAME:
2462 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2463 /*Pass a sample PS string */
2464
2465 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
2466 bytes_to_copy = min((int)(ctrl->controls[0]).size,
2467 MAX_PS_LENGTH);
2468 data = (ctrl->controls[0]).string;
2469
2470 if (copy_from_user(tx_ps.ps_data,
2471 data, bytes_to_copy))
2472 return -EFAULT;
2473 tx_ps.ps_control = 0x01;
2474 tx_ps.pi = radio->pi;
2475 tx_ps.pty = radio->pty;
2476 tx_ps.ps_repeatcount = radio->ps_repeatcount;
2477 tx_ps.ps_len = bytes_to_copy;
2478
2479 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2480 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
2481 break;
2482 case V4L2_CID_RDS_TX_RADIO_TEXT:
2483 bytes_to_copy =
2484 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2485 data = (ctrl->controls[0]).string;
2486
2487 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
2488
2489 if (copy_from_user(tx_rt.rt_data,
2490 data, bytes_to_copy))
2491 return -EFAULT;
2492
2493 tx_rt.rt_control = 0x01;
2494 tx_rt.pi = radio->pi;
2495 tx_rt.pty = radio->pty;
2496 tx_rt.ps_len = bytes_to_copy;
2497
2498 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2499 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
2500 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302501 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
2502 data = (ctrl->controls[0]).string;
2503 memset(&default_data, 0, sizeof(default_data));
2504 if (copy_from_user(&default_data, data, sizeof(default_data)))
2505 return -EFAULT;
2506 retval = hci_def_data_write(&default_data, radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302507 break;
2508 case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
2509 FMDERR("In Set Calibration");
2510 data = (ctrl->controls[0]).string;
2511 bytes_to_copy = (ctrl->controls[0]).size;
2512 memset(cal_req.data, 0, MAX_CALIB_SIZE);
2513 cal_req.mode = PROCS_CALIB_MODE;
2514 if (copy_from_user(&cal_req.data[0],
2515 data, PROCS_CALIB_SIZE))
2516 return -EFAULT;
2517 retval = radio_hci_request(radio->fm_hdev, hci_fm_set_cal_req,
2518 (unsigned long)&cal_req, RADIO_HCI_TIMEOUT);
2519 if (retval < 0)
2520 FMDERR("Set Process calibration failed %d", retval);
2521 if (copy_from_user(&cal_req.data[PROCS_CALIB_SIZE],
2522 data, DC_CALIB_SIZE))
2523 return -EFAULT;
2524 cal_req.mode = DC_CALIB_MODE;
2525 retval = radio_hci_request(radio->fm_hdev, hci_fm_set_cal_req,
2526 (unsigned long)&cal_req, RADIO_HCI_TIMEOUT);
2527 if (retval < 0)
2528 FMDERR("Set DC calibration failed %d", retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302529 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002530 default:
2531 FMDBG("Shouldn't reach here\n");
2532 retval = -1;
2533 }
2534 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002535}
2536
2537static int iris_vidioc_s_ctrl(struct file *file, void *priv,
2538 struct v4l2_control *ctrl)
2539{
2540 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2541 int retval = 0;
2542 unsigned int rds_grps_proc = 0;
2543 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002544 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302545 struct hci_fm_tx_ps tx_ps = {0};
2546 struct hci_fm_tx_rt tx_rt = {0};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547
2548 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302549 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002550 radio->tone_freq = ctrl->value;
2551 retval = radio_hci_request(radio->fm_hdev,
2552 hci_fm_tone_generator, arg,
2553 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
2554 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002555 case V4L2_CID_AUDIO_VOLUME:
2556 break;
2557 case V4L2_CID_AUDIO_MUTE:
2558 radio->mute_mode.hard_mute = ctrl->value;
2559 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
2560 retval = hci_set_fm_mute_mode(
2561 &radio->mute_mode,
2562 radio->fm_hdev);
2563 if (retval < 0)
2564 FMDERR("Error while set FM hard mute"" %d\n",
2565 retval);
2566 break;
2567 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2568 radio->g_search_mode = ctrl->value;
2569 break;
2570 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2571 radio->g_scan_time = ctrl->value;
2572 break;
2573 case V4L2_CID_PRIVATE_IRIS_SRCHON:
2574 iris_search(radio, ctrl->value, SRCH_DIR_UP);
2575 break;
2576 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002577 switch (ctrl->value) {
2578 case FM_RECV:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2580 radio->fm_hdev);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002581
2582 radio->mode = FM_RECV;
2583
2584 if (retval < 0)
2585 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002586 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002587 radio->mute_mode.soft_mute = CTRL_ON;
2588 retval = hci_set_fm_mute_mode(
2589 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302591 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002592 FMDERR("Failed to enable Smute\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302593 return retval;
2594 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002595 radio->stereo_mode.stereo_mode = CTRL_OFF;
2596 radio->stereo_mode.sig_blend = CTRL_ON;
2597 radio->stereo_mode.intf_blend = CTRL_ON;
2598 radio->stereo_mode.most_switch = CTRL_ON;
2599 retval = hci_set_fm_stereo_mode(
2600 &radio->stereo_mode,
2601 radio->fm_hdev);
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302602 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002603 FMDERR("Failed to set stereo mode\n");
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302604 return retval;
2605 }
Srinivasa Rao Uppalaf0d13742011-09-08 10:13:13 +05302606 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2607 radio->fm_hdev);
2608 if (retval < 0)
2609 FMDERR("Failed to get the Recv Config\n");
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002610 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002611 case FM_TRANS:
2612 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
2613 radio->fm_hdev);
2614 radio->mode = FM_TRANS;
2615
2616 if (retval < 0)
2617 FMDERR("Error while enabling TRANS FM"
2618 " %d\n", retval);
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07002619 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002620 case FM_OFF:
2621 switch (radio->mode) {
2622 case FM_RECV:
2623 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2624 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002626 FMDERR("Err on disable recv FM"
2627 " %d\n", retval);
2628 break;
2629 case FM_TRANS:
2630 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
2631 radio->fm_hdev);
2632
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002633 if (retval < 0)
Ankur Nandwanid928d542011-08-11 13:15:41 -07002634 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002635 " %d\n", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07002636 break;
2637 default:
2638 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05302640 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002641 default:
2642 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002643 }
2644 break;
2645 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002646 if (radio->mode == FM_RECV) {
2647 retval = iris_recv_set_region(radio, ctrl->value);
2648 } else {
2649 if (radio->mode == FM_TRANS)
2650 retval = iris_trans_set_region(radio,
2651 ctrl->value);
2652 else
2653 retval = -EINVAL;
2654 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655 break;
2656 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2657 temp_val = ctrl->value;
2658 retval = hci_fm_set_signal_threshold(
2659 &temp_val,
2660 radio->fm_hdev);
2661 if (retval < 0) {
2662 FMDERR("Error while setting signal threshold\n");
2663 break;
2664 }
2665 break;
2666 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
2667 radio->srch_rds.srch_pty = ctrl->value;
2668 radio->srch_st_list.srch_pty = ctrl->value;
2669 break;
2670 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
2671 radio->srch_rds.srch_pi = ctrl->value;
2672 break;
2673 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
2674 break;
2675 case V4L2_CID_PRIVATE_IRIS_SPACING:
2676 radio->recv_conf.ch_spacing = ctrl->value;
2677 break;
2678 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002679 switch (radio->mode) {
2680 case FM_RECV:
2681 radio->recv_conf.emphasis = ctrl->value;
2682 retval = hci_set_fm_recv_conf(
2683 &radio->recv_conf,
2684 radio->fm_hdev);
2685 if (retval < 0)
2686 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002687 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002688 case FM_TRANS:
2689 radio->trans_conf.emphasis = ctrl->value;
2690 retval = hci_set_fm_trans_conf(
2691 &radio->trans_conf,
2692 radio->fm_hdev);
2693 if (retval < 0)
2694 FMDERR("Error in setting emphasis");
2695 break;
2696 default:
2697 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002698 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 break;
2700 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002701 switch (radio->mode) {
2702 case FM_RECV:
2703 radio->recv_conf.rds_std = ctrl->value;
2704 retval = hci_set_fm_recv_conf(
2705 &radio->recv_conf,
2706 radio->fm_hdev);
2707 if (retval < 0)
2708 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07002709 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002710 case FM_TRANS:
2711 radio->trans_conf.rds_std = ctrl->value;
2712 retval = hci_set_fm_trans_conf(
2713 &radio->trans_conf,
2714 radio->fm_hdev);
2715 if (retval < 0)
2716 FMDERR("Error in rds_Std");
2717 break;
2718 default:
2719 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002720 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002721 break;
2722 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002723 switch (radio->mode) {
2724 case FM_RECV:
2725 radio->recv_conf.rds_std = ctrl->value;
2726 retval = hci_set_fm_recv_conf(
2727 &radio->recv_conf,
2728 radio->fm_hdev);
2729 if (retval < 0)
2730 FMDERR("Error in rds_std");
2731 break;
2732 case FM_TRANS:
2733 radio->trans_conf.rds_std = ctrl->value;
2734 retval = hci_set_fm_trans_conf(
2735 &radio->trans_conf,
2736 radio->fm_hdev);
2737 if (retval < 0)
2738 FMDERR("Error in rds_Std");
2739 break;
2740 default:
2741 retval = -EINVAL;
2742 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002743 break;
2744 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2745 radio->rds_grp.rds_grp_enable_mask = ctrl->value;
2746 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
2747 break;
2748 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
2749 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002750 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002752 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002753 radio->fm_hdev);
2754 break;
2755 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2756 radio->rds_grp.rds_buf_size = ctrl->value;
2757 break;
2758 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002759 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
2760 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2761 retval = hci_fm_rds_grps_process(
2762 &radio->g_rds_grp_proc_ps,
2763 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302765 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
2766 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_OFFSET);
2767 radio->g_rds_grp_proc_ps |= rds_grps_proc;
2768 retval = hci_fm_rds_grps_process(
2769 &radio->g_rds_grp_proc_ps,
2770 radio->fm_hdev);
2771 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
2773 break;
2774 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2775 temp_val = ctrl->value;
2776 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
2777 break;
2778 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002779 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780 break;
2781 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002782 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002783 break;
2784 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302785 tx_ps.ps_control = 0x00;
2786 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
2787 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002788 break;
2789 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302790 tx_rt.rt_control = 0x00;
2791 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
2792 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002793 break;
2794 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002795 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002796 break;
2797 case V4L2_CID_TUNE_POWER_LEVEL:
2798 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002799 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2800 radio->mute_mode.soft_mute = ctrl->value;
2801 retval = hci_set_fm_mute_mode(
2802 &radio->mute_mode,
2803 radio->fm_hdev);
2804 if (retval < 0)
2805 FMDERR("Error while setting FM soft mute"" %d\n",
2806 retval);
2807 break;
2808 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
2809 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
2810 break;
2811 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
2812 radio->riva_data_req.cmd_params.length = ctrl->value;
2813 break;
2814 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
2815 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
2816 radio->riva_data_req.cmd_params.length);
2817 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
2818 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
2819 break;
2820 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
2821 radio->ssbi_data_accs.start_addr = ctrl->value;
2822 break;
2823 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
2824 radio->ssbi_data_accs.data = ctrl->value;
2825 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
2826 radio->fm_hdev);
2827 break;
2828 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
2829 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
2830 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
2831 radio->fm_hdev);
2832 break;
2833 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
2834 radio->ssbi_peek_reg.start_address = ctrl->value;
2835 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
2836 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302837 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
2838 temp_val = ctrl->value;
2839 hci_read_grp_counters(&temp_val, radio->fm_hdev);
2840 break;
2841 case V4L2_CID_PRIVATE_IRIS_HLSI:
2842 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
2843 radio->fm_hdev);
2844 if (retval)
2845 break;
2846 radio->recv_conf.hlsi = ctrl->value;
2847 retval = hci_set_fm_recv_conf(
2848 &radio->recv_conf,
2849 radio->fm_hdev);
2850 break;
2851 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
2852 temp_val = ctrl->value;
2853 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
2854 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002855
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002856 default:
2857 retval = -EINVAL;
2858 }
2859 return retval;
2860}
2861
2862static int iris_vidioc_g_tuner(struct file *file, void *priv,
2863 struct v4l2_tuner *tuner)
2864{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002865 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002866 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867 if (tuner->index > 0)
2868 return -EINVAL;
2869
2870 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
2871 if (retval < 0)
2872 return retval;
2873
2874 tuner->type = V4L2_TUNER_RADIO;
2875 tuner->rangelow = radio->recv_conf.band_low_limit * TUNE_PARAM;
2876 tuner->rangehigh = radio->recv_conf.band_high_limit * TUNE_PARAM;
2877 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
2878 tuner->capability = V4L2_TUNER_CAP_LOW;
2879 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
2880 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
2881 tuner->afc = 0;
2882
2883 return 0;
2884}
2885
2886static int iris_vidioc_s_tuner(struct file *file, void *priv,
2887 struct v4l2_tuner *tuner)
2888{
2889 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07002890 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891 if (tuner->index > 0)
2892 return -EINVAL;
2893
Ankur Nandwanid928d542011-08-11 13:15:41 -07002894 if (radio->mode == FM_RECV) {
2895 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
2896 radio->recv_conf.band_high_limit =
2897 tuner->rangehigh / TUNE_PARAM;
2898 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
2899 radio->stereo_mode.stereo_mode = 0x01;
2900 retval = hci_set_fm_stereo_mode(
2901 &radio->stereo_mode,
2902 radio->fm_hdev);
2903 } else {
2904 radio->stereo_mode.stereo_mode = 0x00;
2905 retval = hci_set_fm_stereo_mode(
2906 &radio->stereo_mode,
2907 radio->fm_hdev);
2908 }
2909 if (retval < 0)
2910 FMDERR(": set tuner failed with %d\n", retval);
2911 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002912 } else {
Ankur Nandwanid928d542011-08-11 13:15:41 -07002913 if (radio->mode == FM_TRANS) {
2914 radio->trans_conf.band_low_limit =
2915 tuner->rangelow / TUNE_PARAM;
2916 radio->trans_conf.band_high_limit =
2917 tuner->rangehigh / TUNE_PARAM;
2918 } else {
2919 return -EINVAL;
2920 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002921 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002922
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923 return retval;
2924}
2925
2926static int iris_vidioc_g_frequency(struct file *file, void *priv,
2927 struct v4l2_frequency *freq)
2928{
2929 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2930 int retval;
2931
2932 freq->type = V4L2_TUNER_RADIO;
2933 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
2934 if (retval < 0)
2935 FMDERR("get frequency failed %d\n", retval);
2936 else
2937 freq->frequency =
2938 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
2939 return retval;
2940}
2941
2942static int iris_vidioc_s_frequency(struct file *file, void *priv,
2943 struct v4l2_frequency *freq)
2944{
2945 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2946 int retval = -1;
2947 freq->frequency = freq->frequency / TUNE_PARAM;
2948
2949 if (freq->type != V4L2_TUNER_RADIO)
2950 return -EINVAL;
2951
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002952 /* We turn off RDS prior to tuning to a new station.
2953 because of a bug in SoC which prevents tuning
2954 during RDS transmission.
2955 */
2956 if (radio->mode == FM_TRANS
2957 && (radio->trans_conf.rds_std == 0 ||
2958 radio->trans_conf.rds_std == 1)) {
2959 radio->prev_trans_rds = radio->trans_conf.rds_std;
2960 radio->trans_conf.rds_std = 2;
2961 hci_set_fm_trans_conf(&radio->trans_conf,
2962 radio->fm_hdev);
2963 }
2964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002965 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07002966
2967 if (radio->mode == FM_TRANS
2968 && radio->trans_conf.rds_std == 2
2969 && (radio->prev_trans_rds == 1
2970 || radio->prev_trans_rds == 0)) {
2971 radio->trans_conf.rds_std = radio->prev_trans_rds;
2972 hci_set_fm_trans_conf(&radio->trans_conf,
2973 radio->fm_hdev);
2974 }
2975
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976 if (retval < 0)
2977 FMDERR(" set frequency failed with %d\n", retval);
2978 return retval;
2979}
2980
2981static int iris_vidioc_dqbuf(struct file *file, void *priv,
2982 struct v4l2_buffer *buffer)
2983{
2984 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2985 enum iris_buf_t buf_type = buffer->index;
2986 struct kfifo *data_fifo;
2987 unsigned char *buf = (unsigned char *)buffer->m.userptr;
2988 unsigned int len = buffer->length;
2989 if (!access_ok(VERIFY_WRITE, buf, len))
2990 return -EFAULT;
2991 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
2992 data_fifo = &radio->data_buf[buf_type];
2993 if (buf_type == IRIS_BUF_EVENTS)
2994 if (wait_event_interruptible(radio->event_queue,
2995 kfifo_len(data_fifo)) < 0)
2996 return -EINTR;
2997 } else {
2998 FMDERR("invalid buffer type\n");
2999 return -EINVAL;
3000 }
3001 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3002 &radio->buf_lock[buf_type]);
3003
3004 return 0;
3005}
3006
3007static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
3008 struct v4l2_format *f)
3009{
3010 return 0;
3011
3012}
3013
3014static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3015 struct v4l2_hw_freq_seek *seek)
3016{
3017 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3018 int dir;
3019 if (seek->seek_upward)
3020 dir = SRCH_DIR_UP;
3021 else
3022 dir = SRCH_DIR_DOWN;
3023 return iris_search(radio, CTRL_ON, dir);
3024}
3025
3026static int iris_vidioc_querycap(struct file *file, void *priv,
3027 struct v4l2_capability *capability)
3028{
3029 struct iris_device *radio;
3030 radio = video_get_drvdata(video_devdata(file));
3031 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
3032 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
3033 radio->g_cap = capability;
3034 return 0;
3035}
3036
3037
3038static const struct v4l2_ioctl_ops iris_ioctl_ops = {
3039 .vidioc_querycap = iris_vidioc_querycap,
3040 .vidioc_queryctrl = iris_vidioc_queryctrl,
3041 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
3042 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
3043 .vidioc_g_tuner = iris_vidioc_g_tuner,
3044 .vidioc_s_tuner = iris_vidioc_s_tuner,
3045 .vidioc_g_frequency = iris_vidioc_g_frequency,
3046 .vidioc_s_frequency = iris_vidioc_s_frequency,
3047 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
3048 .vidioc_dqbuf = iris_vidioc_dqbuf,
3049 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
3050 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303051 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052};
3053
3054static const struct v4l2_file_operations iris_fops = {
3055 .owner = THIS_MODULE,
3056 .unlocked_ioctl = video_ioctl2,
3057};
3058
3059static struct video_device iris_viddev_template = {
3060 .fops = &iris_fops,
3061 .ioctl_ops = &iris_ioctl_ops,
3062 .name = DRIVER_NAME,
3063 .release = video_device_release,
3064};
3065
3066static struct video_device *video_get_dev(void)
3067{
3068 return priv_videodev;
3069}
3070
3071static int __init iris_probe(struct platform_device *pdev)
3072{
3073 struct iris_device *radio;
3074 int retval;
3075 int radio_nr = -1;
3076 int i;
3077
3078 if (!pdev) {
3079 FMDERR(": pdev is null\n");
3080 return -ENOMEM;
3081 }
3082
3083 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
3084 if (!radio) {
3085 FMDERR(": Could not allocate radio device\n");
3086 return -ENOMEM;
3087 }
3088
3089 radio->dev = &pdev->dev;
3090 platform_set_drvdata(pdev, radio);
3091
3092 radio->videodev = video_device_alloc();
3093 if (!radio->videodev) {
3094 FMDERR(": Could not allocate V4L device\n");
3095 kfree(radio);
3096 return -ENOMEM;
3097 }
3098
3099 memcpy(radio->videodev, &iris_viddev_template,
3100 sizeof(iris_viddev_template));
3101
3102 for (i = 0; i < IRIS_BUF_MAX; i++) {
3103 int kfifo_alloc_rc = 0;
3104 spin_lock_init(&radio->buf_lock[i]);
3105
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07003106 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003107 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3108 rds_buf*3, GFP_KERNEL);
3109 else
3110 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3111 STD_BUF_SIZE, GFP_KERNEL);
3112
3113 if (kfifo_alloc_rc != 0) {
3114 FMDERR("failed allocating buffers %d\n",
3115 kfifo_alloc_rc);
3116 for (; i > -1; i--) {
3117 kfifo_free(&radio->data_buf[i]);
3118 kfree(radio);
3119 return -ENOMEM;
3120 }
3121 }
3122 }
3123
3124 mutex_init(&radio->lock);
3125 init_completion(&radio->sync_xfr_start);
3126 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003127 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003128 init_waitqueue_head(&radio->event_queue);
3129 init_waitqueue_head(&radio->read_queue);
3130
3131 video_set_drvdata(radio->videodev, radio);
3132
3133 if (NULL == video_get_drvdata(radio->videodev))
3134 FMDERR(": video_get_drvdata failed\n");
3135
3136 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
3137 radio_nr);
3138 if (retval) {
3139 FMDERR(": Could not register video device\n");
3140 video_device_release(radio->videodev);
3141 for (; i > -1; i--)
3142 kfifo_free(&radio->data_buf[i]);
3143 kfree(radio);
3144 return retval;
3145 } else {
3146 priv_videodev = kzalloc(sizeof(struct video_device),
3147 GFP_KERNEL);
3148 memcpy(priv_videodev, radio->videodev,
3149 sizeof(struct video_device));
3150 }
3151 return 0;
3152}
3153
3154
3155static int __devexit iris_remove(struct platform_device *pdev)
3156{
3157 int i;
3158 struct iris_device *radio = platform_get_drvdata(pdev);
3159
3160 video_unregister_device(radio->videodev);
3161
3162 for (i = 0; i < IRIS_BUF_MAX; i++)
3163 kfifo_free(&radio->data_buf[i]);
3164
3165 kfree(radio);
3166
3167 platform_set_drvdata(pdev, NULL);
3168
3169 return 0;
3170}
3171
3172static struct platform_driver iris_driver = {
3173 .driver = {
3174 .owner = THIS_MODULE,
3175 .name = "iris_fm",
3176 },
3177 .remove = __devexit_p(iris_remove),
3178};
3179
3180static int __init iris_radio_init(void)
3181{
3182 return platform_driver_probe(&iris_driver, iris_probe);
3183}
3184module_init(iris_radio_init);
3185
3186static void __exit iris_radio_exit(void)
3187{
3188 platform_driver_unregister(&iris_driver);
3189}
3190module_exit(iris_radio_exit);
3191
3192MODULE_LICENSE("GPL v2");
3193MODULE_AUTHOR(DRIVER_AUTHOR);
3194MODULE_DESCRIPTION(DRIVER_DESC);