blob: 4391dba7b6b92fad6e364cd67d07632e6336e6c1 [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;
58
59 struct video_device *videodev;
60
61 struct mutex lock;
62 spinlock_t buf_lock[IRIS_BUF_MAX];
63 wait_queue_head_t event_queue;
64 wait_queue_head_t read_queue;
65
66 struct radio_hci_dev *fm_hdev;
67
68 struct v4l2_capability *g_cap;
69 struct v4l2_control *g_ctl;
70
71 struct hci_fm_mute_mode_req mute_mode;
72 struct hci_fm_stereo_mode_req stereo_mode;
73 struct hci_fm_station_rsp fm_st_rsp;
74 struct hci_fm_search_station_req srch_st;
75 struct hci_fm_search_rds_station_req srch_rds;
76 struct hci_fm_search_station_list_req srch_st_list;
77 struct hci_fm_recv_conf_req recv_conf;
78 struct hci_fm_rds_grp_req rds_grp;
79 unsigned char g_search_mode;
80 unsigned char g_scan_time;
81 unsigned int g_antenna;
82 unsigned int g_rds_grp_proc_ps;
83 enum iris_region_t region;
84 struct hci_fm_dbg_param_rsp st_dbg_param;
85 struct hci_ev_srch_list_compl srch_st_result;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -070086 struct hci_fm_riva_poke riva_data_req;
87 struct hci_fm_ssbi_req ssbi_data_accs;
88 struct hci_fm_ssbi_peek ssbi_peek_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089};
90
91static struct video_device *priv_videodev;
92
93static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
94 {
95 .id = V4L2_CID_AUDIO_VOLUME,
96 .type = V4L2_CTRL_TYPE_INTEGER,
97 .name = "Volume",
98 .minimum = 0,
99 .maximum = 15,
100 .step = 1,
101 .default_value = 15,
102 },
103 {
104 .id = V4L2_CID_AUDIO_BALANCE,
105 .flags = V4L2_CTRL_FLAG_DISABLED,
106 },
107 {
108 .id = V4L2_CID_AUDIO_BASS,
109 .flags = V4L2_CTRL_FLAG_DISABLED,
110 },
111 {
112 .id = V4L2_CID_AUDIO_TREBLE,
113 .flags = V4L2_CTRL_FLAG_DISABLED,
114 },
115 {
116 .id = V4L2_CID_AUDIO_MUTE,
117 .type = V4L2_CTRL_TYPE_BOOLEAN,
118 .name = "Mute",
119 .minimum = 0,
120 .maximum = 1,
121 .step = 1,
122 .default_value = 1,
123 },
124 {
125 .id = V4L2_CID_AUDIO_LOUDNESS,
126 .flags = V4L2_CTRL_FLAG_DISABLED,
127 },
128 {
129 .id = V4L2_CID_PRIVATE_IRIS_SRCHMODE,
130 .type = V4L2_CTRL_TYPE_INTEGER,
131 .name = "Search mode",
132 .minimum = 0,
133 .maximum = 7,
134 .step = 1,
135 .default_value = 0,
136 },
137 {
138 .id = V4L2_CID_PRIVATE_IRIS_SCANDWELL,
139 .type = V4L2_CTRL_TYPE_INTEGER,
140 .name = "Search dwell time",
141 .minimum = 0,
142 .maximum = 7,
143 .step = 1,
144 .default_value = 0,
145 },
146 {
147 .id = V4L2_CID_PRIVATE_IRIS_SRCHON,
148 .type = V4L2_CTRL_TYPE_BOOLEAN,
149 .name = "Search on/off",
150 .minimum = 0,
151 .maximum = 1,
152 .step = 1,
153 .default_value = 1,
154
155 },
156 {
157 .id = V4L2_CID_PRIVATE_IRIS_STATE,
158 .type = V4L2_CTRL_TYPE_INTEGER,
159 .name = "radio 0ff/rx/tx/reset",
160 .minimum = 0,
161 .maximum = 3,
162 .step = 1,
163 .default_value = 1,
164
165 },
166 {
167 .id = V4L2_CID_PRIVATE_IRIS_REGION,
168 .type = V4L2_CTRL_TYPE_INTEGER,
169 .name = "radio standard",
170 .minimum = 0,
171 .maximum = 2,
172 .step = 1,
173 .default_value = 0,
174 },
175 {
176 .id = V4L2_CID_PRIVATE_IRIS_SIGNAL_TH,
177 .type = V4L2_CTRL_TYPE_INTEGER,
178 .name = "Signal Threshold",
179 .minimum = 0x80,
180 .maximum = 0x7F,
181 .step = 1,
182 .default_value = 0,
183 },
184 {
185 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PTY,
186 .type = V4L2_CTRL_TYPE_INTEGER,
187 .name = "Search PTY",
188 .minimum = 0,
189 .maximum = 31,
190 .default_value = 0,
191 },
192 {
193 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PI,
194 .type = V4L2_CTRL_TYPE_INTEGER,
195 .name = "Search PI",
196 .minimum = 0,
197 .maximum = 0xFF,
198 .default_value = 0,
199 },
200 {
201 .id = V4L2_CID_PRIVATE_IRIS_SRCH_CNT,
202 .type = V4L2_CTRL_TYPE_INTEGER,
203 .name = "Preset num",
204 .minimum = 0,
205 .maximum = 12,
206 .default_value = 0,
207 },
208 {
209 .id = V4L2_CID_PRIVATE_IRIS_EMPHASIS,
210 .type = V4L2_CTRL_TYPE_BOOLEAN,
211 .name = "Emphasis",
212 .minimum = 0,
213 .maximum = 1,
214 .default_value = 0,
215 },
216 {
217 .id = V4L2_CID_PRIVATE_IRIS_RDS_STD,
218 .type = V4L2_CTRL_TYPE_BOOLEAN,
219 .name = "RDS standard",
220 .minimum = 0,
221 .maximum = 1,
222 .default_value = 0,
223 },
224 {
225 .id = V4L2_CID_PRIVATE_IRIS_SPACING,
226 .type = V4L2_CTRL_TYPE_INTEGER,
227 .name = "Channel spacing",
228 .minimum = 0,
229 .maximum = 2,
230 .default_value = 0,
231 },
232 {
233 .id = V4L2_CID_PRIVATE_IRIS_RDSON,
234 .type = V4L2_CTRL_TYPE_BOOLEAN,
235 .name = "RDS on/off",
236 .minimum = 0,
237 .maximum = 1,
238 .default_value = 0,
239 },
240 {
241 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK,
242 .type = V4L2_CTRL_TYPE_INTEGER,
243 .name = "RDS group mask",
244 .minimum = 0,
245 .maximum = 0xFFFFFFFF,
246 .default_value = 0,
247 },
248 {
249 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC,
250 .type = V4L2_CTRL_TYPE_INTEGER,
251 .name = "RDS processing",
252 .minimum = 0,
253 .maximum = 0xFF,
254 .default_value = 0,
255 },
256 {
257 .id = V4L2_CID_PRIVATE_IRIS_RDSD_BUF,
258 .type = V4L2_CTRL_TYPE_INTEGER,
259 .name = "RDS data groups to buffer",
260 .minimum = 1,
261 .maximum = 21,
262 .default_value = 0,
263 },
264 {
265 .id = V4L2_CID_PRIVATE_IRIS_PSALL,
266 .type = V4L2_CTRL_TYPE_BOOLEAN,
267 .name = "pass all ps strings",
268 .minimum = 0,
269 .maximum = 1,
270 .default_value = 0,
271 },
272 {
273 .id = V4L2_CID_PRIVATE_IRIS_LP_MODE,
274 .type = V4L2_CTRL_TYPE_BOOLEAN,
275 .name = "Low power mode",
276 .minimum = 0,
277 .maximum = 1,
278 .default_value = 0,
279 },
280 {
281 .id = V4L2_CID_PRIVATE_IRIS_ANTENNA,
282 .type = V4L2_CTRL_TYPE_BOOLEAN,
283 .name = "headset/internal",
284 .minimum = 0,
285 .maximum = 1,
286 .default_value = 0,
287 },
288
289 {
290 .id = V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT,
291 .type = V4L2_CTRL_TYPE_INTEGER,
292 .name = "Set PS REPEATCOUNT",
293 .minimum = 0,
294 .maximum = 15,
295 },
296 {
297 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME,
298 .type = V4L2_CTRL_TYPE_BOOLEAN,
299 .name = "Stop PS NAME",
300 .minimum = 0,
301 .maximum = 1,
302 },
303 {
304 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT,
305 .type = V4L2_CTRL_TYPE_BOOLEAN,
306 .name = "Stop RT",
307 .minimum = 0,
308 .maximum = 1,
309 },
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700310 {
311 .id = V4L2_CID_PRIVATE_IRIS_SOFT_MUTE,
312 .type = V4L2_CTRL_TYPE_BOOLEAN,
313 .name = "Soft Mute",
314 .minimum = 0,
315 .maximum = 1,
316 },
317 {
318 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR,
319 .type = V4L2_CTRL_TYPE_BOOLEAN,
320 .name = "Riva addr",
321 .minimum = 0,
322 .maximum = 0x31E0004,
323 },
324 {
325 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN,
326 .type = V4L2_CTRL_TYPE_INTEGER,
327 .name = "Data len",
328 .minimum = 0,
329 .maximum = 0xFF,
330 },
331 {
332 .id = V4L2_CID_PRIVATE_IRIS_RIVA_PEEK,
333 .type = V4L2_CTRL_TYPE_BOOLEAN,
334 .name = "Riva peek",
335 .minimum = 0,
336 .maximum = 1,
337 },
338 {
339 .id = V4L2_CID_PRIVATE_IRIS_RIVA_POKE,
340 .type = V4L2_CTRL_TYPE_INTEGER,
341 .name = "Riva poke",
342 .minimum = 0,
343 .maximum = 0x31E0004,
344 },
345 {
346 .id = V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR,
347 .type = V4L2_CTRL_TYPE_INTEGER,
348 .name = "Ssbi addr",
349 .minimum = 0,
350 .maximum = 0x37F,
351 },
352 {
353 .id = V4L2_CID_PRIVATE_IRIS_SSBI_PEEK,
354 .type = V4L2_CTRL_TYPE_INTEGER,
355 .name = "Ssbi peek",
356 .minimum = 0,
357 .maximum = 0x37F,
358 },
359 {
360 .id = V4L2_CID_PRIVATE_IRIS_SSBI_POKE,
361 .type = V4L2_CTRL_TYPE_INTEGER,
362 .name = "ssbi poke",
363 .minimum = 0x01,
364 .maximum = 0xFF,
365 },
366 {
367 .id = V4L2_CID_PRIVATE_IRIS_HLSI,
368 .type = V4L2_CTRL_TYPE_INTEGER,
369 .name = "set hlsi",
370 .minimum = 0,
371 .maximum = 2,
372 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373
374};
375
376static void iris_q_event(struct iris_device *radio,
377 enum iris_evt_t event)
378{
379 struct kfifo *data_b = &radio->data_buf[IRIS_BUF_EVENTS];
380 unsigned char evt = event;
381 if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
382 wake_up_interruptible(&radio->event_queue);
383}
384
385static int hci_send_frame(struct sk_buff *skb)
386{
387 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
388
389 if (!hdev) {
390 kfree_skb(skb);
391 return -ENODEV;
392 }
393
394 __net_timestamp(skb);
395
396 skb_orphan(skb);
397 return hdev->send(skb);
398}
399
400static void radio_hci_cmd_task(unsigned long arg)
401{
402 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
403 struct sk_buff *skb;
404 if (!(atomic_read(&hdev->cmd_cnt))
405 && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
406 FMDERR("%s command tx timeout", hdev->name);
407 atomic_set(&hdev->cmd_cnt, 1);
408 }
409
410 skb = skb_dequeue(&hdev->cmd_q);
411 if (atomic_read(&hdev->cmd_cnt) && skb) {
412 kfree_skb(hdev->sent_cmd);
413 hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
414 if (hdev->sent_cmd) {
415 atomic_dec(&hdev->cmd_cnt);
416 hci_send_frame(skb);
417 hdev->cmd_last_tx = jiffies;
418 } else {
419 skb_queue_head(&hdev->cmd_q, skb);
420 tasklet_schedule(&hdev->cmd_task);
421 }
422 }
423
424}
425
426static void radio_hci_rx_task(unsigned long arg)
427{
428 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
429 struct sk_buff *skb;
430
431 read_lock(&hci_task_lock);
432
433 skb = skb_dequeue(&hdev->rx_q);
434 radio_hci_event_packet(hdev, skb);
435
436 read_unlock(&hci_task_lock);
437}
438
439int radio_hci_register_dev(struct radio_hci_dev *hdev)
440{
441 struct iris_device *radio = video_get_drvdata(video_get_dev());
442 if (!radio) {
443 FMDERR(":radio is null");
444 return -EINVAL;
445 }
446
447 if (!hdev) {
448 FMDERR("hdev is null");
449 return -EINVAL;
450 }
451
452 hdev->flags = 0;
453
454 tasklet_init(&hdev->cmd_task, radio_hci_cmd_task, (unsigned long)
455 hdev);
456 tasklet_init(&hdev->rx_task, radio_hci_rx_task, (unsigned long)
457 hdev);
458
459 init_waitqueue_head(&hdev->req_wait_q);
460
461 skb_queue_head_init(&hdev->rx_q);
462 skb_queue_head_init(&hdev->cmd_q);
463 skb_queue_head_init(&hdev->raw_q);
464
465 if (!radio)
466 FMDERR(":radio is null");
467
468 radio->fm_hdev = hdev;
469
470 return 0;
471}
472EXPORT_SYMBOL(radio_hci_register_dev);
473
474int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
475{
476 struct iris_device *radio = video_get_drvdata(video_get_dev());
477 if (!radio) {
478 FMDERR(":radio is null");
479 return -EINVAL;
480 }
481
482 tasklet_kill(&hdev->rx_task);
483 tasklet_kill(&hdev->cmd_task);
484 skb_queue_purge(&hdev->rx_q);
485 skb_queue_purge(&hdev->cmd_q);
486 skb_queue_purge(&hdev->raw_q);
487 kfree(radio->fm_hdev);
488 kfree(radio->videodev);
489
490 return 0;
491}
492EXPORT_SYMBOL(radio_hci_unregister_dev);
493
494int radio_hci_recv_frame(struct sk_buff *skb)
495{
496 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
497 if (!hdev) {
498 FMDERR("%s hdev is null while receiving frame", hdev->name);
499 kfree_skb(skb);
500 return -ENXIO;
501 }
502
503 __net_timestamp(skb);
504
505 radio_hci_event_packet(hdev, skb);
506
507 return 0;
508}
509EXPORT_SYMBOL(radio_hci_recv_frame);
510
511int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
512 void *param)
513{
514 int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
515 struct radio_hci_command_hdr *hdr;
516 struct sk_buff *skb;
517 int ret = 0;
518
519 skb = alloc_skb(len, GFP_ATOMIC);
520 if (!skb) {
521 FMDERR("%s no memory for command", hdev->name);
522 return -ENOMEM;
523 }
524
525 hdr = (struct radio_hci_command_hdr *) skb_put(skb,
526 RADIO_HCI_COMMAND_HDR_SIZE);
527 hdr->opcode = cpu_to_le16(opcode);
528 hdr->plen = plen;
529
530 if (plen)
531 memcpy(skb_put(skb, plen), param, plen);
532
533 skb->dev = (void *) hdev;
534
535 ret = hci_send_frame(skb);
536
537 return ret;
538}
539EXPORT_SYMBOL(radio_hci_send_cmd);
540
541static int hci_fm_enable_recv_req(struct radio_hci_dev *hdev,
542 unsigned long param)
543{
544 __u16 opcode = 0;
545
546 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
547 HCI_OCF_FM_ENABLE_RECV_REQ);
548 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
549}
550
551static int hci_fm_disable_recv_req(struct radio_hci_dev *hdev,
552 unsigned long param)
553{
554 __u16 opcode = 0;
555
556 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
557 HCI_OCF_FM_DISABLE_RECV_REQ);
558 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
559}
560
561static int hci_get_fm_recv_conf_req(struct radio_hci_dev *hdev,
562 unsigned long param)
563{
564 __u16 opcode = 0;
565
566 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
567 HCI_OCF_FM_GET_RECV_CONF_REQ);
568 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
569}
570
571static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
572 unsigned long param)
573{
574 __u16 opcode = 0;
575
576 struct hci_fm_recv_conf_req *recv_conf_req =
577 (struct hci_fm_recv_conf_req *) param;
578
579 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
580 HCI_OCF_FM_SET_RECV_CONF_REQ);
581 return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
582 recv_conf_req);
583}
584
585static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
586 unsigned long param)
587{
588 __u16 opcode = 0;
589
590 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
591 HCI_OCF_FM_GET_STATION_PARAM_REQ);
592 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
593}
594
595static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
596 unsigned long param)
597{
598 __u16 opcode = 0;
599 struct hci_fm_mute_mode_req *mute_mode_req =
600 (struct hci_fm_mute_mode_req *) param;
601
602 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
603 HCI_OCF_FM_SET_MUTE_MODE_REQ);
604 return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
605 mute_mode_req);
606}
607
608static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
609 unsigned long param)
610{
611 __u16 opcode = 0;
612 struct hci_fm_stereo_mode_req *stereo_mode_req =
613 (struct hci_fm_stereo_mode_req *) param;
614 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
615 HCI_OCF_FM_SET_STEREO_MODE_REQ);
616 return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
617 stereo_mode_req);
618}
619
620static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
621 unsigned long param)
622{
623 __u16 opcode = 0;
624
625 __u8 antenna = param;
626
627 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
628 HCI_OCF_FM_SET_ANTENNA);
629 return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
630}
631
632static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
633 unsigned long param)
634{
635 __u16 opcode = 0;
636
637 __u8 sig_threshold = param;
638
639 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
640 HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
641 return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
642 &sig_threshold);
643}
644
645static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
646 unsigned long param)
647{
648 __u16 opcode = 0;
649
650 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
651 HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
652 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
653}
654
655static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
656 unsigned long param)
657{
658 __u16 opcode = 0;
659
660 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
661 HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
662 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
663}
664
665static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
666 unsigned long param)
667{
668 __u16 opcode = 0;
669
670 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
671 HCI_OCF_FM_GET_RADIO_TEXT_REQ);
672 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
673}
674
675static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
676 unsigned long param)
677{
678 __u16 opcode = 0;
679
680 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
681 HCI_OCF_FM_GET_AF_LIST_REQ);
682 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
683}
684
685static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
686 unsigned long param)
687{
688 __u16 opcode = 0;
689 struct hci_fm_search_station_req *srch_stations =
690 (struct hci_fm_search_station_req *) param;
691
692 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
693 HCI_OCF_FM_SEARCH_STATIONS);
694 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
695 srch_stations);
696}
697
698static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
699 unsigned long param)
700{
701 __u16 opcode = 0;
702 struct hci_fm_search_rds_station_req *srch_stations =
703 (struct hci_fm_search_rds_station_req *) param;
704
705 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
706 HCI_OCF_FM_SEARCH_RDS_STATIONS);
707 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
708 srch_stations);
709}
710
711static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
712 unsigned long param)
713{
714 __u16 opcode = 0;
715 struct hci_fm_search_station_list_req *srch_list =
716 (struct hci_fm_search_station_list_req *) param;
717
718 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
719 HCI_OCF_FM_SEARCH_STATIONS_LIST);
720 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
721 srch_list);
722}
723
724static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
725 unsigned long param)
726{
727 __u16 opcode = 0;
728
729 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
730 HCI_OCF_FM_CANCEL_SEARCH);
731 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
732}
733
734static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
735 unsigned long param)
736{
737 __u16 opcode = 0;
738
739 __u32 fm_grps_process = param;
740
741 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
742 HCI_OCF_FM_RDS_GRP_PROCESS);
743 return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
744 &fm_grps_process);
745}
746
747static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
748 unsigned long param)
749{
750 __u16 opcode = 0;
751
752 __u32 tune_freq = param;
753
754 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
755 HCI_OCF_FM_TUNE_STATION_REQ);
756 return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
757}
758
759static int hci_def_data_read_req(struct radio_hci_dev *hdev,
760 unsigned long param)
761{
762 __u16 opcode = 0;
763 struct hci_fm_def_data_rd_req *def_data_rd =
764 (struct hci_fm_def_data_rd_req *) param;
765
766 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
767 HCI_OCF_FM_DEFAULT_DATA_READ);
768 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
769 def_data_rd);
770}
771
772static int hci_def_data_write_req(struct radio_hci_dev *hdev,
773 unsigned long param)
774{
775 __u16 opcode = 0;
776 struct hci_fm_def_data_wr_req *def_data_wr =
777 (struct hci_fm_def_data_wr_req *) param;
778
779 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
780 HCI_OCF_FM_DEFAULT_DATA_WRITE);
781 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
782 def_data_wr);
783}
784
785static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
786{
787 __u16 opcode = 0;
788
789 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
790 HCI_OCF_FM_RESET);
791 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
792}
793
794static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
795 unsigned long param)
796{
797 __u16 opcode = 0;
798
799 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
800 HCI_OCF_FM_GET_FEATURE_LIST);
801 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
802}
803
804static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
805 unsigned long param)
806{
807 __u16 opcode = 0;
808
809 __u8 mode = param;
810
811 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
812 HCI_OCF_FM_DO_CALIBRATION);
813 return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
814}
815
816static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
817 unsigned long param)
818{
819 __u16 opcode = 0;
820
821 __u8 reset_counters = param;
822
823 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
824 HCI_OCF_FM_READ_GRP_COUNTERS);
825 return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
826 &reset_counters);
827}
828
829static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
830{
831 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700832 struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700834 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835 HCI_OCF_FM_PEEK_DATA);
836 return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
837 peek_data);
838}
839
840static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
841{
842 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700843 struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844
845 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
846 HCI_OCF_FM_POKE_DATA);
847 return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
848 poke_data);
849}
850
851static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
852 unsigned long param)
853{
854 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700855 struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700857 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858 HCI_OCF_FM_SSBI_PEEK_REG);
859 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
860 ssbi_peek);
861}
862
863static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
864 unsigned long param)
865{
866 __u16 opcode = 0;
867 struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
868
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700869 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870 HCI_OCF_FM_SSBI_POKE_REG);
871 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
872 ssbi_poke);
873}
874
875static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
876 unsigned long param)
877{
878 __u16 opcode = 0;
879
880 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
881 HCI_OCF_FM_STATION_DBG_PARAM);
882 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
883}
884
885static int radio_hci_err(__u16 code)
886{
887 switch (code) {
888 case 0:
889 return 0;
890 case 0x01:
891 return -EBADRQC;
892 case 0x02:
893 return -ENOTCONN;
894 case 0x03:
895 return -EIO;
896 case 0x07:
897 return -ENOMEM;
898 case 0x0c:
899 return -EBUSY;
900 case 0x11:
901 return -EOPNOTSUPP;
902 case 0x12:
903 return -EINVAL;
904 default:
905 return -ENOSYS;
906 }
907}
908
909static int __radio_hci_request(struct radio_hci_dev *hdev,
910 int (*req)(struct radio_hci_dev *hdev,
911 unsigned long param),
912 unsigned long param, __u32 timeout)
913{
914 int err = 0;
915
916 DECLARE_WAITQUEUE(wait, current);
917
918 hdev->req_status = HCI_REQ_PEND;
919
920 add_wait_queue(&hdev->req_wait_q, &wait);
921 set_current_state(TASK_INTERRUPTIBLE);
922
923 err = req(hdev, param);
924
925 schedule_timeout(timeout);
926
927 remove_wait_queue(&hdev->req_wait_q, &wait);
928
929 if (signal_pending(current))
930 return -EINTR;
931
932 switch (hdev->req_status) {
933 case HCI_REQ_DONE:
934 case HCI_REQ_STATUS:
935 err = radio_hci_err(hdev->req_result);
936 break;
937
938 case HCI_REQ_CANCELED:
939 err = -hdev->req_result;
940 break;
941
942 default:
943 err = -ETIMEDOUT;
944 break;
945 }
946
947 hdev->req_status = hdev->req_result = 0;
948
949 return err;
950}
951
952static inline int radio_hci_request(struct radio_hci_dev *hdev,
953 int (*req)(struct
954 radio_hci_dev * hdev, unsigned long param),
955 unsigned long param, __u32 timeout)
956{
957 int ret = 0;
958
959 ret = __radio_hci_request(hdev, req, param, timeout);
960
961 return ret;
962}
963
964static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
965 struct radio_hci_dev *hdev)
966{
967 int ret = 0;
968 struct hci_fm_recv_conf_req *set_recv_conf = arg;
969
970 ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
971 long)set_recv_conf, RADIO_HCI_TIMEOUT);
972
973 return ret;
974}
975
976static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
977{
978 int ret = 0;
979 __u32 tune_freq = *arg;
980
981 ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
982 RADIO_HCI_TIMEOUT);
983
984 return ret;
985}
986
987static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
988 struct radio_hci_dev *hdev)
989{
990 int ret = 0;
991 struct hci_fm_mute_mode_req *set_mute_conf = arg;
992
993 ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
994 long)set_mute_conf, RADIO_HCI_TIMEOUT);
995
996 return ret;
997}
998
999static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
1000 struct radio_hci_dev *hdev)
1001{
1002 int ret = 0;
1003 struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
1004
1005 ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
1006 long)set_stereo_conf, RADIO_HCI_TIMEOUT);
1007
1008 return ret;
1009}
1010
1011static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
1012{
1013 int ret = 0;
1014 __u8 antenna = *arg;
1015
1016 ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
1017 RADIO_HCI_TIMEOUT);
1018
1019 return ret;
1020}
1021
1022static int hci_fm_set_signal_threshold(__u8 *arg,
1023 struct radio_hci_dev *hdev)
1024{
1025 int ret = 0;
1026 __u8 sig_threshold = *arg;
1027
1028 ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
1029 sig_threshold, RADIO_HCI_TIMEOUT);
1030
1031 return ret;
1032}
1033
1034static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
1035 struct radio_hci_dev *hdev)
1036{
1037 int ret = 0;
1038 struct hci_fm_search_station_req *srch_stations = arg;
1039
1040 ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
1041 long)srch_stations, RADIO_HCI_TIMEOUT);
1042
1043 return ret;
1044}
1045
1046static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
1047 struct radio_hci_dev *hdev)
1048{
1049 int ret = 0;
1050 struct hci_fm_search_rds_station_req *srch_stations = arg;
1051
1052 ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
1053 long)srch_stations, RADIO_HCI_TIMEOUT);
1054
1055 return ret;
1056}
1057
1058static int hci_fm_search_station_list
1059 (struct hci_fm_search_station_list_req *arg,
1060 struct radio_hci_dev *hdev)
1061{
1062 int ret = 0;
1063 struct hci_fm_search_station_list_req *srch_list = arg;
1064
1065 ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
1066 long)srch_list, RADIO_HCI_TIMEOUT);
1067
1068 return ret;
1069}
1070
1071static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
1072 struct radio_hci_dev *hdev)
1073{
1074 return 0;
1075}
1076
1077static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
1078{
1079 int ret = 0;
1080 __u32 fm_grps_process = *arg;
1081
1082 ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
1083 fm_grps_process, RADIO_HCI_TIMEOUT);
1084
1085 return ret;
1086}
1087
1088int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
1089 struct radio_hci_dev *hdev)
1090{
1091 int ret = 0;
1092 struct hci_fm_def_data_rd_req *def_data_rd = arg;
1093
1094 ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
1095 long)def_data_rd, RADIO_HCI_TIMEOUT);
1096
1097 return ret;
1098}
1099
1100int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
1101 struct radio_hci_dev *hdev)
1102{
1103 int ret = 0;
1104 struct hci_fm_def_data_wr_req *def_data_wr = arg;
1105
1106 ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
1107 long)def_data_wr, RADIO_HCI_TIMEOUT);
1108
1109 return ret;
1110}
1111
1112int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
1113{
1114 int ret = 0;
1115 __u8 mode = *arg;
1116
1117 ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
1118 RADIO_HCI_TIMEOUT);
1119
1120 return ret;
1121}
1122
1123int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
1124{
1125 int ret = 0;
1126 __u8 reset_counters = *arg;
1127
1128 ret = radio_hci_request(hdev, hci_read_grp_counters_req,
1129 reset_counters, RADIO_HCI_TIMEOUT);
1130
1131 return ret;
1132}
1133
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001134static int hci_peek_data(struct hci_fm_riva_data *arg,
1135 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136{
1137 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001138 struct hci_fm_riva_data *peek_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139
1140 ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
1141 long)peek_data, RADIO_HCI_TIMEOUT);
1142
1143 return ret;
1144}
1145
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001146static int hci_poke_data(struct hci_fm_riva_poke *arg,
1147 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148{
1149 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001150 struct hci_fm_riva_poke *poke_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151
1152 ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
1153 long)poke_data, RADIO_HCI_TIMEOUT);
1154
1155 return ret;
1156}
1157
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001158static int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *arg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 struct radio_hci_dev *hdev)
1160{
1161 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001162 struct hci_fm_ssbi_peek *ssbi_peek_reg = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001163
1164 ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
1165 long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
1166
1167 return ret;
1168}
1169
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001170static int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg,
1171 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172{
1173 int ret = 0;
1174 struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
1175
1176 ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
1177 long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
1178
1179 return ret;
1180}
1181
1182static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1183{
1184 int ret = 0;
1185 unsigned long arg = 0;
1186
1187 switch (cmd) {
1188 case HCI_FM_ENABLE_RECV_CMD:
1189 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1190 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1191 break;
1192
1193 case HCI_FM_DISABLE_RECV_CMD:
1194 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1195 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1196 break;
1197
1198 case HCI_FM_GET_RECV_CONF_CMD:
1199 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1200 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1201 break;
1202
1203 case HCI_FM_GET_STATION_PARAM_CMD:
1204 ret = radio_hci_request(hdev,
1205 hci_fm_get_station_param_req, arg,
1206 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1207 break;
1208
1209 case HCI_FM_GET_SIGNAL_TH_CMD:
1210 ret = radio_hci_request(hdev,
1211 hci_fm_get_sig_threshold_req, arg,
1212 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1213 break;
1214
1215 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1216 ret = radio_hci_request(hdev,
1217 hci_fm_get_program_service_req, arg,
1218 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1219 break;
1220
1221 case HCI_FM_GET_RADIO_TEXT_CMD:
1222 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1223 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1224 break;
1225
1226 case HCI_FM_GET_AF_LIST_CMD:
1227 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1228 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1229 break;
1230
1231 case HCI_FM_CANCEL_SEARCH_CMD:
1232 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1233 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1234 break;
1235
1236 case HCI_FM_RESET_CMD:
1237 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1238 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1239 break;
1240
1241 case HCI_FM_GET_FEATURES_CMD:
1242 ret = radio_hci_request(hdev,
1243 hci_fm_get_feature_lists_req, arg,
1244 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1245 break;
1246
1247 case HCI_FM_STATION_DBG_PARAM_CMD:
1248 ret = radio_hci_request(hdev,
1249 hci_fm_get_station_dbg_param_req, arg,
1250 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1251 break;
1252
1253 default:
1254 ret = -EINVAL;
1255 break;
1256 }
1257
1258 return ret;
1259}
1260
1261static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1262{
1263 hdev->req_result = result;
1264 hdev->req_status = HCI_REQ_DONE;
1265 wake_up_interruptible(&hdev->req_wait_q);
1266}
1267
1268static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1269{
1270 hdev->req_result = result;
1271 hdev->req_status = HCI_REQ_STATUS;
1272 wake_up_interruptible(&hdev->req_wait_q);
1273}
1274
1275static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1276{
1277 __u8 status = *((__u8 *) skb->data);
1278
1279 if (status)
1280 return;
1281
1282 radio_hci_req_complete(hdev, status);
1283}
1284
1285static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1286 struct sk_buff *skb)
1287{
1288 __u8 status = *((__u8 *) skb->data);
1289 struct iris_device *radio = video_get_drvdata(video_get_dev());
1290
1291 if (status)
1292 return;
1293
1294 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1295
1296 radio_hci_req_complete(hdev, status);
1297}
1298
1299static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1300{
1301 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1302 struct iris_device *radio = video_get_drvdata(video_get_dev());
1303
1304 if (rsp->status)
1305 return;
1306
1307 radio->recv_conf = rsp->recv_conf_rsp;
1308 radio_hci_req_complete(hdev, rsp->status);
1309}
1310
1311static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1312 struct sk_buff *skb)
1313{
1314 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1315 struct iris_device *radio = video_get_drvdata(video_get_dev());
1316
1317 if (rsp->status)
1318 return;
1319
1320 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1321
1322 radio_hci_req_complete(hdev, rsp->status);
1323}
1324
1325static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1326 struct sk_buff *skb)
1327{
1328 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1329 struct iris_device *radio = video_get_drvdata(video_get_dev());
1330 struct v4l2_control *v4l_ctl = radio->g_ctl;
1331
1332 if (rsp->status)
1333 return;
1334
1335 v4l_ctl->value = rsp->sig_threshold;
1336
1337 radio_hci_req_complete(hdev, rsp->status);
1338}
1339
1340static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1341{
1342 struct iris_device *radio = video_get_drvdata(video_get_dev());
1343 struct hci_fm_station_rsp *rsp = (void *)skb->data;
1344 radio->fm_st_rsp = *(rsp);
1345
1346 /* Tune is always succesful */
1347 radio_hci_req_complete(hdev, 0);
1348}
1349
1350static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1351{
1352 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1353
1354 if (rsp->status)
1355 return;
1356
1357 radio_hci_req_complete(hdev, rsp->status);
1358}
1359
1360static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1361{
1362 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1363
1364 if (rsp->status)
1365 return;
1366
1367 radio_hci_req_complete(hdev, rsp->status);
1368}
1369
1370static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1371{
1372 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1373
1374 if (rsp->status)
1375 return;
1376
1377 radio_hci_req_complete(hdev, rsp->status);
1378}
1379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1381 struct sk_buff *skb)
1382{
1383 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1384 struct iris_device *radio = video_get_drvdata(video_get_dev());
1385 struct v4l2_capability *v4l_cap = radio->g_cap;
1386
1387 if (rsp->status)
1388 return;
1389 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1390 (rsp->feature_mask & 0x000001);
1391
1392 radio_hci_req_complete(hdev, rsp->status);
1393}
1394
1395static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1396 struct sk_buff *skb)
1397{
1398 struct iris_device *radio = video_get_drvdata(video_get_dev());
1399 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
1400 radio->st_dbg_param = *(rsp);
1401
1402 if (radio->st_dbg_param.status)
1403 return;
1404
1405 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1406}
1407
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001408static void iris_q_evt_data(struct iris_device *radio,
1409 char *data, int len, int event)
1410{
1411 struct kfifo *data_b = &radio->data_buf[event];
1412 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1413 wake_up_interruptible(&radio->event_queue);
1414}
1415
1416static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1417 struct sk_buff *skb)
1418{
1419 struct iris_device *radio = video_get_drvdata(video_get_dev());
1420 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1421 int len;
1422 char *data;
1423
1424 if (rsp->status)
1425 return;
1426 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1427 data = kmalloc(len, GFP_ATOMIC);
1428
1429 if (!data) {
1430 FMDERR("Memory allocation failed");
1431 return;
1432 }
1433
1434 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1435 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
1436 radio_hci_req_complete(hdev, rsp->status);
1437
1438
1439}
1440static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1441 struct sk_buff *skb)
1442{
1443 struct iris_device *radio = video_get_drvdata(video_get_dev());
1444 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1445 char *data;
1446
1447 if (rsp->status)
1448 return;
1449 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1450 if (!data) {
1451 FMDERR("Memory allocation failed");
1452 return;
1453 }
1454
1455 data[0] = skb->data[PEEK_DATA_OFSET];
1456 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
1457 radio_hci_req_complete(hdev, rsp->status);
1458 kfree(data);
1459}
1460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
1462 struct sk_buff *skb)
1463{
1464 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
1465 __u16 opcode;
1466
1467 skb_pull(skb, sizeof(*cmd_compl_ev));
1468
1469 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
1470
1471 switch (opcode) {
1472 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
1473 hci_cc_fm_enable_rsp(hdev, skb);
1474 break;
1475 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
1476 hci_cc_conf_rsp(hdev, skb);
1477 break;
1478
1479 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
1480 hci_cc_fm_disable_rsp(hdev, skb);
1481 break;
1482
1483 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
1484 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
1485 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
1486 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
1487 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
1488 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
1489 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
1490 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
1491 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
1492 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
1493 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
1494 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001495 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001496 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
1497 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001498 hci_cc_rsp(hdev, skb);
1499 break;
1500
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001501 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
1502 hci_cc_ssbi_peek_rsp(hdev, skb);
1503 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
1505 hci_cc_sig_threshold_rsp(hdev, skb);
1506 break;
1507
1508 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
1509 hci_cc_station_rsp(hdev, skb);
1510 break;
1511
1512 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
1513 hci_cc_prg_srv_rsp(hdev, skb);
1514 break;
1515
1516 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
1517 hci_cc_rd_txt_rsp(hdev, skb);
1518 break;
1519
1520 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
1521 hci_cc_af_list_rsp(hdev, skb);
1522 break;
1523
1524 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
1525 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001526 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 break;
1528
1529 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
1530 hci_cc_feature_list_rsp(hdev, skb);
1531 break;
1532
1533 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
1534 hci_cc_dbg_param_rsp(hdev, skb);
1535 break;
1536
1537 default:
1538 FMDERR("%s opcode 0x%x", hdev->name, opcode);
1539 break;
1540 }
1541
1542}
1543
1544static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
1545 struct sk_buff *skb)
1546{
1547 struct hci_ev_cmd_status *ev = (void *) skb->data;
1548 radio_hci_status_complete(hdev, ev->status);
1549}
1550
1551static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
1552 struct sk_buff *skb)
1553{
1554 int i;
1555 int len;
1556
1557 struct iris_device *radio = video_get_drvdata(video_get_dev());
1558
1559 len = sizeof(struct hci_fm_station_rsp);
1560
1561 memcpy(&radio->fm_st_rsp.station_rsp, skb_pull(skb, len), len);
1562
1563 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
1564
1565 for (i = 0; i < IRIS_BUF_MAX; i++) {
1566 if (i >= IRIS_BUF_RT_RDS)
1567 kfifo_reset(&radio->data_buf[i]);
1568 }
1569
1570 if (radio->fm_st_rsp.station_rsp.rssi)
1571 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
1572 else
1573 iris_q_event(radio, IRIS_EVT_BELOW_TH);
1574
1575 if (radio->fm_st_rsp.station_rsp.stereo_prg)
1576 iris_q_event(radio, IRIS_EVT_STEREO);
1577
1578 if (radio->fm_st_rsp.station_rsp.mute_mode)
1579 iris_q_event(radio, IRIS_EVT_MONO);
1580
1581 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
1582 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
1583 else
1584 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
1585}
1586
1587static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
1588 struct sk_buff *skb)
1589{
1590 struct iris_device *radio = video_get_drvdata(video_get_dev());
1591 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
1592}
1593
1594static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
1595 struct sk_buff *skb)
1596{
1597 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001598 struct hci_ev_srch_list_compl *ev ;
1599 int cnt;
1600 int stn_num;
1601 int rel_freq;
1602 int abs_freq;
1603 int len;
1604
1605 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1606 if (!ev) {
1607 FMDERR("Memory allocation failed");
1608 return ;
1609 }
1610
1611 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
1612 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
1613
1614 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
1615 (cnt < len) && (stn_num < ev->num_stations_found);
1616 cnt += PARAMS_PER_STATION, stn_num++) {
1617 abs_freq = *((int *)&skb->data[cnt]);
1618 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
1619 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
1620
1621 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
1622 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
1623 }
1624
1625 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
1626 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
1627 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
1628 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629}
1630
1631static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
1632 struct sk_buff *skb)
1633{
1634 struct iris_device *radio = video_get_drvdata(video_get_dev());
1635 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
1636}
1637
1638static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
1639 struct sk_buff *skb)
1640{
1641 struct iris_device *radio = video_get_drvdata(video_get_dev());
1642 __u8 st_status = *((__u8 *) skb->data);
1643 if (st_status)
1644 iris_q_event(radio, IRIS_EVT_STEREO);
1645 else
1646 iris_q_event(radio, IRIS_EVT_MONO);
1647}
1648
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001649
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001650static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
1651 struct sk_buff *skb)
1652{
1653 struct iris_device *radio = video_get_drvdata(video_get_dev());
1654 int len;
1655 char *data;
1656
1657 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
1658 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
1659 data = kmalloc(len, GFP_ATOMIC);
1660 if (!data) {
1661 FMDERR("Failed to allocate memory");
1662 return;
1663 }
1664
1665 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
1666 data[1] = skb->data[RDS_PTYPE];
1667 data[2] = skb->data[RDS_PID_LOWER];
1668 data[3] = skb->data[RDS_PID_HIGHER];
1669 data[4] = 0;
1670
1671 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
1672
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001673 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001674
1675 kfree(data);
1676}
1677
1678
1679static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
1680 struct sk_buff *skb)
1681{
1682 struct iris_device *radio = video_get_drvdata(video_get_dev());
1683 int len = 0;
1684 char *data;
1685
1686 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
1687
1688 while (skb->data[len+RDS_OFFSET] != 0x0d)
1689 len++;
1690 len++;
1691
1692 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
1693 if (!data) {
1694 FMDERR("Failed to allocate memory");
1695 return;
1696 }
1697
1698 data[0] = len;
1699 data[1] = skb->data[RDS_PTYPE];
1700 data[2] = skb->data[RDS_PID_LOWER];
1701 data[3] = skb->data[RDS_PID_HIGHER];
1702 data[4] = 0;
1703
1704 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
1705 data[len+RDS_OFFSET] = 0x00;
1706
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001707 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001708
1709 kfree(data);
1710}
1711
1712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001713void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
1714{
1715 struct radio_hci_event_hdr *hdr = (void *) skb->data;
1716 __u8 event = hdr->evt;
1717
1718 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
1719
1720 switch (event) {
1721 case HCI_EV_TUNE_STATUS:
1722 hci_ev_tune_status(hdev, skb);
1723 break;
1724 case HCI_EV_SEARCH_PROGRESS:
1725 case HCI_EV_SEARCH_RDS_PROGRESS:
1726 case HCI_EV_SEARCH_LIST_PROGRESS:
1727 hci_ev_search_next(hdev, skb);
1728 break;
1729 case HCI_EV_STEREO_STATUS:
1730 hci_ev_stereo_status(hdev, skb);
1731 break;
1732 case HCI_EV_RDS_LOCK_STATUS:
1733 case HCI_EV_SERVICE_AVAILABLE:
1734 case HCI_EV_RDS_RX_DATA:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001735 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001737 hci_ev_program_service(hdev, skb);
1738 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07001740 hci_ev_radio_text(hdev, skb);
1741 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742 case HCI_EV_FM_AF_LIST:
1743 case HCI_EV_TX_RDS_GRP_COMPL:
1744 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
1745 break;
1746
1747 case HCI_EV_CMD_COMPLETE:
1748 hci_cmd_complete_event(hdev, skb);
1749 break;
1750
1751 case HCI_EV_CMD_STATUS:
1752 hci_cmd_status_event(hdev, skb);
1753 break;
1754
1755 case HCI_EV_SEARCH_COMPLETE:
1756 case HCI_EV_SEARCH_RDS_COMPLETE:
1757 hci_ev_search_compl(hdev, skb);
1758 break;
1759
1760 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07001761 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 break;
1763
1764 default:
1765 break;
1766 }
1767}
1768
1769/*
1770 * fops/IOCTL helper functions
1771 */
1772
1773static int iris_search(struct iris_device *radio, int on, int dir)
1774{
1775 int retval = 0;
1776 enum search_t srch = radio->g_search_mode & SRCH_MODE;
1777
1778 if (on) {
1779 switch (srch) {
1780 case SCAN_FOR_STRONG:
1781 case SCAN_FOR_WEAK:
1782 radio->srch_st_list.srch_list_dir = dir;
1783 radio->srch_st_list.srch_list_mode = srch;
1784 radio->srch_st_list.srch_list_max = 0;
1785 retval = hci_fm_search_station_list(
1786 &radio->srch_st_list, radio->fm_hdev);
1787 break;
1788 case RDS_SEEK_PTY:
1789 case RDS_SCAN_PTY:
1790 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07001791 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 radio->srch_rds.srch_station.srch_mode = srch;
1793 radio->srch_rds.srch_station.srch_dir = dir;
1794 radio->srch_rds.srch_station.scan_time =
1795 radio->g_scan_time;
1796 retval = hci_fm_search_rds_stations(&radio->srch_rds,
1797 radio->fm_hdev);
1798 break;
1799 default:
1800 radio->srch_st.srch_mode = srch;
1801 radio->srch_st.scan_time = radio->g_scan_time;
1802 radio->srch_st.srch_dir = dir;
1803 retval = hci_fm_search_stations(
1804 &radio->srch_st, radio->fm_hdev);
1805 break;
1806 }
1807
1808 } else {
1809 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
1810 }
1811
1812 return retval;
1813}
1814
1815static int iris_set_region(struct iris_device *radio, int req_region)
1816{
1817 int retval;
1818 radio->region = req_region;
1819
1820 switch (radio->region) {
1821 case IRIS_REGION_US:
1822 {
1823 radio->recv_conf.band_low_limit = 88100;
1824 radio->recv_conf.band_high_limit = 108000;
1825 radio->recv_conf.emphasis = 0;
1826 radio->recv_conf.hlsi = 0;
1827 radio->recv_conf.ch_spacing = 0;
1828 radio->recv_conf.rds_std = 0;
1829 }
1830 break;
1831 case IRIS_REGION_EU:
1832 {
1833 radio->recv_conf.band_low_limit = 88100;
1834 radio->recv_conf.band_high_limit = 108000;
1835 radio->recv_conf.emphasis = 0;
1836 radio->recv_conf.hlsi = 0;
1837 radio->recv_conf.ch_spacing = 0;
1838 radio->recv_conf.rds_std = 0;
1839 }
1840 break;
1841 case IRIS_REGION_JAPAN:
1842 {
1843 radio->recv_conf.band_low_limit = 76000;
1844 radio->recv_conf.band_high_limit = 108000;
1845 radio->recv_conf.emphasis = 0;
1846 radio->recv_conf.hlsi = 0;
1847 radio->recv_conf.ch_spacing = 0;
1848 }
1849 break;
1850 default:
1851 {
1852 radio->recv_conf.emphasis = 0;
1853 radio->recv_conf.hlsi = 0;
1854 radio->recv_conf.ch_spacing = 0;
1855 radio->recv_conf.rds_std = 0;
1856 }
1857 break;
1858 }
1859
1860
1861 retval = hci_set_fm_recv_conf(
1862 &radio->recv_conf,
1863 radio->fm_hdev);
1864
1865 return retval;
1866}
1867
1868static int iris_set_freq(struct iris_device *radio, unsigned int freq)
1869{
1870
1871 int retval;
1872 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
1873 if (retval < 0)
1874 FMDERR("Error while setting the frequency : %d\n", retval);
1875 return retval;
1876}
1877
1878
1879static int iris_vidioc_queryctrl(struct file *file, void *priv,
1880 struct v4l2_queryctrl *qc)
1881{
1882 unsigned char i;
1883 int retval = -EINVAL;
1884
1885 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
1886 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
1887 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
1888 retval = 0;
1889 break;
1890 }
1891 }
1892
1893 return retval;
1894}
1895
1896static int iris_vidioc_g_ctrl(struct file *file, void *priv,
1897 struct v4l2_control *ctrl)
1898{
1899 struct iris_device *radio = video_get_drvdata(video_devdata(file));
1900 int retval = 0;
1901
1902 switch (ctrl->id) {
1903 case V4L2_CID_AUDIO_VOLUME:
1904 break;
1905 case V4L2_CID_AUDIO_MUTE:
1906 ctrl->value = radio->mute_mode.hard_mute;
1907 break;
1908 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
1909 ctrl->value = radio->g_search_mode;
1910 break;
1911 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
1912 ctrl->value = radio->g_scan_time;
1913 break;
1914 case V4L2_CID_PRIVATE_IRIS_SRCHON:
1915 break;
1916 case V4L2_CID_PRIVATE_IRIS_STATE:
1917 break;
1918 case V4L2_CID_PRIVATE_IRIS_IOVERC:
1919 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
1920 if (retval < 0)
1921 return retval;
1922 ctrl->value = radio->st_dbg_param.io_verc;
1923 break;
1924 case V4L2_CID_PRIVATE_IRIS_INTDET:
1925 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
1926 if (retval < 0)
1927 return retval;
1928 ctrl->value = radio->st_dbg_param.in_det_out;
1929 break;
1930 case V4L2_CID_PRIVATE_IRIS_REGION:
1931 ctrl->value = radio->region;
1932 break;
1933 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
1934 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
1935 break;
1936 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
1937 break;
1938 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
1939 break;
1940 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
1941 break;
1942 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
1943 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
1944 radio->fm_hdev);
1945 if (retval < 0)
1946 FMDERR("Error get FM recv conf"
1947 " %d\n", retval);
1948 else
1949 ctrl->value = radio->recv_conf.emphasis;
1950 break;
1951 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
1952 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
1953 radio->fm_hdev);
1954 if (retval < 0)
1955 FMDERR("Error get FM recv conf"
1956 " %d\n", retval);
1957 else
1958 ctrl->value = radio->recv_conf.rds_std;
1959 break;
1960 case V4L2_CID_PRIVATE_IRIS_SPACING:
1961 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
1962 radio->fm_hdev);
1963 if (retval < 0)
1964 FMDERR("Error get FM recv conf"
1965 " %d\n", retval);
1966 else
1967 ctrl->value = radio->recv_conf.ch_spacing;
1968 break;
1969 case V4L2_CID_PRIVATE_IRIS_RDSON:
1970 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
1971 radio->fm_hdev);
1972 if (retval < 0)
1973 FMDERR("Error get FM recv conf"
1974 " %d\n", retval);
1975 else
1976 ctrl->value = radio->recv_conf.rds_std;
1977 break;
1978 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
1979 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
1980 break;
1981 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
1982 break;
1983 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
1984 ctrl->value = radio->rds_grp.rds_buf_size;
1985 break;
1986 case V4L2_CID_PRIVATE_IRIS_PSALL:
1987 ctrl->value = radio->g_rds_grp_proc_ps;
1988 break;
1989 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
1990 break;
1991 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
1992 ctrl->value = radio->g_antenna;
1993 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001994 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
1995 ctrl->value = radio->mute_mode.soft_mute;
1996 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997 default:
1998 retval = -EINVAL;
1999 }
2000 if (retval < 0)
2001 FMDERR("get control failed with %d, id: %d\n",
2002 retval, ctrl->id);
2003 return retval;
2004}
2005
2006static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
2007 struct v4l2_ext_controls *ctrl)
2008{
2009 return -ENOTSUPP;
2010}
2011
2012static int iris_vidioc_s_ctrl(struct file *file, void *priv,
2013 struct v4l2_control *ctrl)
2014{
2015 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2016 int retval = 0;
2017 unsigned int rds_grps_proc = 0;
2018 __u8 temp_val = 0;
2019 radio->recv_conf.emphasis = 0;
2020 radio->recv_conf.ch_spacing = 0;
2021 radio->recv_conf.hlsi = 0;
2022 radio->recv_conf.band_low_limit = 87500;
2023 radio->recv_conf.band_high_limit = 108000;
2024 radio->recv_conf.rds_std = 0;
2025
2026
2027 switch (ctrl->id) {
2028 case V4L2_CID_AUDIO_VOLUME:
2029 break;
2030 case V4L2_CID_AUDIO_MUTE:
2031 radio->mute_mode.hard_mute = ctrl->value;
2032 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
2033 retval = hci_set_fm_mute_mode(
2034 &radio->mute_mode,
2035 radio->fm_hdev);
2036 if (retval < 0)
2037 FMDERR("Error while set FM hard mute"" %d\n",
2038 retval);
2039 break;
2040 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2041 radio->g_search_mode = ctrl->value;
2042 break;
2043 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2044 radio->g_scan_time = ctrl->value;
2045 break;
2046 case V4L2_CID_PRIVATE_IRIS_SRCHON:
2047 iris_search(radio, ctrl->value, SRCH_DIR_UP);
2048 break;
2049 case V4L2_CID_PRIVATE_IRIS_STATE:
2050 if (ctrl->value == FM_RECV) {
2051 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2052 radio->fm_hdev);
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002053 if (retval < 0) {
2054 FMDERR("Error while enabling FM"
2055 " %d\n", retval);
2056 } else {
2057 radio->mute_mode.soft_mute = CTRL_ON;
2058 retval = hci_set_fm_mute_mode(
2059 &radio->mute_mode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002060 radio->fm_hdev);
2061 if (retval < 0)
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07002062 FMDERR("Failed to enable Smute\n");
2063 radio->stereo_mode.stereo_mode = CTRL_OFF;
2064 radio->stereo_mode.sig_blend = CTRL_ON;
2065 radio->stereo_mode.intf_blend = CTRL_ON;
2066 radio->stereo_mode.most_switch = CTRL_ON;
2067 retval = hci_set_fm_stereo_mode(
2068 &radio->stereo_mode,
2069 radio->fm_hdev);
2070 if (retval < 0)
2071 FMDERR("Failed to stereo mode\n");
2072 }
2073 } else if (ctrl->value == FM_OFF) {
2074 retval = hci_cmd(
2075 HCI_FM_DISABLE_RECV_CMD,
2076 radio->fm_hdev);
2077 if (retval < 0) {
2078 FMDERR("Error on disable FM"
2079 " %d\n", retval);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002080 }
2081 }
2082 break;
2083 case V4L2_CID_PRIVATE_IRIS_REGION:
2084 retval = iris_set_region(radio, ctrl->value);
2085 break;
2086 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2087 temp_val = ctrl->value;
2088 retval = hci_fm_set_signal_threshold(
2089 &temp_val,
2090 radio->fm_hdev);
2091 if (retval < 0) {
2092 FMDERR("Error while setting signal threshold\n");
2093 break;
2094 }
2095 break;
2096 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
2097 radio->srch_rds.srch_pty = ctrl->value;
2098 radio->srch_st_list.srch_pty = ctrl->value;
2099 break;
2100 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
2101 radio->srch_rds.srch_pi = ctrl->value;
2102 break;
2103 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
2104 break;
2105 case V4L2_CID_PRIVATE_IRIS_SPACING:
2106 radio->recv_conf.ch_spacing = ctrl->value;
2107 break;
2108 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
2109 radio->recv_conf.emphasis = ctrl->value;
2110 retval =
2111 hci_set_fm_recv_conf(&radio->recv_conf, radio->fm_hdev);
2112 break;
2113 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
2114 radio->recv_conf.rds_std = ctrl->value;
2115 retval =
2116 hci_set_fm_recv_conf(&radio->recv_conf, radio->fm_hdev);
2117 break;
2118 case V4L2_CID_PRIVATE_IRIS_RDSON:
2119 radio->recv_conf.rds_std = ctrl->value;
2120 retval =
2121 hci_set_fm_recv_conf(&radio->recv_conf, radio->fm_hdev);
2122 break;
2123 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2124 radio->rds_grp.rds_grp_enable_mask = ctrl->value;
2125 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
2126 break;
2127 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
2128 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
2129 retval = hci_fm_rds_grps_process(
2130 &rds_grps_proc,
2131 radio->fm_hdev);
2132 break;
2133 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2134 radio->rds_grp.rds_buf_size = ctrl->value;
2135 break;
2136 case V4L2_CID_PRIVATE_IRIS_PSALL:
2137 radio->g_rds_grp_proc_ps = ctrl->value;
2138 break;
2139 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
2140 break;
2141 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2142 temp_val = ctrl->value;
2143 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
2144 break;
2145 case V4L2_CID_RDS_TX_PTY:
2146 break;
2147 case V4L2_CID_RDS_TX_PI:
2148 break;
2149 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
2150 break;
2151 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
2152 break;
2153 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
2154 break;
2155 case V4L2_CID_TUNE_POWER_LEVEL:
2156 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002157 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2158 radio->mute_mode.soft_mute = ctrl->value;
2159 retval = hci_set_fm_mute_mode(
2160 &radio->mute_mode,
2161 radio->fm_hdev);
2162 if (retval < 0)
2163 FMDERR("Error while setting FM soft mute"" %d\n",
2164 retval);
2165 break;
2166 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
2167 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
2168 break;
2169 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
2170 radio->riva_data_req.cmd_params.length = ctrl->value;
2171 break;
2172 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
2173 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
2174 radio->riva_data_req.cmd_params.length);
2175 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
2176 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
2177 break;
2178 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
2179 radio->ssbi_data_accs.start_addr = ctrl->value;
2180 break;
2181 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
2182 radio->ssbi_data_accs.data = ctrl->value;
2183 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
2184 radio->fm_hdev);
2185 break;
2186 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
2187 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
2188 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
2189 radio->fm_hdev);
2190 break;
2191 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
2192 radio->ssbi_peek_reg.start_address = ctrl->value;
2193 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
2194 break;
2195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196 default:
2197 retval = -EINVAL;
2198 }
2199 return retval;
2200}
2201
2202static int iris_vidioc_g_tuner(struct file *file, void *priv,
2203 struct v4l2_tuner *tuner)
2204{
2205 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2206 int retval;
2207 if (tuner->index > 0)
2208 return -EINVAL;
2209
2210 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
2211 if (retval < 0)
2212 return retval;
2213
2214 tuner->type = V4L2_TUNER_RADIO;
2215 tuner->rangelow = radio->recv_conf.band_low_limit * TUNE_PARAM;
2216 tuner->rangehigh = radio->recv_conf.band_high_limit * TUNE_PARAM;
2217 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
2218 tuner->capability = V4L2_TUNER_CAP_LOW;
2219 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
2220 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
2221 tuner->afc = 0;
2222
2223 return 0;
2224}
2225
2226static int iris_vidioc_s_tuner(struct file *file, void *priv,
2227 struct v4l2_tuner *tuner)
2228{
2229 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2230 int retval;
2231 if (tuner->index > 0)
2232 return -EINVAL;
2233
2234 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
2235 radio->recv_conf.band_high_limit = tuner->rangehigh / TUNE_PARAM;
2236 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
2237 radio->stereo_mode.stereo_mode = 0x01;
2238 retval = hci_set_fm_stereo_mode(
2239 &radio->stereo_mode,
2240 radio->fm_hdev);
2241 } else {
2242 radio->stereo_mode.stereo_mode = 0x00;
2243 retval = hci_set_fm_stereo_mode(
2244 &radio->stereo_mode,
2245 radio->fm_hdev);
2246 }
2247 if (retval < 0)
2248 FMDERR(": set tuner failed with %d\n", retval);
2249 return retval;
2250}
2251
2252static int iris_vidioc_g_frequency(struct file *file, void *priv,
2253 struct v4l2_frequency *freq)
2254{
2255 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2256 int retval;
2257
2258 freq->type = V4L2_TUNER_RADIO;
2259 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
2260 if (retval < 0)
2261 FMDERR("get frequency failed %d\n", retval);
2262 else
2263 freq->frequency =
2264 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
2265 return retval;
2266}
2267
2268static int iris_vidioc_s_frequency(struct file *file, void *priv,
2269 struct v4l2_frequency *freq)
2270{
2271 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2272 int retval = -1;
2273 freq->frequency = freq->frequency / TUNE_PARAM;
2274
2275 if (freq->type != V4L2_TUNER_RADIO)
2276 return -EINVAL;
2277
2278 retval = iris_set_freq(radio, freq->frequency);
2279 if (retval < 0)
2280 FMDERR(" set frequency failed with %d\n", retval);
2281 return retval;
2282}
2283
2284static int iris_vidioc_dqbuf(struct file *file, void *priv,
2285 struct v4l2_buffer *buffer)
2286{
2287 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2288 enum iris_buf_t buf_type = buffer->index;
2289 struct kfifo *data_fifo;
2290 unsigned char *buf = (unsigned char *)buffer->m.userptr;
2291 unsigned int len = buffer->length;
2292 if (!access_ok(VERIFY_WRITE, buf, len))
2293 return -EFAULT;
2294 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
2295 data_fifo = &radio->data_buf[buf_type];
2296 if (buf_type == IRIS_BUF_EVENTS)
2297 if (wait_event_interruptible(radio->event_queue,
2298 kfifo_len(data_fifo)) < 0)
2299 return -EINTR;
2300 } else {
2301 FMDERR("invalid buffer type\n");
2302 return -EINVAL;
2303 }
2304 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
2305 &radio->buf_lock[buf_type]);
2306
2307 return 0;
2308}
2309
2310static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
2311 struct v4l2_format *f)
2312{
2313 return 0;
2314
2315}
2316
2317static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
2318 struct v4l2_hw_freq_seek *seek)
2319{
2320 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2321 int dir;
2322 if (seek->seek_upward)
2323 dir = SRCH_DIR_UP;
2324 else
2325 dir = SRCH_DIR_DOWN;
2326 return iris_search(radio, CTRL_ON, dir);
2327}
2328
2329static int iris_vidioc_querycap(struct file *file, void *priv,
2330 struct v4l2_capability *capability)
2331{
2332 struct iris_device *radio;
2333 radio = video_get_drvdata(video_devdata(file));
2334 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
2335 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
2336 radio->g_cap = capability;
2337 return 0;
2338}
2339
2340
2341static const struct v4l2_ioctl_ops iris_ioctl_ops = {
2342 .vidioc_querycap = iris_vidioc_querycap,
2343 .vidioc_queryctrl = iris_vidioc_queryctrl,
2344 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
2345 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
2346 .vidioc_g_tuner = iris_vidioc_g_tuner,
2347 .vidioc_s_tuner = iris_vidioc_s_tuner,
2348 .vidioc_g_frequency = iris_vidioc_g_frequency,
2349 .vidioc_s_frequency = iris_vidioc_s_frequency,
2350 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
2351 .vidioc_dqbuf = iris_vidioc_dqbuf,
2352 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
2353 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
2354};
2355
2356static const struct v4l2_file_operations iris_fops = {
2357 .owner = THIS_MODULE,
2358 .unlocked_ioctl = video_ioctl2,
2359};
2360
2361static struct video_device iris_viddev_template = {
2362 .fops = &iris_fops,
2363 .ioctl_ops = &iris_ioctl_ops,
2364 .name = DRIVER_NAME,
2365 .release = video_device_release,
2366};
2367
2368static struct video_device *video_get_dev(void)
2369{
2370 return priv_videodev;
2371}
2372
2373static int __init iris_probe(struct platform_device *pdev)
2374{
2375 struct iris_device *radio;
2376 int retval;
2377 int radio_nr = -1;
2378 int i;
2379
2380 if (!pdev) {
2381 FMDERR(": pdev is null\n");
2382 return -ENOMEM;
2383 }
2384
2385 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
2386 if (!radio) {
2387 FMDERR(": Could not allocate radio device\n");
2388 return -ENOMEM;
2389 }
2390
2391 radio->dev = &pdev->dev;
2392 platform_set_drvdata(pdev, radio);
2393
2394 radio->videodev = video_device_alloc();
2395 if (!radio->videodev) {
2396 FMDERR(": Could not allocate V4L device\n");
2397 kfree(radio);
2398 return -ENOMEM;
2399 }
2400
2401 memcpy(radio->videodev, &iris_viddev_template,
2402 sizeof(iris_viddev_template));
2403
2404 for (i = 0; i < IRIS_BUF_MAX; i++) {
2405 int kfifo_alloc_rc = 0;
2406 spin_lock_init(&radio->buf_lock[i]);
2407
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002408 if ((i == IRIS_BUF_RAW_RDS) | (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
2410 rds_buf*3, GFP_KERNEL);
2411 else
2412 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
2413 STD_BUF_SIZE, GFP_KERNEL);
2414
2415 if (kfifo_alloc_rc != 0) {
2416 FMDERR("failed allocating buffers %d\n",
2417 kfifo_alloc_rc);
2418 for (; i > -1; i--) {
2419 kfifo_free(&radio->data_buf[i]);
2420 kfree(radio);
2421 return -ENOMEM;
2422 }
2423 }
2424 }
2425
2426 mutex_init(&radio->lock);
2427 init_completion(&radio->sync_xfr_start);
2428 radio->tune_req = 0;
2429 init_waitqueue_head(&radio->event_queue);
2430 init_waitqueue_head(&radio->read_queue);
2431
2432 video_set_drvdata(radio->videodev, radio);
2433
2434 if (NULL == video_get_drvdata(radio->videodev))
2435 FMDERR(": video_get_drvdata failed\n");
2436
2437 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
2438 radio_nr);
2439 if (retval) {
2440 FMDERR(": Could not register video device\n");
2441 video_device_release(radio->videodev);
2442 for (; i > -1; i--)
2443 kfifo_free(&radio->data_buf[i]);
2444 kfree(radio);
2445 return retval;
2446 } else {
2447 priv_videodev = kzalloc(sizeof(struct video_device),
2448 GFP_KERNEL);
2449 memcpy(priv_videodev, radio->videodev,
2450 sizeof(struct video_device));
2451 }
2452 return 0;
2453}
2454
2455
2456static int __devexit iris_remove(struct platform_device *pdev)
2457{
2458 int i;
2459 struct iris_device *radio = platform_get_drvdata(pdev);
2460
2461 video_unregister_device(radio->videodev);
2462
2463 for (i = 0; i < IRIS_BUF_MAX; i++)
2464 kfifo_free(&radio->data_buf[i]);
2465
2466 kfree(radio);
2467
2468 platform_set_drvdata(pdev, NULL);
2469
2470 return 0;
2471}
2472
2473static struct platform_driver iris_driver = {
2474 .driver = {
2475 .owner = THIS_MODULE,
2476 .name = "iris_fm",
2477 },
2478 .remove = __devexit_p(iris_remove),
2479};
2480
2481static int __init iris_radio_init(void)
2482{
2483 return platform_driver_probe(&iris_driver, iris_probe);
2484}
2485module_init(iris_radio_init);
2486
2487static void __exit iris_radio_exit(void)
2488{
2489 platform_driver_unregister(&iris_driver);
2490}
2491module_exit(iris_radio_exit);
2492
2493MODULE_LICENSE("GPL v2");
2494MODULE_AUTHOR(DRIVER_AUTHOR);
2495MODULE_DESCRIPTION(DRIVER_DESC);