kernel - Remove D_KQFILTER flag
[dragonfly.git] / sys / dev / video / cxm / cxm.c
CommitLineData
e9afadfd
SW
1/*
2 * Copyright (c) 2003, 2004, 2005
3 * John Wehle <john@feith.com>. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Wehle.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Conexant MPEG-2 Codec driver. Supports the CX23415 / CX23416
34 * chips that are on the Hauppauge PVR-250 and PVR-350 video
35 * capture cards. Currently only the encoder is supported.
36 *
37 * This driver was written using the invaluable information
38 * compiled by The IvyTV Project (ivtv.sourceforge.net).
39 */
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/conf.h>
44#include <sys/uio.h>
45#include <sys/kernel.h>
46#include <sys/mman.h>
47#include <sys/module.h>
a8fbdc8b 48#include <sys/event.h>
e9afadfd
SW
49#include <sys/proc.h>
50#include <sys/signalvar.h>
51#include <sys/thread2.h>
52#include <sys/vnode.h>
e9afadfd
SW
53#include <sys/resource.h>
54#include <sys/bus.h>
55#include <sys/rman.h>
56
57#include <machine/clock.h>
58
59#include <dev/video/meteor/ioctl_meteor.h>
60#include <dev/video/bktr/ioctl_bt848.h>
61
62#include <bus/pci/pcireg.h>
63#include <bus/pci/pcivar.h>
64
65#include <dev/video/cxm/cxm.h>
66
67#include <bus/iicbus/iiconf.h>
68
69/*
70 * Various supported device vendors/types and their names.
71 */
72static struct cxm_dev cxm_devs[] = {
73 { PCI_VENDOR_ICOMPRESSION, PCI_PRODUCT_ICOMPRESSION_ITVC15,
74 "Conexant iTVC15 MPEG Coder" },
75 { PCI_VENDOR_ICOMPRESSION, PCI_PRODUCT_ICOMPRESSION_ITVC16,
76 "Conexant iTVC16 MPEG Coder" },
77 { 0, 0, NULL }
78};
79
80
81static int cxm_probe(device_t dev);
82static int cxm_attach(device_t dev);
83static int cxm_detach(device_t dev);
84static int cxm_shutdown(device_t dev);
85static void cxm_intr(void *arg);
86
87static void cxm_child_detached(device_t dev, device_t child);
88static int cxm_read_ivar(device_t bus, device_t dev,
89 int index, uintptr_t* val);
90static int cxm_write_ivar(device_t bus, device_t dev,
91 int index, uintptr_t val);
92
93
94static device_method_t cxm_methods[] = {
95 /* Device interface */
96 DEVMETHOD(device_probe, cxm_probe),
97 DEVMETHOD(device_attach, cxm_attach),
98 DEVMETHOD(device_detach, cxm_detach),
99 DEVMETHOD(device_shutdown, cxm_shutdown),
100
101 /* bus interface */
102 DEVMETHOD(bus_child_detached, cxm_child_detached),
103 DEVMETHOD(bus_print_child, bus_generic_print_child),
104 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
105 DEVMETHOD(bus_read_ivar, cxm_read_ivar),
106 DEVMETHOD(bus_write_ivar, cxm_write_ivar),
107
108 { 0, 0 }
109};
110
111static driver_t cxm_driver = {
112 "cxm",
113 cxm_methods,
114 sizeof(struct cxm_softc),
115};
116
117static devclass_t cxm_devclass;
118
119static d_open_t cxm_open;
120static d_close_t cxm_close;
121static d_read_t cxm_read;
122static d_ioctl_t cxm_ioctl;
a8fbdc8b
SG
123static d_kqfilter_t cxm_kqfilter;
124
125static void cxm_filter_detach(struct knote *);
126static int cxm_filter(struct knote *, long);
e9afadfd
SW
127
128#define CDEV_MAJOR 93
129
130static struct dev_ops cxm_ops = {
d4b8aec4 131 { "cxm", CDEV_MAJOR, 0 },
e9afadfd
SW
132 .d_open = cxm_open,
133 .d_close = cxm_close,
134 .d_read = cxm_read,
135 .d_ioctl = cxm_ioctl,
a8fbdc8b 136 .d_kqfilter = cxm_kqfilter
e9afadfd
SW
137};
138
139MODULE_DEPEND(cxm, cxm_iic, 1, 1, 1);
140DRIVER_MODULE(cxm, pci, cxm_driver, cxm_devclass, 0, 0);
141
142
143static struct cxm_codec_audio_format codec_audio_formats[] = {
144 { 44100, 0xb8 }, /* 44.1 Khz, MPEG-1 Layer II, 224 kb/s */
145 { 48000, 0xe9 } /* 48 Khz, MPEG-1 Layer II, 384 kb/s */
146};
147
148
149/*
150 * Various profiles.
151 */
152static struct cxm_codec_profile vcd_ntsc_profile = {
153 "MPEG-1 VideoCD NTSC video and MPEG audio",
154 CXM_FW_STREAM_TYPE_VCD,
155 30,
156 352, 240, 480,
157 { 10, 12, 21 },
158 12,
159 0,
160 { 1, 1150000, 0 },
161 { 1, 15, 3},
162 /*
163 * Spatial filter = Manual, Temporal filter = Manual
164 * Median filter = Horizontal / Vertical
165 * Spatial filter value = 1, Temporal filter value = 4
166 */
167 { 0, 3, 1, 4 },
168 44100
169};
170
171static struct cxm_codec_profile vcd_pal_profile = {
172 "MPEG-1 VideoCD PAL video and MPEG audio",
173 CXM_FW_STREAM_TYPE_VCD,
174 25,
175 352, 288, 576,
176 { 6, 17, 22 },
177 8,
178 0,
179 { 1, 1150000, 0 },
180 { 1, 12, 3},
181 /*
182 * Spatial filter = Manual, Temporal filter = Manual
183 * Median filter = Horizontal / Vertical
184 * Spatial filter value = 1, Temporal filter value = 4
185 */
186 { 0, 3, 1, 4 },
187 44100
188};
189
190static struct cxm_codec_profile svcd_ntsc_profile = {
191 "MPEG-2 SuperVCD NTSC video and MPEG audio",
192 CXM_FW_STREAM_TYPE_SVCD,
193 30,
194 480, 480, 480,
195 { 10, 12, 21 },
196 2,
197 0,
198 /* 2.5 Mb/s peak limit to keep bbdmux followed by mplex -f 4 happy */
199 { 0, 1150000, 2500000 },
200 { 1, 15, 3},
201 /*
202 * Spatial filter = Manual, Temporal filter = Manual
203 * Median filter = Horizontal / Vertical
204 * Spatial filter value = 1, Temporal filter value = 4
205 */
206 { 0, 3, 1, 4 },
207 44100
208};
209
210static struct cxm_codec_profile svcd_pal_profile = {
211 "MPEG-2 SuperVCD PAL video and MPEG audio",
212 CXM_FW_STREAM_TYPE_SVCD,
213 25,
214 480, 576, 576,
215 { 6, 17, 22 },
216 2,
217 0,
218 /* 2.5 Mb/s peak limit to keep bbdmux followed by mplex -f 4 happy */
219 { 0, 1150000, 2500000 },
220 { 1, 12, 3},
221 /*
222 * Spatial filter = Manual, Temporal filter = Manual
223 * Median filter = Horizontal / Vertical
224 * Spatial filter value = 1, Temporal filter value = 4
225 */
226 { 0, 3, 1, 4 },
227 44100
228};
229
230static struct cxm_codec_profile dvd_half_d1_ntsc_profile = {
231 "MPEG-2 DVD NTSC video and MPEG audio",
232 CXM_FW_STREAM_TYPE_DVD,
233 30,
234 352, 480, 480,
235 { 10, 12, 21 },
236 2,
237 0,
238 { 0, 4000000, 4520000 }, /* 4 hours on 8.54 GB media */
239 { 1, 15, 3},
240 /*
241 * Spatial filter = Manual, Temporal filter = Manual
242 * Median filter = Horizontal / Vertical
243 * Spatial filter value = 1, Temporal filter value = 4
244 */
245 { 0, 3, 1, 4 },
246 48000
247};
248
249static struct cxm_codec_profile dvd_half_d1_pal_profile = {
250 "MPEG-2 DVD PAL video and MPEG audio",
251 CXM_FW_STREAM_TYPE_DVD,
252 25,
253 352, 576, 576,
254 { 6, 17, 22 },
255 2,
256 0,
257 { 0, 4000000, 4520000 }, /* 4 hours on 8.54 GB media */
258 { 1, 12, 3},
259 /*
260 * Spatial filter = Manual, Temporal filter = Manual
261 * Median filter = Horizontal / Vertical
262 * Spatial filter value = 1, Temporal filter value = 4
263 */
264 { 0, 3, 1, 4 },
265 48000
266};
267
268static struct cxm_codec_profile dvd_full_d1_ntsc_profile = {
269 "MPEG-2 DVD NTSC video and MPEG audio",
270 CXM_FW_STREAM_TYPE_DVD,
271 30,
272 720, 480, 480,
273 { 10, 12, 21 },
274 2,
275 0,
276 /* 9.52 Mb/s peak limit to keep bbdmux followed by mplex -f 8 happy */
277 { 0, 9000000, 9520000 }, /* 1 hour on 4.7 GB media */
278 { 1, 15, 3},
279 /*
280 * Spatial filter = Manual, Temporal filter = Manual
281 * Median filter = Horizontal / Vertical
282 * Spatial filter value = 1, Temporal filter value = 4
283 */
284 { 0, 3, 1, 4 },
285 48000
286};
287
288static struct cxm_codec_profile dvd_full_d1_pal_profile = {
289 "MPEG-2 DVD PAL video and MPEG audio",
290 CXM_FW_STREAM_TYPE_DVD,
291 25,
292 720, 576, 576,
293 { 6, 17, 22 },
294 2,
295 0,
296 /* 9.52 Mb/s peak limit to keep bbdmux followed by mplex -f 8 happy */
297 { 0, 9000000, 9520000 }, /* 1 hour on 4.7 GB media */
298 { 1, 12, 3},
299 /*
300 * Spatial filter = Manual, Temporal filter = Manual
301 * Median filter = Horizontal / Vertical
302 * Spatial filter value = 1, Temporal filter value = 4
303 */
304 { 0, 3, 1, 4 },
305 48000
306};
307
308
309static const struct cxm_codec_profile
310*codec_profiles[] = {
311 &vcd_ntsc_profile,
312 &vcd_pal_profile,
313 &svcd_ntsc_profile,
314 &svcd_pal_profile,
315 &dvd_half_d1_ntsc_profile,
316 &dvd_half_d1_pal_profile,
317 &dvd_full_d1_ntsc_profile,
318 &dvd_full_d1_pal_profile
319};
320
321
322static unsigned int
323cxm_queue_firmware_command(struct cxm_softc *sc,
324 enum cxm_mailbox_name mbx_name, uint32_t cmd,
325 uint32_t *parameters, unsigned int nparameters)
326{
327 unsigned int i;
328 unsigned int mailbox;
329 uint32_t completed_command;
330 uint32_t flags;
331
332 if (nparameters > CXM_MBX_MAX_PARAMETERS) {
333 device_printf(sc->dev, "too many parameters for mailbox\n");
334 return -1;
335 }
336
337 mailbox = 0;
338
339 switch (mbx_name) {
340 case cxm_dec_mailbox:
341 mailbox = sc->dec_mbx
342 + CXM_MBX_FW_CMD_MAILBOX *sizeof(struct cxm_mailbox);
343 break;
344
345 case cxm_enc_mailbox:
346 mailbox = sc->enc_mbx
347 + CXM_MBX_FW_CMD_MAILBOX *sizeof(struct cxm_mailbox);
348 break;
349
350 default:
351 return -1;
352 }
353
354 crit_enter();
355 for (i = 0; i < CXM_MBX_FW_CMD_MAILBOXES; i++) {
356 flags = CSR_READ_4(sc,
357 mailbox
358 + offsetof(struct cxm_mailbox, flags));
359 if (!(flags & CXM_MBX_FLAG_IN_USE))
360 break;
361
362 /*
363 * Mail boxes containing certain completed commands
364 * for which the results are never needed can be reused.
365 */
366
367 if ((flags & (CXM_MBX_FLAG_DRV_DONE | CXM_MBX_FLAG_FW_DONE))
368 == (CXM_MBX_FLAG_DRV_DONE | CXM_MBX_FLAG_FW_DONE)) {
369 completed_command
370 = CSR_READ_4(sc,
371 mailbox
372 + offsetof(struct cxm_mailbox, command));
373
374 /*
375 * DMA results are always check by reading the
376 * DMA status register ... never by checking
377 * the mailbox after the command has completed.
378 */
379
380 if (completed_command == CXM_FW_CMD_SCHED_DMA_TO_HOST)
381 break;
382 }
383
384 mailbox += sizeof(struct cxm_mailbox);
385 }
386
387 if (i >= CXM_MBX_FW_CMD_MAILBOXES) {
388 crit_exit();
389 return -1;
390 }
391
392 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags),
393 CXM_MBX_FLAG_IN_USE);
394
395 /*
396 * PCI writes may be buffered so force the
397 * write to complete by reading the last
398 * location written.
399 */
400
401 CSR_READ_4(sc, mailbox + offsetof(struct cxm_mailbox, flags));
402
403 crit_exit();
404
405 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, command), cmd);
406 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, timeout),
407 CXM_FW_STD_TIMEOUT);
408
409 for (i = 0; i < nparameters; i++)
410 CSR_WRITE_4(sc,
411 mailbox
412 + offsetof(struct cxm_mailbox, parameters)
413 + i * sizeof(uint32_t),
414 *(parameters + i));
415
416 for (; i < CXM_MBX_MAX_PARAMETERS; i++)
417 CSR_WRITE_4(sc,
418 mailbox
419 + offsetof(struct cxm_mailbox, parameters)
420 + i * sizeof(uint32_t), 0);
421
422 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags),
423 CXM_MBX_FLAG_IN_USE | CXM_MBX_FLAG_DRV_DONE);
424
425 return mailbox;
426}
427
428
429static int
430cxm_firmware_command(struct cxm_softc *sc,
431 enum cxm_mailbox_name mbx_name, uint32_t cmd,
432 uint32_t *parameters, unsigned int nparameters)
433{
434 const char *wmesg;
435 unsigned int *bmp;
436 unsigned int i;
437 unsigned int mailbox;
438 uint32_t flags;
439 uint32_t result;
440
441 bmp = NULL;
442 wmesg = "";
443
444 switch (mbx_name) {
445 case cxm_dec_mailbox:
446 bmp = &sc->dec_mbx;
447 wmesg = "cxmdfw";
448 break;
449
450 case cxm_enc_mailbox:
451 bmp = &sc->enc_mbx;
452 wmesg = "cxmefw";
453 break;
454
455 default:
456 return -1;
457 }
458
459 mailbox = cxm_queue_firmware_command(sc, mbx_name, cmd,
460 parameters, nparameters);
461 if (mailbox == -1) {
462 device_printf(sc->dev, "no free mailboxes\n");
463 return -1;
464 }
465
466 /* Give the firmware a chance to start processing the request */
467 tsleep(bmp, 0, wmesg, hz / 100);
468
469 for (i = 0; i < 100; i++) {
470 flags = CSR_READ_4(sc,
471 mailbox
472 + offsetof(struct cxm_mailbox, flags));
473 if ((flags & CXM_MBX_FLAG_FW_DONE))
474 break;
475
476 /* Wait for 10ms */
477 tsleep(bmp, 0, wmesg, hz / 100);
478 }
479
480 if (i >= 100) {
481 device_printf(sc->dev, "timeout\n");
482 return -1;
483 }
484
485 result = CSR_READ_4(sc,
486 mailbox
487 + offsetof(struct cxm_mailbox, result));
488
489 for (i = 0; i < nparameters; i++)
490 *(parameters + i)
491 = CSR_READ_4(sc,
492 mailbox
493 + offsetof(struct cxm_mailbox, parameters)
494 + i * sizeof(uint32_t));
495
496 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags), 0);
497
498 return result == 0 ? 0 : -1;
499}
500
501
502static int
503cxm_firmware_command_nosleep(struct cxm_softc *sc,
504 enum cxm_mailbox_name mbx_name, uint32_t cmd,
505 uint32_t *parameters, unsigned int nparameters)
506{
507 unsigned int i;
508 unsigned int mailbox;
509 uint32_t flags;
510 uint32_t result;
511
512 for (i = 0; i < 100; i++) {
513 mailbox = cxm_queue_firmware_command(sc, mbx_name, cmd,
514 parameters, nparameters);
515 if (mailbox != -1)
516 break;
517
518 /* Wait for 10ms */
519 DELAY(10000);
520 }
521
522 if (i >= 100) {
523 device_printf(sc->dev, "no free mailboxes\n");
524 return -1;
525 }
526
527 /* Give the firmware a chance to start processing the request */
528 DELAY(10000);
529
530 for (i = 0; i < 100; i++) {
531 flags = CSR_READ_4(sc,
532 mailbox
533 + offsetof(struct cxm_mailbox, flags));
534 if ((flags & CXM_MBX_FLAG_FW_DONE))
535 break;
536
537 /* Wait for 10ms */
538 DELAY(10000);
539 }
540
541 if (i >= 100) {
542 device_printf(sc->dev, "timeout\n");
543 return -1;
544 }
545
546 result = CSR_READ_4(sc,
547 mailbox
548 + offsetof(struct cxm_mailbox, result));
549
550 for (i = 0; i < nparameters; i++)
551 *(parameters + i)
552 = CSR_READ_4(sc,
553 mailbox
554 + offsetof(struct cxm_mailbox, parameters)
555 + i * sizeof(uint32_t));
556
557 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags), 0);
558
559 return result == 0 ? 0 : -1;
560}
561
562
563static int
564cxm_stop_firmware(struct cxm_softc *sc)
565{
566
567 if (cxm_firmware_command_nosleep(sc, cxm_enc_mailbox,
568 CXM_FW_CMD_ENC_HALT_FW, NULL, 0) < 0)
569 return -1;
570
571 if (sc->type == cxm_iTVC15_type
572 && cxm_firmware_command_nosleep(sc, cxm_dec_mailbox,
573 CXM_FW_CMD_DEC_HALT_FW,
574 NULL, 0) < 0)
575 return -1;
576
577 /* Wait for 10ms */
578 DELAY(10000);
579
580 return 0;
581}
582
583
584static void
585cxm_set_irq_mask(struct cxm_softc *sc, uint32_t mask)
586{
587 crit_enter();
588
589 CSR_WRITE_4(sc, CXM_REG_IRQ_MASK, mask);
590
591 /*
592 * PCI writes may be buffered so force the
593 * write to complete by reading the last
594 * location written.
595 */
596
597 CSR_READ_4(sc, CXM_REG_IRQ_MASK);
598
599 sc->irq_mask = mask;
600
601 crit_exit();
602}
603
604
605static void
606cxm_set_irq_status(struct cxm_softc *sc, uint32_t status)
607{
608
609 CSR_WRITE_4(sc, CXM_REG_IRQ_STATUS, status);
610
611 /*
612 * PCI writes may be buffered so force the
613 * write to complete by reading the last
614 * location written.
615 */
616
617 CSR_READ_4(sc, CXM_REG_IRQ_STATUS);
618}
619
620
621static int
622cxm_stop_hardware(struct cxm_softc *sc)
623{
624 if (sc->cxm_iic) {
625 if (cxm_saa7115_mute(sc) < 0)
626 return -1;
627 if (cxm_msp_mute(sc) < 0)
628 return -1;
629 }
630
631 /* Halt the firmware */
632 if (sc->enc_mbx != -1) {
633 if (cxm_stop_firmware(sc) < 0)
634 return -1;
635 }
636
637 /* Mask all interrupts */
638 cxm_set_irq_mask(sc, 0xffffffff);
639
640 /* Stop VDM */
641 CSR_WRITE_4(sc, CXM_REG_VDM, CXM_CMD_VDM_STOP);
642
643 /* Stop AO */
644 CSR_WRITE_4(sc, CXM_REG_AO, CXM_CMD_AO_STOP);
645
646 /* Ping (?) APU */
647 CSR_WRITE_4(sc, CXM_REG_APU, CXM_CMD_APU_PING);
648
649 /* Stop VPU */
650 CSR_WRITE_4(sc, CXM_REG_VPU, sc->type == cxm_iTVC15_type
651 ? CXM_CMD_VPU_STOP15
652 : CXM_CMD_VPU_STOP16);
653
654 /* Reset Hw Blocks */
655 CSR_WRITE_4(sc, CXM_REG_HW_BLOCKS, CXM_CMD_HW_BLOCKS_RST);
656
657 /* Stop SPU */
658 CSR_WRITE_4(sc, CXM_REG_SPU, CXM_CMD_SPU_STOP);
659
660 /* Wait for 10ms */
661 DELAY(10000);
662
663 return 0;
664}
665
666
667static int
668cxm_download_firmware(struct cxm_softc *sc)
669{
670 unsigned int i;
671 const uint32_t *fw;
672
764b28ca
SW
673 /* Check if firmware is compiled in */
674 if (strncmp((const char *)cxm_enc_fw, "NOFW", 4) == 0) {
675 device_printf(sc->dev, "encoder firmware not compiled in\n");
676 return -1;
677 } else if (strncmp((const char *)cxm_dec_fw, "NOFW", 4) == 0) {
678 device_printf(sc->dev, "decoder firmware not compiled in\n");
679 return -1;
680 }
681
e9afadfd
SW
682 /* Download the encoder firmware */
683 fw = (const uint32_t *)cxm_enc_fw;
684 for (i = 0; i < CXM_FW_SIZE; i += sizeof(*fw))
685 CSR_WRITE_4(sc, CXM_MEM_ENC + i, *fw++);
686
687 /* Download the decoder firmware */
688 if (sc->type == cxm_iTVC15_type) {
689 fw = (const uint32_t *)cxm_dec_fw;
690 for (i = 0; i < CXM_FW_SIZE; i += sizeof(*fw))
691 CSR_WRITE_4(sc, CXM_MEM_DEC + i, *fw++);
692 }
693
694 return 0;
695}
696
697
698static int
699cxm_init_hardware(struct cxm_softc *sc)
700{
701 unsigned int i;
702 unsigned int mailbox;
703 uint32_t parameter;
704
705 if (cxm_stop_hardware(sc) < 0)
706 return -1;
707
708 /* Initialize encoder SDRAM pre-charge */
709 CSR_WRITE_4(sc, CXM_REG_ENC_SDRAM_PRECHARGE,
710 CXM_CMD_SDRAM_PRECHARGE_INIT);
711
712 /* Initialize encoder SDRAM refresh to 1us */
713 CSR_WRITE_4(sc, CXM_REG_ENC_SDRAM_REFRESH,
714 CXM_CMD_SDRAM_REFRESH_INIT);
715
716 /* Initialize decoder SDRAM pre-charge */
717 CSR_WRITE_4(sc, CXM_REG_DEC_SDRAM_PRECHARGE,
718 CXM_CMD_SDRAM_PRECHARGE_INIT);
719
720 /* Initialize decoder SDRAM refresh to 1us */
721 CSR_WRITE_4(sc, CXM_REG_DEC_SDRAM_REFRESH,
722 CXM_CMD_SDRAM_REFRESH_INIT);
723
724 /* Wait for 600ms */
725 DELAY(600000);
726
727 if (cxm_download_firmware(sc) < 0)
728 return -1;
729
730 /* Enable SPU */
731 CSR_WRITE_4(sc, CXM_REG_SPU,
732 CSR_READ_4(sc, CXM_REG_SPU) & CXM_MASK_SPU_ENABLE);
733
734 /* Wait for 1 second */
735 DELAY(1000000);
736
737 /* Enable VPU */
738 CSR_WRITE_4(sc, CXM_REG_VPU,
739 CSR_READ_4(sc, CXM_REG_VPU)
740 & (sc->type == cxm_iTVC15_type
741 ? CXM_MASK_VPU_ENABLE15
742 : CXM_MASK_VPU_ENABLE16));
743
744 /* Wait for 1 second */
745 DELAY(1000000);
746
747 /* Locate encoder mailbox */
748 mailbox = CXM_MEM_ENC;
749 for (i = 0; i < CXM_MEM_ENC_SIZE; i += 0x100)
750 if (CSR_READ_4(sc, mailbox + i) == 0x12345678
751 && CSR_READ_4(sc, mailbox + i + 4) == 0x34567812
752 && CSR_READ_4(sc, mailbox + i + 8) == 0x56781234
753 && CSR_READ_4(sc, mailbox + i + 12) == 0x78123456)
754 break;
755
756 if (i >= CXM_MEM_ENC_SIZE)
757 return -1;
758
759 sc->enc_mbx = mailbox + i + 16;
760
761 /* Locate decoder mailbox */
762 if (sc->type == cxm_iTVC15_type) {
763 mailbox = CXM_MEM_DEC;
764 for (i = 0; i < CXM_MEM_DEC_SIZE; i += 0x100)
765 if (CSR_READ_4(sc, mailbox + i) == 0x12345678
766 && CSR_READ_4(sc, mailbox + i + 4) == 0x34567812
767 && CSR_READ_4(sc, mailbox + i + 8) == 0x56781234
768 && CSR_READ_4(sc, mailbox + i + 12) == 0x78123456)
769 break;
770
771 if (i >= CXM_MEM_DEC_SIZE)
772 return -1;
773
774 sc->dec_mbx = mailbox + i + 16;
775 }
776
777 /* Get encoder firmware version */
778 parameter = 0;
779 if (cxm_firmware_command_nosleep(sc, cxm_enc_mailbox,
780 CXM_FW_CMD_ENC_GET_FW_VER,
781 &parameter, 1) < 0)
782 return -1;
783
784 device_printf(sc->dev, "encoder firmware version %#x\n",
785 (unsigned int)parameter);
786
787 /* Get decoder firmware version */
788 if (sc->type == cxm_iTVC15_type) {
789 parameter = 0;
790 if (cxm_firmware_command_nosleep(sc, cxm_dec_mailbox,
791 CXM_FW_CMD_DEC_GET_FW_VER,
792 &parameter, 1) < 0)
793 return -1;
794
795 device_printf(sc->dev, "decoder firmware version %#x\n",
796 (unsigned int)parameter);
797 }
798
799 return 0;
800}
801
802
803static int
804cxm_configure_encoder(struct cxm_softc *sc)
805{
806 int fps;
807 unsigned int i;
808 uint32_t parameters[12];
809 const struct cxm_codec_profile *cpp;
810
811 if (sc->source == cxm_fm_source)
812 switch (cxm_tuner_selected_channel_set(sc)) {
813 case CHNLSET_NABCST:
814 case CHNLSET_CABLEIRC:
815 case CHNLSET_JPNBCST:
816 case CHNLSET_JPNCABLE:
817 fps = 30;
818 break;
819
820 default:
821 fps = 25;
822 break;
823 }
824 else
825 fps = cxm_saa7115_detected_fps(sc);
826
827 if (fps < 0)
828 return -1;
829
830 if (sc->profile->fps != fps) {
831
832 /*
833 * Pick a profile with the correct fps using the
834 * chosen stream type and width to decide between
835 * the VCD, SVCD, or DVD profiles.
836 */
837
838 for (i = 0; i < NUM_ELEMENTS(codec_profiles); i++)
839 if (codec_profiles[i]->fps == fps
840 && codec_profiles[i]->stream_type
841 == sc->profile->stream_type
842 && codec_profiles[i]->width == sc->profile->width)
843 break;
844
845 if (i >= NUM_ELEMENTS(codec_profiles))
846 return -1;
847
848 sc->profile = codec_profiles[i];
849 }
850
851 cpp = sc->profile;
852
853 if (cxm_saa7115_configure(sc,
854 cpp->width, cpp->source_height, fps,
855 cpp->audio_sample_rate) < 0)
856 return -1;
857
858 /* assign dma block len */
859 parameters[0] = 1; /* Transfer block size = 1 */
860 parameters[1] = 1; /* Units = 1 (frames) */
861 if (cxm_firmware_command(sc, cxm_enc_mailbox,
862 CXM_FW_CMD_ASSIGN_DMA_BLOCKLEN,
863 parameters, 2) != 0)
864 return -1;
865
866
867 /* assign program index info */
868 parameters[0] = 0; /* Picture mask = 0 (don't generate index) */
869 parameters[1] = 0; /* Num_req = 0 */
870 if (cxm_firmware_command(sc, cxm_enc_mailbox,
871 CXM_FW_CMD_ASSIGN_PGM_INDEX_INFO,
872 parameters, 2) != 0)
873 return -1;
874
875 /* assign stream type */
876 parameters[0] = cpp->stream_type;
877 if (cxm_firmware_command(sc, cxm_enc_mailbox,
878 CXM_FW_CMD_ASSIGN_STREAM_TYPE,
879 parameters, 1) != 0)
880 return -1;
881
882 /* assign output port */
883 parameters[0] = 0; /* 0 (Memory) */
884 if (cxm_firmware_command(sc, cxm_enc_mailbox,
885 CXM_FW_CMD_ASSIGN_OUTPUT_PORT,
886 parameters, 1) != 0)
887 return -1;
888
889 /* assign framerate */
890 parameters[0] = cpp->fps == 30 ? 0 : 1;
891 if (cxm_firmware_command(sc, cxm_enc_mailbox,
892 CXM_FW_CMD_ASSIGN_FRAME_RATE,
893 parameters, 1) != 0)
894 return -1;
895
896 /* assign frame size */
897 parameters[0] = cpp->height;
898 parameters[1] = cpp->width;
899 if (cxm_firmware_command(sc, cxm_enc_mailbox,
900 CXM_FW_CMD_ASSIGN_FRAME_SIZE,
901 parameters, 2) != 0)
902 return -1;
903
904 /* assign aspect ratio */
905 parameters[0] = cpp->aspect;
906 if (cxm_firmware_command(sc, cxm_enc_mailbox,
907 CXM_FW_CMD_ASSIGN_ASPECT_RATIO,
908 parameters, 1) != 0)
909 return -1;
910
911 /* assign bitrates */
912 parameters[0] = cpp->bitrate.mode;
913 parameters[1] = cpp->bitrate.average;
914 parameters[2] = cpp->bitrate.peak / 400;
915 if (cxm_firmware_command(sc, cxm_enc_mailbox,
916 CXM_FW_CMD_ASSIGN_BITRATES,
917 parameters, 3) != 0)
918 return -1;
919
920 /* assign gop closure */
921 parameters[0] = cpp->gop.closure;
922 if (cxm_firmware_command(sc, cxm_enc_mailbox,
923 CXM_FW_CMD_ASSIGN_GOP_CLOSURE,
924 parameters, 1) != 0)
925 return -1;
926
927 /* assign gop properties */
928 parameters[0] = cpp->gop.frames;
929 parameters[1] = cpp->gop.bframes;
930 if (cxm_firmware_command(sc, cxm_enc_mailbox,
931 CXM_FW_CMD_ASSIGN_GOP_PROPERTIES,
932 parameters, 2) != 0)
933 return -1;
934
935 /* assign 3 2 pulldown */
936 parameters[0] = cpp->pulldown;
937 if (cxm_firmware_command(sc, cxm_enc_mailbox,
938 CXM_FW_CMD_ASSIGN_3_2_PULLDOWN,
939 parameters, 1) != 0)
940 return -1;
941
942 /* assign dnr filter mode */
943 parameters[0] = cpp->dnr.mode;
944 parameters[1] = cpp->dnr.type;
945 if (cxm_firmware_command(sc, cxm_enc_mailbox,
946 CXM_FW_CMD_ASSIGN_DNR_FILTER_MODE,
947 parameters, 2) != 0)
948 return -1;
949
950 /* assign dnr filter props */
951 parameters[0] = cpp->dnr.spatial;
952 parameters[1] = cpp->dnr.temporal;
953 if (cxm_firmware_command(sc, cxm_enc_mailbox,
954 CXM_FW_CMD_ASSIGN_DNR_FILTER_PROPERTIES,
955 parameters, 2) != 0)
956 return -1;
957
958 /*
959 * assign audio properties
960 */
961
962 for (i = 0; i < NUM_ELEMENTS(codec_audio_formats); i++)
963 if (codec_audio_formats[i].sample_rate
964 == cpp->audio_sample_rate)
965 break;
966
967 if (i >= NUM_ELEMENTS(codec_audio_formats))
968 return -1;
969
970 parameters[0] = codec_audio_formats[i].format;
971 if (cxm_firmware_command(sc, cxm_enc_mailbox,
972 CXM_FW_CMD_ASSIGN_AUDIO_PROPERTIES,
973 parameters, 1) != 0)
974 return -1;
975
976 /* assign coring levels */
977 parameters[0] = 0; /* luma_h */
978 parameters[1] = 255; /* luma_l */
979 parameters[2] = 0; /* chroma_h */
980 parameters[3] = 255; /* chroma_l */
981 if (cxm_firmware_command(sc, cxm_enc_mailbox,
982 CXM_FW_CMD_ASSIGN_CORING_LEVELS,
983 parameters, 4) != 0)
984 return -1;
985
986 /* assign spatial filter type */
987 parameters[0] = 3; /* Luminance filter = 3 (2D H/V Separable) */
988 parameters[1] = 1; /* Chrominance filter = 1 (1D Horizontal) */
989 if (cxm_firmware_command(sc, cxm_enc_mailbox,
990 CXM_FW_CMD_ASSIGN_SPATIAL_FILTER_TYPE,
991 parameters, 2) != 0)
992 return -1;
993
994 /* assign frame drop rate */
995 parameters[0] = 0;
996 if (cxm_firmware_command(sc, cxm_enc_mailbox,
997 CXM_FW_CMD_ASSIGN_FRAME_DROP_RATE,
998 parameters, 1) != 0)
999 return -1;
1000
1001 /* assign placeholder */
1002 parameters[0] = 0; /* type = 0 (Extension / UserData) */
1003 parameters[1] = 0; /* period */
1004 parameters[2] = 0; /* size_t */
1005 parameters[3] = 0; /* arg0 */
1006 parameters[4] = 0; /* arg1 */
1007 parameters[5] = 0; /* arg2 */
1008 parameters[6] = 0; /* arg3 */
1009 parameters[7] = 0; /* arg4 */
1010 parameters[8] = 0; /* arg5 */
1011 parameters[9] = 0; /* arg6 */
1012 parameters[10] = 0; /* arg7 */
1013 parameters[11] = 0; /* arg8 */
1014 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1015 CXM_FW_CMD_ASSIGN_PLACEHOLDER,
1016 parameters, 12) != 0)
1017 return -1;
1018
1019 /* assign VBI properties */
1020 parameters[0] = 0xbd04; /* mode = 0 (sliced), stream and user data */
1021 parameters[1] = 0; /* frames per interrupt (only valid in raw mode) */
1022 parameters[2] = 0; /* total raw VBI frames (only valid in raw mode) */
1023 parameters[3] = 0x25256262; /* ITU 656 start codes (saa7115 table 24)*/
1024 parameters[4] = 0x38387f7f; /* ITU 656 stop codes (saa7115 table 24) */
1025 parameters[5] = cpp->vbi.nlines; /* lines per frame */
1026 parameters[6] = 1440; /* bytes per line = 720 pixels */
1027 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1028 CXM_FW_CMD_ASSIGN_VBI_PROPERTIES,
1029 parameters, 7) != 0)
1030 return -1;
1031
1032 /* assign VBI lines */
1033 parameters[0] = 0xffffffff; /* all lines */
1034 parameters[1] = 0; /* disable VBI features */
1035 parameters[2] = 0;
1036 parameters[3] = 0;
1037 parameters[4] = 0;
1038 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1039 CXM_FW_CMD_ASSIGN_VBI_LINE,
1040 parameters, 5) != 0)
1041 return -1;
1042
1043 /* assign number of lines in fields 1 and 2 */
1044 parameters[0] = cpp->source_height / 2 + cpp->vbi.nlines;
1045 parameters[1] = cpp->source_height / 2 + cpp->vbi.nlines;
1046 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1047 CXM_FW_CMD_ASSIGN_NUM_VSYNC_LINES,
1048 parameters, 2) != 0)
1049 return -1;
1050
1051 return 0;
1052}
1053
1054
1055static int
1056cxm_start_encoder(struct cxm_softc *sc)
1057{
1058 uint32_t parameters[4];
1059 uint32_t subtype;
1060 uint32_t type;
1061
1062
1063 if (sc->encoding)
1064 return 0;
1065
1066 if (cxm_configure_encoder(sc) < 0)
1067 return -1;
1068
1069 /* Mute the video input if necessary. */
1070 parameters[0] = sc->source == cxm_fm_source ? 1 : 0;
1071 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1072 CXM_FW_CMD_MUTE_VIDEO_INPUT,
1073 parameters, 1) != 0)
1074 return -1;
1075
1076 /* Clear pending encoder interrupts (which are currently masked) */
1077 cxm_set_irq_status(sc, CXM_IRQ_ENC);
1078
1079 /* Enable event notification */
1080 parameters[0] = 0; /* Event = 0 (refresh encoder input) */
1081 parameters[1] = 1; /* Notification = 1 (enable) */
1082 parameters[2] = 0x10000000; /* Interrupt bit */
1083 parameters[3] = -1; /* Mailbox = -1 (no mailbox) */
1084 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1085 CXM_FW_CMD_ENC_EVENT_NOTIFICATION,
1086 parameters, 4) != 0)
1087 return -1;
1088
1089 if (cxm_saa7115_mute(sc) < 0)
1090 return -1;
1091 if (cxm_msp_mute(sc) < 0)
1092 return -1;
1093
1094 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1095 CXM_FW_CMD_INITIALIZE_VIDEO_INPUT,
1096 NULL, 0) < 0)
1097 return -1;
1098
1099 if (cxm_saa7115_unmute(sc) < 0)
1100 return -1;
1101 if (cxm_msp_unmute(sc) < 0)
1102 return -1;
1103
1104 /* Wait for 100ms */
1105 tsleep(&sc->encoding, 0, "cxmce", hz / 10);
1106
1107 type = sc->mpeg ? CXM_FW_CAPTURE_STREAM_TYPE_MPEG
1108 : CXM_FW_CAPTURE_STREAM_TYPE_RAW;
1109 subtype = ((sc->mpeg || sc->source == cxm_fm_source)
1110 ? CXM_FW_CAPTURE_STREAM_PCM_AUDIO : 0)
1111 | ((sc->mpeg || sc->source != cxm_fm_source)
1112 ? CXM_FW_CAPTURE_STREAM_YUV : 0);
1113
1114 /* Start the encoder */
1115 parameters[0] = type;
1116 parameters[1] = subtype;
1117 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1118 CXM_FW_CMD_BEGIN_CAPTURE, parameters, 2) != 0)
1119 return -1;
1120
1121 sc->enc_pool.offset = 0;
1122 sc->enc_pool.read = 0;
1123 sc->enc_pool.write = 0;
1124
1125 sc->encoding_eos = 0;
1126
1127 sc->encoding = 1;
1128
1129 /* Enable interrupts */
1130 cxm_set_irq_mask(sc, sc->irq_mask & ~CXM_IRQ_ENC);
1131
1132 return 0;
1133}
1134
1135
1136static int
1137cxm_stop_encoder(struct cxm_softc *sc)
1138{
1139 uint32_t parameters[4];
1140 uint32_t subtype;
1141 uint32_t type;
1142
1143 if (!sc->encoding)
1144 return 0;
1145
1146 type = sc->mpeg ? CXM_FW_CAPTURE_STREAM_TYPE_MPEG
1147 : CXM_FW_CAPTURE_STREAM_TYPE_RAW;
1148 subtype = ((sc->mpeg || sc->source == cxm_fm_source)
1149 ? CXM_FW_CAPTURE_STREAM_PCM_AUDIO : 0)
1150 | ((sc->mpeg || sc->source != cxm_fm_source)
1151 ? CXM_FW_CAPTURE_STREAM_YUV : 0);
1152
1153 /* Stop the encoder */
1154 parameters[0] = sc->mpeg ? 0 : 1; /* When = 0 (end of GOP) */
1155 parameters[1] = type;
1156 parameters[2] = subtype;
1157 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1158 CXM_FW_CMD_END_CAPTURE, parameters, 3) != 0)
1159 return -1;
1160
1161 /* Wait for up to 1 second */
1162 crit_enter();
1163 if (!sc->encoding_eos)
1164 tsleep(&sc->encoding_eos, 0, "cxmeos", hz);
1165 crit_exit();
1166
1167 if (sc->mpeg && !sc->encoding_eos)
1168 device_printf(sc->dev, "missing encoder EOS\n");
1169
1170 /* Disable event notification */
1171 parameters[0] = 0; /* Event = 0 (refresh encoder input) */
1172 parameters[1] = 0; /* Notification = 0 (disable) */
1173 parameters[2] = 0x10000000; /* Interrupt bit */
1174 parameters[3] = -1; /* Mailbox = -1 (no mailbox) */
1175 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1176 CXM_FW_CMD_ENC_EVENT_NOTIFICATION,
1177 parameters, 4) != 0)
1178 return -1;
1179
1180 /* Disable interrupts */
1181 cxm_set_irq_mask(sc, sc->irq_mask | CXM_IRQ_ENC);
1182
1183 sc->encoding = 0;
1184
1185 return 0;
1186}
1187
1188
1189static int
1190cxm_pause_encoder(struct cxm_softc *sc)
1191{
1192 uint32_t parameter;
1193
1194 /* Pause the encoder */
1195 parameter = 0;
1196 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1197 CXM_FW_CMD_PAUSE_ENCODER, &parameter, 1) != 0)
1198 return -1;
1199
1200 return 0;
1201}
1202
1203
1204static int
1205cxm_unpause_encoder(struct cxm_softc *sc)
1206{
1207 uint32_t parameter;
1208
1209 /* Unpause the encoder */
1210 parameter = 1;
1211 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1212 CXM_FW_CMD_PAUSE_ENCODER, &parameter, 1) != 0)
1213 return -1;
1214
1215 return 0;
1216}
1217
1218
1219static unsigned int
1220cxm_encoder_fixup_byte_order(struct cxm_softc *sc,
1221 unsigned int current, size_t offset)
1222{
1223 unsigned int strips;
1224 unsigned int i;
1225 unsigned int j;
1226 unsigned int k;
1227 unsigned int macroblocks_per_line;
1228 unsigned int scratch;
1229 unsigned int words_per_line;
1230 uint32_t *ptr;
1231 uint32_t *src;
1232 size_t nbytes;
1233
1234 switch (sc->enc_pool.bufs[current].byte_order) {
1235 case cxm_device_mpeg_byte_order:
1236
1237 /*
1238 * Convert each 32 bit word to the proper byte ordering.
1239 */
1240
1241 for (nbytes = 0,
1242 ptr = (uint32_t *)sc->enc_pool.bufs[current].vaddr;
1243 nbytes != sc->enc_pool.bufs[current].size;
1244 nbytes += sizeof(*ptr), ptr++)
1245 *ptr = bswap32(*ptr);
1246 break;
1247
1248 case cxm_device_yuv12_byte_order:
1249
1250 /*
1251 * Convert each macro block to planar using
1252 * a scratch buffer (the buffer prior to the
1253 * current buffer is always free since it marks
1254 * the end of the ring buffer).
1255 */
1256
1257 scratch = (current + (CXM_SG_BUFFERS - 1)) % CXM_SG_BUFFERS;
1258
1259 if (offset) {
1260 current = scratch;
1261 break;
1262 }
1263
1264 src = (uint32_t *)sc->enc_pool.bufs[current].vaddr;
1265 words_per_line = sc->profile->width / sizeof(*ptr);
1266 macroblocks_per_line
1267 = sc->profile->width / CXM_MACROBLOCK_WIDTH;
1268 strips = sc->enc_pool.bufs[current].size
1269 / (macroblocks_per_line * CXM_MACROBLOCK_SIZE);
1270
1271 for (i = 0; i < strips; i++) {
1272 ptr = (uint32_t *)sc->enc_pool.bufs[scratch].vaddr
1273 + i * macroblocks_per_line * CXM_MACROBLOCK_SIZE
1274 / sizeof(*ptr);
1275 for (j = 0; j < macroblocks_per_line; j++) {
1276 for (k = 0; k < CXM_MACROBLOCK_HEIGHT; k++) {
1277#if CXM_MACROBLOCK_WIDTH != 16
1278# error CXM_MACROBLOCK_WIDTH != 16
1279#endif
1280 *(ptr + k * words_per_line)
1281 = *src++;
1282 *(ptr + k * words_per_line + 1)
1283 = *src++;
1284 *(ptr + k * words_per_line + 2)
1285 = *src++;
1286 *(ptr + k * words_per_line + 3)
1287 = *src++;
1288 }
1289 ptr += CXM_MACROBLOCK_WIDTH / sizeof(*ptr);
1290 }
1291 }
1292
1293 sc->enc_pool.bufs[scratch].size
1294 = sc->enc_pool.bufs[current].size;
1295
1296 current = scratch;
1297 break;
1298
1299 default:
1300 break;
1301 }
1302
1303 sc->enc_pool.bufs[current].byte_order = cxm_host_byte_order;
1304
1305 return current;
1306}
1307
1308
1309static void
1310cxm_encoder_dma_discard(struct cxm_softc *sc)
1311{
1312 uint32_t parameters[3];
1313
1314 /* Discard the DMA request */
1315 parameters[0] = 0;
1316 parameters[1] = 0;
1317 parameters[2] = 0;
1318 if (cxm_queue_firmware_command(sc, cxm_enc_mailbox,
1319 CXM_FW_CMD_SCHED_DMA_TO_HOST,
1320 parameters, 3) == -1) {
1321 device_printf(sc->dev,
1322 "failed to discard encoder dma request\n");
1323 return;
1324 }
1325
1326 sc->encoding_dma = -1;
1327}
1328
1329
1330static void
1331cxm_encoder_dma_done(struct cxm_softc *sc)
1332{
1333 int buffers_pending;
1334 uint32_t status;
1335
1336 if (!sc->encoding_dma) {
1337 device_printf(sc->dev,
1338 "encoder dma not already in progress\n");
1339 return;
1340 }
1341
1342 buffers_pending = sc->encoding_dma;
1343 sc->encoding_dma = 0;
1344
1345 if (buffers_pending < 0)
1346 return;
1347
1348 status = CSR_READ_4(sc, CXM_REG_DMA_STATUS) & 0x0000000f;
1349
1350 if ((status
1351 & (CXM_DMA_ERROR_LIST | CXM_DMA_ERROR_WRITE | CXM_DMA_SUCCESS))
1352 != CXM_DMA_SUCCESS) {
1353 device_printf(sc->dev, "encoder dma status %#x\n",
1354 (unsigned int)status);
1355 return;
1356 }
1357
1358 /* Update the books */
1359 crit_enter();
1360 sc->enc_pool.write = (sc->enc_pool.write + buffers_pending)
1361 % CXM_SG_BUFFERS;
1362 crit_exit();
1363
1364 /* signal anyone requesting notification */
1365 if (sc->enc_proc)
1366 ksignal (sc->enc_proc, sc->enc_signal);
1367
1368 /* wakeup anyone waiting for data */
1369 wakeup(&sc->enc_pool.read);
1370
1371 /* wakeup anyone polling for data */
5b22f1a7 1372 KNOTE(&sc->enc_kq.ki_note, 0);
e9afadfd
SW
1373}
1374
1375
1376static void
1377cxm_encoder_dma_request(struct cxm_softc *sc)
1378{
1379 enum cxm_byte_order byte_order;
1380 int buffers_free;
1381 int buffers_pending;
1382 unsigned int current;
1383 unsigned int i;
1384 unsigned int mailbox;
1385 unsigned int macroblocks_per_line;
1386 unsigned int nrequests;
1387 unsigned int strips;
1388 uint32_t parameters[CXM_MBX_MAX_PARAMETERS];
1389 uint32_t type;
1390 size_t max_sg_segment;
1391 struct {
1392 size_t offset;
1393 size_t size;
1394 } requests[2];
1395
1396 if (sc->encoding_dma) {
1397 device_printf(sc->dev, "encoder dma already in progress\n");
1398 cxm_encoder_dma_discard(sc);
1399 return;
1400 }
1401
1402 mailbox = sc->enc_mbx
1403 + CXM_MBX_FW_DMA_MAILBOX * sizeof(struct cxm_mailbox);
1404
1405 for (i = 0; i < CXM_MBX_MAX_PARAMETERS; i++)
1406 parameters[i]
1407 = CSR_READ_4(sc,
1408 mailbox
1409 + offsetof(struct cxm_mailbox, parameters)
1410 + i * sizeof(uint32_t)
1411 );
1412
1413 byte_order = cxm_device_mpeg_byte_order;
1414 max_sg_segment = CXM_SG_SEGMENT;
1415 nrequests = 0;
1416 type = parameters[0];
1417
1418 switch (type) {
1419 case 0: /* MPEG */
1420 requests[nrequests].offset = parameters[1];
1421 requests[nrequests++].size = parameters[2];
1422 break;
1423
1424 case 1: /* YUV */
1425 byte_order = cxm_device_yuv12_byte_order;
1426
1427 /*
1428 * Simplify macroblock unpacking by ensuring
1429 * that strips don't span buffers.
1430 */
1431
1432#if CXM_MACROBLOCK_SIZE % 256
1433# error CXM_MACROBLOCK_SIZE not a multiple of 256
1434#endif
1435
1436 macroblocks_per_line = sc->profile->width
1437 / CXM_MACROBLOCK_WIDTH;
1438 strips = CXM_SG_SEGMENT
1439 / (macroblocks_per_line * CXM_MACROBLOCK_SIZE);
1440 max_sg_segment = strips
1441 * macroblocks_per_line * CXM_MACROBLOCK_SIZE;
1442
1443 requests[nrequests].offset = parameters[1]; /* Y */
1444 requests[nrequests++].size = parameters[2];
1445 requests[nrequests].offset = parameters[3]; /* UV */
1446 requests[nrequests++].size = parameters[4];
1447 break;
1448
1449 case 2: /* PCM (audio) */
1450 case 3: /* VBI */
1451 default:
1452 device_printf(sc->dev, "encoder dma type %#x unsupported\n",
1453 (unsigned int)type);
1454 cxm_encoder_dma_discard(sc);
1455 return;
1456 }
1457
1458 /*
1459 * Determine the number of buffers free at this * instant *
1460 * taking into consideration that the ring buffer wraps.
1461 */
1462 crit_enter();
1463 buffers_free = sc->enc_pool.read - sc->enc_pool.write;
1464 if (buffers_free <= 0)
1465 buffers_free += CXM_SG_BUFFERS;
1466 crit_exit();
1467
1468 /*
1469 * Build the scatter / gather list taking in
1470 * consideration that the ring buffer wraps,
1471 * at least one free buffer must always be
1472 * present to mark the end of the ring buffer,
1473 * and each transfer must be a multiple of 256.
1474 */
1475
1476 buffers_pending = 0;
1477 current = sc->enc_pool.write;
1478
1479 for (i = 0; i < nrequests; i++) {
1480 if (!requests[i].size) {
1481 device_printf(sc->dev, "encoder dma size is zero\n");
1482 cxm_encoder_dma_discard(sc);
1483 return;
1484 }
1485
1486 while (requests[i].size) {
1487 sc->enc_pool.bufs[current].size
1488 = requests[i].size > max_sg_segment
1489 ? max_sg_segment : requests[i].size;
1490 sc->enc_pool.bufs[current].byte_order = byte_order;
1491
1492 sc->enc_sg.vaddr[buffers_pending].src
1493 = requests[i].offset;
1494 sc->enc_sg.vaddr[buffers_pending].dst
1495 = sc->enc_pool.bufs[current].baddr;
1496 sc->enc_sg.vaddr[buffers_pending].size
1497 = (sc->enc_pool.bufs[current].size + 0x000000ff)
1498 & 0xffffff00;
1499
1500 requests[i].offset += sc->enc_pool.bufs[current].size;
1501 requests[i].size -= sc->enc_pool.bufs[current].size;
1502 buffers_pending++;
1503 current = (current + 1) % CXM_SG_BUFFERS;
1504
1505 if (buffers_pending >= buffers_free) {
1506 device_printf(sc->dev,
1507 "encoder dma not enough buffer space free\n");
1508 cxm_encoder_dma_discard(sc);
1509 return;
1510 }
1511 }
1512 }
1513
1514 /* Mark the last transfer in the list */
1515 sc->enc_sg.vaddr[buffers_pending - 1].size |= 0x80000000;
1516
1517 /* Schedule the DMA */
1518 parameters[0] = sc->enc_sg.baddr;
1519 parameters[1] = buffers_pending * sizeof(sc->enc_sg.vaddr[0]);
1520 parameters[2] = type;
1521 if (cxm_queue_firmware_command(sc, cxm_enc_mailbox,
1522 CXM_FW_CMD_SCHED_DMA_TO_HOST,
1523 parameters, 3) == -1) {
1524 device_printf(sc->dev,
1525 "failed to schedule encoder dma request\n");
1526 return;
1527 }
1528
1529 /*
1530 * Record the number of pending buffers for the
1531 * benefit of cxm_encoder_dma_done. Doing this
1532 * after queuing the command doesn't introduce
1533 * a race condition since we're already in the
1534 * interrupt handler.
1535 */
1536
1537 sc->encoding_dma = buffers_pending;
1538}
1539
1540
1541static int
1542cxm_encoder_wait_for_lock(struct cxm_softc *sc)
1543{
1544 int muted;
1545 int locked;
1546 int result;
1547
1548 locked = 1;
1549
1550 /*
1551 * Wait for the tuner to lock.
1552 */
1553 if (sc->source == cxm_fm_source || sc->source == cxm_tuner_source) {
1554 result = cxm_tuner_wait_for_lock(sc);
1555 if (result <= 0)
1556 return result;
1557 }
1558
1559 /*
1560 * Wait for the video decoder to lock.
1561 */
1562 if (sc->source != cxm_fm_source) {
1563 result = cxm_saa7115_wait_for_lock(sc);
1564 if (result < 0)
1565 return result;
1566 else if (result == 0)
1567 locked = 0;
1568 }
1569
1570 /*
1571 * Wait for the audio decoder to lock.
1572 */
1573 if (sc->source == cxm_tuner_source) {
1574 muted = cxm_msp_is_muted(sc);
1575
1576 result = cxm_msp_autodetect_standard(sc);
1577 if (result < 0)
1578 return result;
1579 else if (result == 0)
1580 locked = 0;
1581
1582 if (muted == 0 && cxm_msp_unmute(sc) < 0)
1583 return -1;
1584 }
1585
1586 return locked;
1587}
1588
1589
1590static void
1591cxm_mapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1592{
1593 bus_addr_t *busaddrp;
1594
1595 /*
1596 * Only the first bus space address is needed
1597 * since it's known that the memory is physically
1598 * contiguous due to bus_dmamem_alloc.
1599 */
1600
1601 busaddrp = (bus_addr_t *)arg;
1602 *busaddrp = segs->ds_addr;
1603}
1604
1605
1606/*
1607 * the boot time probe routine.
1608 */
1609static int
1610cxm_probe(device_t dev)
1611{
1612 struct cxm_dev *t;
1613
1614 t = cxm_devs;
1615
1616 while(t->name != NULL) {
1617 if ((pci_get_vendor(dev) == t->vid) &&
1618 (pci_get_device(dev) == t->did)) {
1619 device_set_desc(dev, t->name);
1620 return 0;
1621 }
1622 t++;
1623 }
1624
1625 return ENXIO;
1626}
1627
1628
1629/*
1630 * the attach routine.
1631 */
1632static int
1633cxm_attach(device_t dev)
1634{
1635 int error;
1636 int rid;
1637 int unit;
1638 unsigned int i;
1639 uint32_t command;
1640 struct cxm_softc *sc;
1641
1642 /* Get the device data */
1643 sc = device_get_softc(dev);
1644 unit = device_get_unit(dev);
1645
1646 sc->dev = dev;
1647 sc->type = cxm_iTVC15_type;
1648
1649 switch(pci_get_device(dev)) {
1650 case PCI_PRODUCT_ICOMPRESSION_ITVC16:
1651 sc->type = cxm_iTVC16_type;
1652 break;
1653
1654 default:
1655 break;
1656 }
1657
1658 /*
1659 * Enable bus mastering and memory mapped I/O.
1660 */
1661 pci_enable_busmaster(dev);
1662 pci_enable_io(dev, SYS_RES_MEMORY);
1663 command = pci_read_config(dev, PCIR_COMMAND, 4);
1664
1665 if (!(command & PCIM_CMD_MEMEN)) {
1666 device_printf(dev, "failed to enable memory mappings\n");
1667 error = ENXIO;
1668 goto fail;
1669 }
1670
1671 /*
1672 * Map control/status registers.
1673 */
1674 rid = CXM_RID;
1675 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
1676 0, ~0, 1, RF_ACTIVE);
1677
1678 if (!sc->mem_res) {
1679 device_printf(dev, "could not map memory\n");
1680 error = ENXIO;
1681 goto fail;
1682 }
1683
1684 sc->btag = rman_get_bustag(sc->mem_res);
1685 sc->bhandle = rman_get_bushandle(sc->mem_res);
1686
1687 /*
1688 * Attach the I2C bus.
1689 */
1690 sc->cxm_iic = device_add_child(dev, "cxm_iic", unit);
1691
1692 if (!sc->cxm_iic) {
1693 device_printf(dev, "could not add cxm_iic\n");
1694 error = ENXIO;
1695 goto fail;
1696 }
1697
1698 error = device_probe_and_attach(sc->cxm_iic);
1699
1700 if (error) {
1701 device_printf(dev, "could not attach cxm_iic\n");
1702 goto fail;
1703 }
1704
1705 /*
1706 * Initialize the tuner.
1707 */
1708 if (cxm_tuner_init(sc) < 0) {
1709 device_printf(dev, "could not initialize tuner\n");
1710 error = ENXIO;
1711 goto fail;
1712 }
1713
1714 /*
1715 * Initialize the SAA7115.
1716 */
1717 if (cxm_saa7115_init(sc) < 0) {
1718 device_printf(dev, "could not initialize video decoder\n");
1719 error = ENXIO;
1720 goto fail;
1721 }
1722
1723 /*
1724 * Initialize the MSP3400.
1725 */
1726 if (cxm_msp_init(sc) < 0) {
1727 device_printf(dev, "could not initialize audio decoder\n");
1728 error = ENXIO;
1729 goto fail;
1730 }
1731
1732 /*
1733 * Initialize the IR Remote.
1734 */
1735 if (cxm_ir_init(sc) < 0) {
1736 device_printf(dev, "could not initialize IR remote\n");
1737 error = ENXIO;
1738 goto fail;
1739 }
1740
1741 sc->dec_mbx = -1;
1742 sc->enc_mbx = -1;
1743
1744 /*
1745 * Disable the Conexant device.
1746 *
1747 * This is done * after * attaching the I2C bus so
1748 * cxm_stop_hardware can mute the video and audio
1749 * decoders.
1750 */
1751 cxm_stop_hardware(sc);
1752
1753 /*
1754 * Allocate our interrupt.
1755 */
1756 rid = 0;
1757 sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
1758 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
1759
1760 if (sc->irq_res == NULL) {
1761 device_printf(dev, "could not map interrupt\n");
1762 error = ENXIO;
1763 goto fail;
1764 }
1765
1766 error = bus_setup_intr(dev, sc->irq_res, 0,
1767 cxm_intr, sc, &sc->ih_cookie, NULL);
1768 if (error) {
1769 device_printf(dev, "could not setup irq\n");
1770 goto fail;
1771
1772 }
1773
1774 /*
1775 * Allocate a DMA tag for the parent bus.
1776 */
1777 error = bus_dma_tag_create(NULL, 1, 0,
1778 BUS_SPACE_MAXADDR_32BIT,
1779 BUS_SPACE_MAXADDR, NULL, NULL,
1780 BUS_SPACE_MAXSIZE_32BIT, 1,
1781 BUS_SPACE_MAXSIZE_32BIT, 0,
1782 &sc->parent_dmat);
1783 if (error) {
1784 device_printf(dev, "could not create parent bus DMA tag\n");
1785 goto fail;
1786 }
1787
1788 /*
1789 * Allocate a DMA tag for the encoder buffers.
1790 */
1791 error = bus_dma_tag_create(sc->parent_dmat, 256, 0,
1792 BUS_SPACE_MAXADDR_32BIT,
1793 BUS_SPACE_MAXADDR, NULL, NULL,
1794 CXM_SG_SEGMENT, 1,
1795 BUS_SPACE_MAXSIZE_32BIT, 0,
1796 &sc->enc_pool.dmat);
1797 if (error) {
1798 device_printf(dev,
1799 "could not create encoder buffer DMA tag\n");
1800 goto fail;
1801 }
1802
1803 for (i = 0; i < CXM_SG_BUFFERS; i++) {
1804
1805 /*
1806 * Allocate the encoder buffer.
1807 */
1808 error = bus_dmamem_alloc(sc->enc_pool.dmat,
1809 (void **)&sc->enc_pool.bufs[i].vaddr,
1810 BUS_DMA_NOWAIT,
1811 &sc->enc_pool.bufs[i].dmamap);
1812 if (error) {
1813 device_printf(dev,
1814 "could not allocate encoder buffer\n");
1815 goto fail;
1816 }
1817
1818 /*
1819 * Map the encoder buffer.
1820 */
1821 error = bus_dmamap_load(sc->enc_pool.dmat,
1822 sc->enc_pool.bufs[i].dmamap,
1823 sc->enc_pool.bufs[i].vaddr,
1824 CXM_SG_SEGMENT,
1825 cxm_mapmem,
1826 &sc->enc_pool.bufs[i].baddr, 0);
1827 if (error) {
1828 device_printf(dev, "could not map encoder buffer\n");
1829 goto fail;
1830 }
1831 }
1832
1833 /*
1834 * Allocate a DMA tag for the scatter / gather list.
1835 */
1836 error = bus_dma_tag_create(sc->parent_dmat, 1, 0,
1837 BUS_SPACE_MAXADDR_32BIT,
1838 BUS_SPACE_MAXADDR, NULL, NULL,
1839 CXM_SG_BUFFERS
1840 * sizeof(struct cxm_sg_entry), 1,
1841 BUS_SPACE_MAXSIZE_32BIT, 0,
1842 &sc->enc_sg.dmat);
1843 if (error) {
1844 device_printf(dev,
1845 "could not create scatter / gather DMA tag\n");
1846 goto fail;
1847 }
1848
1849 /*
1850 * Allocate the scatter / gather list.
1851 */
1852 error = bus_dmamem_alloc(sc->enc_sg.dmat, (void **)&sc->enc_sg.vaddr,
1853 BUS_DMA_NOWAIT, &sc->enc_sg.dmamap);
1854 if (error) {
1855 device_printf(dev,
1856 "could not allocate scatter / gather list\n");
1857 goto fail;
1858 }
1859
1860 /*
1861 * Map the scatter / gather list.
1862 */
1863 error = bus_dmamap_load(sc->enc_sg.dmat, sc->enc_sg.dmamap,
1864 sc->enc_sg.vaddr,
1865 CXM_SG_BUFFERS * sizeof(struct cxm_sg_entry),
1866 cxm_mapmem, &sc->enc_sg.baddr, 0);
1867 if (error) {
1868 device_printf(dev, "could not map scatter / gather list\n");
1869 goto fail;
1870 }
1871
1872 /*
1873 * Initialize the hardware.
1874 */
1875 if (cxm_init_hardware(sc) < 0) {
1876 device_printf(dev, "could not initialize hardware\n");
1877 error = ENXIO;
1878 goto fail;
1879 }
1880
1881 sc->profile = &dvd_full_d1_ntsc_profile;
1882
1883 sc->source = cxm_tuner_source;
1884
1885
1886 /* make the device entries */
e9afadfd 1887 sc->cxm_dev_t = make_dev(&cxm_ops, unit,
3e82b46c 1888 0, 0, 0444, "cxm%d", unit);
e9afadfd
SW
1889
1890 return 0;
1891
1892fail:
1893 if (sc->enc_sg.baddr)
1894 bus_dmamap_unload(sc->enc_sg.dmat, sc->enc_sg.dmamap);
1895 if (sc->enc_sg.vaddr)
1896 bus_dmamem_free(sc->enc_sg.dmat, sc->enc_sg.vaddr,
1897 sc->enc_sg.dmamap);
1898 if (sc->enc_sg.dmat)
1899 bus_dma_tag_destroy(sc->enc_sg.dmat);
1900
1901 for (i = 0; i < CXM_SG_BUFFERS; i++) {
1902 if (sc->enc_pool.bufs[i].baddr)
1903 bus_dmamap_unload(sc->enc_pool.dmat,
1904 sc->enc_pool.bufs[i].dmamap);
1905 if (sc->enc_pool.bufs[i].vaddr)
1906 bus_dmamem_free(sc->enc_pool.dmat,
1907 sc->enc_pool.bufs[i].vaddr,
1908 sc->enc_pool.bufs[i].dmamap);
1909 }
1910
1911 if (sc->enc_pool.dmat)
1912 bus_dma_tag_destroy(sc->enc_pool.dmat);
1913
1914 if (sc->parent_dmat)
1915 bus_dma_tag_destroy(sc->parent_dmat);
1916
1917 /*
1918 * Detach the I2C bus.
1919 *
1920 * This is done * after * deallocating the scatter / gather
1921 * list and buffers so the kernel has a better chance of
1922 * gracefully handling a memory shortage.
1923 *
1924 * Detach the children before recursively deleting
1925 * in case a child has a pointer to a grandchild
1926 * which is used by the child's detach routine.
1927 */
1928 bus_generic_detach(dev);
1929 if (sc->cxm_iic)
1930 device_delete_child(dev, sc->cxm_iic);
1931
1932 if (sc->ih_cookie)
1933 bus_teardown_intr(dev, sc->irq_res, sc->ih_cookie);
1934 if (sc->irq_res)
1935 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
1936 if (sc->mem_res)
1937 bus_release_resource(dev, SYS_RES_MEMORY, CXM_RID, sc->mem_res);
1938
1939 return error;
1940}
1941
1942/*
1943 * the detach routine.
1944 */
1945static int
1946cxm_detach(device_t dev)
1947{
1948 unsigned int i;
1949 struct cxm_softc *sc;
1950 device_t child;
1951
1952 /* Get the device data */
1953 sc = device_get_softc(dev);
1954
1955 /* Disable the Conexant device. */
1956 cxm_stop_hardware(sc);
1957
1958 /* Unregister the /dev/cxmN device. */
cd29885a 1959 dev_ops_remove_minor(&cxm_ops, /*0, */device_get_unit(dev));
e9afadfd
SW
1960
1961 /*
1962 * Deallocate scatter / gather list and buffers.
1963 */
1964 bus_dmamap_unload(sc->enc_sg.dmat, sc->enc_sg.dmamap);
1965 bus_dmamem_free(sc->enc_sg.dmat, sc->enc_sg.vaddr, sc->enc_sg.dmamap);
1966
1967 bus_dma_tag_destroy(sc->enc_sg.dmat);
1968
1969 for (i = 0; i < CXM_SG_BUFFERS; i++) {
1970 bus_dmamap_unload(sc->enc_pool.dmat,
1971 sc->enc_pool.bufs[i].dmamap);
1972 bus_dmamem_free(sc->enc_pool.dmat, sc->enc_pool.bufs[i].vaddr,
1973 sc->enc_pool.bufs[i].dmamap);
1974 }
1975
1976 bus_dma_tag_destroy(sc->enc_pool.dmat);
1977
1978 bus_dma_tag_destroy(sc->parent_dmat);
1979
1980 /*
1981 * Detach the I2C bus.
1982 *
1983 * This is done * after * deallocating the scatter / gather
1984 * list and buffers so the kernel has a better chance of
1985 * gracefully handling a memory shortage.
1986 *
1987 * Detach the children before recursively deleting
1988 * in case a child has a pointer to a grandchild
1989 * which is used by the child's detach routine.
1990 *
1991 * Remember the child before detaching so we can
1992 * delete it (bus_generic_detach indirectly zeroes
1993 * sc->child_dev).
1994 */
1995 child = sc->cxm_iic;
1996 bus_generic_detach(dev);
1997 if (child)
1998 device_delete_child(dev, child);
1999
2000 /* Deallocate resources. */
2001 bus_teardown_intr(dev, sc->irq_res, sc->ih_cookie);
2002 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
2003 bus_release_resource(dev, SYS_RES_MEMORY, CXM_RID, sc->mem_res);
2004
2005 return 0;
2006}
2007
2008/*
2009 * the shutdown routine.
2010 */
2011static int
2012cxm_shutdown(device_t dev)
2013{
2014 struct cxm_softc *sc = device_get_softc(dev);
2015
2016 /* Disable the Conexant device. */
2017 cxm_stop_hardware(sc);
2018
2019 return 0;
2020}
2021
2022/*
2023 * the interrupt routine.
2024 */
2025static void
2026cxm_intr(void *arg)
2027{
2028 uint32_t status;
2029 struct cxm_softc *sc;
2030
2031 /* Get the device data */
2032 sc = (struct cxm_softc *)arg;
2033
2034 status = CSR_READ_4(sc, CXM_REG_IRQ_STATUS);
2035
2036 status &= ~sc->irq_mask;
2037
2038 if (!status)
2039 return;
2040
2041 /* Process DMA done before handling a new DMA request or EOS */
2042 if (status & CXM_IRQ_ENC_DMA_DONE)
2043 cxm_encoder_dma_done(sc);
2044
2045 if (status & CXM_IRQ_ENC_DMA_REQUEST)
2046 cxm_encoder_dma_request(sc);
2047
2048 if (status & CXM_IRQ_ENC_EOS) {
2049 sc->encoding_eos = 1;
2050 wakeup(&sc->encoding_eos);
2051 }
2052
2053 cxm_set_irq_status(sc, status);
2054}
2055
2056
2057/*
2058 * the child detached routine.
2059 */
2060static void
2061cxm_child_detached(device_t dev, device_t child)
2062{
2063 struct cxm_softc *sc;
2064
2065 /* Get the device data */
2066 sc = device_get_softc(dev);
2067
2068 if (child == sc->cxm_iic)
2069 sc->cxm_iic = NULL;
2070}
2071
2072
2073static int
2074cxm_read_ivar(device_t dev, device_t child, int index, uintptr_t* val)
2075{
2076 struct cxm_softc *sc;
2077
2078 /* Get the device data */
2079 sc = device_get_softc(dev);
2080
2081 switch (index) {
2082 case CXM_IVAR_BHANDLE:
2083 *(bus_space_handle_t **)val = &sc->bhandle;
2084 break;
2085
2086 case CXM_IVAR_BTAG:
2087 *(bus_space_tag_t **)val = &sc->btag;
2088 break;
2089
2090 case CXM_IVAR_IICBUS:
2091 *(device_t **)val = &sc->iicbus;
2092 break;
2093
2094 default:
2095 return ENOENT;
2096 }
2097
2098 return 0;
2099}
2100
2101
2102static int
2103cxm_write_ivar(device_t dev, device_t child, int index, uintptr_t val)
2104{
2105 struct cxm_softc *sc;
2106
2107 /* Get the device data */
2108 sc = device_get_softc(dev);
2109
2110 switch (index) {
2111 case CXM_IVAR_BHANDLE:
2112 return EINVAL;
2113
2114 case CXM_IVAR_BTAG:
2115 return EINVAL;
2116
2117 case CXM_IVAR_IICBUS:
2118 if (sc->iicbus)
2119 return EINVAL;
2120 sc->iicbus = val ? *(device_t *)val : NULL;
2121 break;
2122
2123 default:
2124 return ENOENT;
2125 }
2126
2127 return 0;
2128}
2129
2130
2131/*---------------------------------------------------------
2132**
2133** Conexant iTVC15 / iTVC16 character device driver routines
2134**
2135**---------------------------------------------------------
2136*/
2137
2138#define UNIT(x) ((x) & 0x0f)
2139#define FUNCTION(x) (x >> 4)
2140
2141/*
2142 *
2143 */
2144int
2145cxm_open(struct dev_open_args *ap)
2146{
2147 cdev_t dev = ap->a_head.a_dev;
2148 int unit;
2149 struct cxm_softc *sc;
2150
2151 unit = UNIT(minor(dev));
2152
2153 /* Get the device data */
2154 sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit);
2155 if (sc == NULL) {
2156 /* the device is no longer valid/functioning */
2157 return ENXIO;
2158 }
2159
2160 if (sc->is_opened)
2161 return EBUSY;
2162
2163 sc->is_opened = 1;
2164 sc->mpeg = 1;
2165
2166 /* Record that the device is now busy */
2167 device_busy(devclass_get_device(cxm_devclass, unit));
2168
2169 return 0;
2170}
2171
2172
2173/*
2174 *
2175 */
2176int
2177cxm_close(struct dev_close_args *ap)
2178{
2179 cdev_t dev = ap->a_head.a_dev;
2180 int unit;
2181 struct cxm_softc *sc;
2182
2183 unit = UNIT(minor(dev));
2184
2185 /* Get the device data */
2186 sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit);
2187 if (sc == NULL) {
2188 /* the device is no longer valid/functioning */
2189 return ENXIO;
2190 }
2191
2192 if (cxm_stop_encoder(sc) < 0)
2193 return ENXIO;
2194
2195 sc->enc_pool.offset = 0;
2196 sc->enc_pool.read = 0;
2197 sc->enc_pool.write = 0;
2198
2199 sc->enc_proc = NULL;
2200 sc->enc_signal = 0;
2201
2202 device_unbusy(devclass_get_device(cxm_devclass, unit));
2203
2204 sc->is_opened = 0;
2205
2206 return 0;
2207}
2208
2209
2210/*
2211 *
2212 */
2213int
2214cxm_read(struct dev_read_args *ap)
2215{
2216 cdev_t dev = ap->a_head.a_dev;
2217 int buffers_available;
2218 int buffers_read;
2219 int error;
2220 int unit;
2221 unsigned int current;
2222 unsigned int i;
2223 size_t nbytes;
2224 size_t offset;
2225 struct cxm_softc *sc;
2226
2227 unit = UNIT(minor(dev));
2228
2229 /* Get the device data */
2230 sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit);
2231 if (sc == NULL) {
2232 /* the device is no longer valid/functioning */
2233 return ENXIO;
2234 }
2235
2236 /* Only trigger the encoder if the ring buffer is empty */
2237 if (!sc->encoding && sc->enc_pool.read == sc->enc_pool.write) {
2238 if (cxm_start_encoder(sc) < 0)
2239 return ENXIO;
2240 if (ap->a_ioflag & IO_NDELAY)
2241 return EWOULDBLOCK;
2242 }
2243
2244 buffers_available = 0;
2245
2246 crit_enter();
2247 while (sc->enc_pool.read == sc->enc_pool.write) {
2248 error = tsleep(&sc->enc_pool.read, PCATCH, "cxmrd", 0);
2249 if (error) {
2250 crit_exit();
2251 return error;
2252 }
2253 }
2254
2255 /*
2256 * Determine the number of buffers available at this * instant *
2257 * taking in consideration that the ring buffer wraps.
2258 */
2259 buffers_available = sc->enc_pool.write - sc->enc_pool.read;
2260 if (buffers_available < 0)
2261 buffers_available += CXM_SG_BUFFERS;
2262 crit_exit();
2263
2264 offset = sc->enc_pool.offset;
2265
2266 for (buffers_read = 0, i = sc->enc_pool.read;
2267 buffers_read != buffers_available && ap->a_uio->uio_resid;
2268 buffers_read++, i = (i + 1) % CXM_SG_BUFFERS) {
2269
2270 current = cxm_encoder_fixup_byte_order (sc, i, offset);
2271
2272 nbytes = sc->enc_pool.bufs[current].size - offset;
2273
2274 /* Don't transfer more than requested */
2275 if (nbytes > ap->a_uio->uio_resid)
2276 nbytes = ap->a_uio->uio_resid;
2277
2278 error = uiomove(sc->enc_pool.bufs[current].vaddr + offset,
2279 nbytes, ap->a_uio);
2280 if (error)
2281 return error;
2282
2283 offset += nbytes;
2284
2285 /* Handle a partial read of a buffer */
2286 if (!ap->a_uio->uio_resid && offset != sc->enc_pool.bufs[i].size)
2287 break;
2288
2289 offset = 0;
2290 }
2291
2292 sc->enc_pool.offset = offset;
2293
2294 /* Update the books */
2295 crit_enter();
2296 sc->enc_pool.read = (sc->enc_pool.read + buffers_read)
2297 % CXM_SG_BUFFERS;
2298 crit_exit();
2299
2300 return 0;
2301}
2302
2303
2304/*
2305 *
2306 */
2307int
2308cxm_ioctl(struct dev_ioctl_args *ap)
2309{
2310 cdev_t dev = ap->a_head.a_dev;
2311 int brightness;
2312 int chroma_saturation;
2313 int contrast;
2314 int fps;
2315 int hue;
2316 int result;
2317 int status;
2318 int unit;
2319 unsigned int i;
2320 unsigned int sig;
2321 unsigned long freq;
2322 struct cxm_softc *sc;
2323 enum cxm_source source;
2324 struct bktr_capture_area *cap;
2325 struct bktr_remote *remote;
2326
2327 unit = UNIT(minor(dev));
2328
2329 /* Get the device data */
2330 sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit);
2331 if (sc == NULL) {
2332 /* the device is no longer valid/functioning */
2333 return ENXIO;
2334 }
2335
2336 switch (ap->a_cmd) {
2337 case BT848_GAUDIO:
2338 switch (cxm_msp_selected_source(sc)) {
2339 case cxm_tuner_source:
2340 *(int *) ap->a_data = AUDIO_TUNER;
2341 break;
2342
2343 case cxm_line_in_source_composite:
2344 case cxm_line_in_source_svideo:
2345 *(int *) ap->a_data = AUDIO_EXTERN;
2346 break;
2347
2348 case cxm_fm_source:
2349 *(int *) ap->a_data = AUDIO_INTERN;
2350 break;
2351
2352 default:
2353 return ENXIO;
2354 }
2355
2356 if (cxm_msp_is_muted(sc) == 1)
2357 *(int *) ap->a_data |= AUDIO_MUTE;
2358 break;
2359
2360 case BT848_SAUDIO:
2361 source = cxm_unknown_source;
2362
2363 switch (*(int *) ap->a_data) {
2364 case AUDIO_TUNER:
2365 source = cxm_tuner_source;
2366 break;
2367
2368 case AUDIO_EXTERN:
2369 source = cxm_line_in_source_composite;
2370 break;
2371
2372 case AUDIO_INTERN:
2373 source = cxm_fm_source;
2374 break;
2375
2376 case AUDIO_MUTE:
2377 if (cxm_msp_mute(sc) < 0)
2378 return ENXIO;
2379 return 0;
2380
2381 case AUDIO_UNMUTE:
2382 if (cxm_msp_unmute(sc) < 0)
2383 return ENXIO;
2384 return 0;
2385
2386 default:
2387 return EINVAL;
2388 }
2389
2390 if (sc->encoding) {
2391
2392 /*
2393 * Switching between audio + video and audio only
2394 * subtypes isn't supported while encoding.
2395 */
2396
2397 if (source != sc->source
2398 && (source == cxm_fm_source
2399 || sc->source == cxm_fm_source))
2400 return EBUSY;
2401 }
2402
2403 if (cxm_pause_encoder(sc) < 0)
2404 return ENXIO;
2405
2406 if (cxm_msp_select_source(sc, source) < 0)
2407 return ENXIO;
2408
2409 if (source == cxm_fm_source)
2410 sc->source = source;
2411
2412 result = cxm_encoder_wait_for_lock(sc);
2413 if (result < 0)
2414 return ENXIO;
2415 else if (result == 0)
2416 return EINVAL;
2417
2418 if (cxm_unpause_encoder(sc) < 0)
2419 return ENXIO;
2420 break;
2421
2422 case BT848_GBRIG:
2423 brightness = cxm_saa7115_get_brightness(sc);
2424
2425 if (brightness < 0)
2426 return ENXIO;
2427
2428 /*
2429 * Brooktree brightness:
2430 * 0x80 = -50.0%, 0x00 = +0.0%, 0x7f = +49.6%
2431 */
2432 *(int *)ap->a_data = (int)(unsigned char)brightness - 128;
2433 break;
2434
2435 case BT848_SBRIG:
2436
2437 /*
2438 * Brooktree brightness:
2439 * 0x80 = -50.0%, 0x00 = +0.0%, 0x7f = +49.6%
2440 */
2441 brightness = *(int *)ap->a_data + 128;
2442
2443 if (cxm_saa7115_set_brightness(sc, brightness) < 0)
2444 return ENXIO;
2445 break;
2446
2447 case METEORGBRIG:
2448 brightness = cxm_saa7115_get_brightness(sc);
2449
2450 if (brightness < 0)
2451 return ENXIO;
2452
2453 *(unsigned char *)ap->a_data = (unsigned char)brightness;
2454 break;
2455
2456 case METEORSBRIG:
2457 brightness = *(unsigned char *)ap->a_data;
2458
2459 if (cxm_saa7115_set_brightness(sc, brightness) < 0)
2460 return ENXIO;
2461 break;
2462
2463 case BT848_GCSAT:
2464 chroma_saturation = cxm_saa7115_get_chroma_saturation(sc);
2465
2466 if (chroma_saturation < 0)
2467 return ENXIO;
2468
2469 /*
2470 * Brooktree chroma saturation:
2471 * 0x000 = 0%, 0x0fe = 100%, 0x1ff = 201.18%
2472 */
2473 *(int *)ap->a_data = ((signed char)chroma_saturation > 0)
2474 ? (chroma_saturation * 4 - 2) : 0;
2475 break;
2476
2477 case BT848_SCSAT:
2478
2479 /*
2480 * Brooktree chroma saturation:
2481 * 0x000 = 0%, 0x0fe = 100%, 0x1ff = 201.18%
2482 */
2483 chroma_saturation = (*(int *)ap->a_data & 0x1ff) < 510
2484 ? ((*(int *)ap->a_data & 0x1ff) + 2) / 4 : 127;
2485
2486 if (cxm_saa7115_set_chroma_saturation(sc, chroma_saturation)
2487 < 0)
2488 return ENXIO;
2489
2490 break;
2491
2492 case METEORGCSAT:
2493 chroma_saturation = cxm_saa7115_get_chroma_saturation(sc);
2494
2495 if (chroma_saturation < 0)
2496 return ENXIO;
2497
2498 *(unsigned char *)ap->a_data = (unsigned char)chroma_saturation;
2499 break;
2500
2501 case METEORSCSAT:
2502 chroma_saturation = *(unsigned char *)ap->a_data;
2503
2504 if (cxm_saa7115_set_chroma_saturation(sc, chroma_saturation)
2505 < 0)
2506 return ENXIO;
2507 break;
2508
2509 case METEORGCONT:
2510 contrast = cxm_saa7115_get_contrast(sc);
2511
2512 if (contrast < 0)
2513 return ENXIO;
2514
2515 *(unsigned char *)ap->a_data = (unsigned char)contrast;
2516 break;
2517
2518 case METEORSCONT:
2519 contrast = *(unsigned char *)ap->a_data;
2520
2521 if (cxm_saa7115_set_contrast(sc, contrast) < 0)
2522 return ENXIO;
2523 break;
2524
2525 case BT848_GHUE:
2526 hue = cxm_saa7115_get_hue(sc);
2527
2528 if (hue < 0)
2529 return ENXIO;
2530
2531 *(int *)ap->a_data = (signed char)hue;
2532 break;
2533
2534 case BT848_SHUE:
2535 hue = *(int *)ap->a_data;
2536
2537 if (cxm_saa7115_set_hue(sc, hue) < 0)
2538 return ENXIO;
2539 break;
2540
2541 case METEORGHUE:
2542 hue = cxm_saa7115_get_hue(sc);
2543
2544 if (hue < 0)
2545 return ENXIO;
2546
2547 *(signed char *)ap->a_data = (signed char)hue;
2548 break;
2549
2550 case METEORSHUE:
2551 hue = *(signed char *)ap->a_data;
2552
2553 if (cxm_saa7115_set_hue(sc, hue) < 0)
2554 return ENXIO;
2555 break;
2556
2557 case METEORCAPTUR:
2558 switch (*(int *) ap->a_data) {
2559 case METEOR_CAP_CONTINOUS:
2560 if (cxm_start_encoder(sc) < 0)
2561 return ENXIO;
2562 break;
2563
2564 case METEOR_CAP_STOP_CONT:
2565 if (cxm_stop_encoder(sc) < 0)
2566 return ENXIO;
2567 break;
2568
2569 default:
2570 return EINVAL;
2571 }
2572 break;
2573
2574 case BT848_GCAPAREA:
2575 cap = (struct bktr_capture_area *)ap->a_data;
2576 memset (cap, 0, sizeof (*cap));
2577 cap->x_offset = 0;
2578 cap->y_offset = 0;
2579 cap->x_size = sc->profile->width;
2580 cap->y_size = sc->profile->height;
2581 break;
2582
2583 case BT848_SCAPAREA:
2584 if (sc->encoding)
2585 return EBUSY;
2586
2587 cap = (struct bktr_capture_area *)ap->a_data;
2588 if (cap->x_offset || cap->y_offset
2589 || (cap->x_size % CXM_MACROBLOCK_WIDTH)
2590 || (cap->y_size % CXM_MACROBLOCK_HEIGHT))
2591 return EINVAL;
2592
2593 /*
2594 * Setting the width and height has the side effect of
2595 * chosing between the VCD, SVCD, and DVD profiles.
2596 */
2597
2598 for (i = 0; i < NUM_ELEMENTS(codec_profiles); i++)
2599 if (codec_profiles[i]->width == cap->x_size
2600 && codec_profiles[i]->height == cap->y_size)
2601 break;
2602
2603 if (i >= NUM_ELEMENTS(codec_profiles))
2604 return EINVAL;
2605
2606 sc->profile = codec_profiles[i];
2607 break;
2608
2609 case BT848GFMT:
2610 switch (cxm_saa7115_detected_format(sc)) {
2611 case cxm_ntsc_60hz_source_format:
2612 *(unsigned long *)ap->a_data = BT848_IFORM_F_NTSCM;
2613 break;
2614
2615 case cxm_pal_50hz_source_format:
2616 *(unsigned long *)ap->a_data = BT848_IFORM_F_PALBDGHI;
2617 break;
2618
2619 case cxm_secam_50hz_source_format:
2620 *(unsigned long *)ap->a_data = BT848_IFORM_F_SECAM;
2621 break;
2622
2623 case cxm_pal_60hz_source_format:
2624 *(unsigned long *)ap->a_data = BT848_IFORM_F_PALM;
2625 break;
2626
2627 case cxm_bw_50hz_source_format:
2628 case cxm_bw_60hz_source_format:
2629 case cxm_ntsc_50hz_source_format:
2630 *(unsigned long *)ap->a_data = BT848_IFORM_F_AUTO;
2631 break;
2632
2633 default:
2634 return ENXIO;
2635 }
2636 break;
2637
2638 case METEORGFMT:
2639 switch (cxm_saa7115_detected_format(sc)) {
2640 case cxm_ntsc_60hz_source_format:
2641 *(unsigned long *)ap->a_data = METEOR_FMT_NTSC;
2642 break;
2643
2644 case cxm_pal_50hz_source_format:
2645 *(unsigned long *)ap->a_data = METEOR_FMT_PAL;
2646 break;
2647
2648 case cxm_secam_50hz_source_format:
2649 *(unsigned long *)ap->a_data = METEOR_FMT_SECAM;
2650 break;
2651
2652 case cxm_bw_50hz_source_format:
2653 case cxm_bw_60hz_source_format:
2654 case cxm_ntsc_50hz_source_format:
2655 case cxm_pal_60hz_source_format:
2656 *(unsigned long *)ap->a_data = METEOR_FMT_AUTOMODE;
2657 break;
2658
2659 default:
2660 return ENXIO;
2661 }
2662 break;
2663
2664 case METEORGFPS:
2665 fps = cxm_saa7115_detected_fps(sc);
2666
2667 if (fps < 0)
2668 return ENXIO;
2669
2670 *(unsigned short *)ap->a_data = fps;
2671 break;
2672
2673 case METEORGINPUT:
2674 switch (sc->source) {
2675 case cxm_tuner_source:
2676 *(unsigned long *)ap->a_data = METEOR_INPUT_DEV1;
2677 break;
2678
2679 case cxm_line_in_source_composite:
2680 *(unsigned long *)ap->a_data = METEOR_INPUT_DEV2;
2681 break;
2682
2683 case cxm_line_in_source_svideo:
2684 *(unsigned long *)ap->a_data = METEOR_INPUT_DEV_SVIDEO;
2685 break;
2686
2687 default:
2688 return ENXIO;
2689 }
2690 break;
2691
2692 case METEORSINPUT:
2693 source = cxm_unknown_source;
2694
2695 switch (*(unsigned long *)ap->a_data & 0xf000) {
2696 case METEOR_INPUT_DEV1:
2697 source = cxm_tuner_source;
2698 break;
2699
2700 case METEOR_INPUT_DEV2:
2701 source = cxm_line_in_source_composite;
2702 break;
2703
2704 case METEOR_INPUT_DEV_SVIDEO:
2705 source = cxm_line_in_source_svideo;
2706 break;
2707
2708 default:
2709 return EINVAL;
2710 }
2711
2712 if (sc->encoding) {
2713
2714 /*
2715 * Switching between audio + video and audio only
2716 * subtypes isn't supported while encoding.
2717 */
2718
2719 if (source != sc->source
2720 && (source == cxm_fm_source
2721 || sc->source == cxm_fm_source))
2722 return EBUSY;
2723 }
2724
2725 if (cxm_pause_encoder(sc) < 0)
2726 return ENXIO;
2727
2728 if (cxm_saa7115_select_source(sc, source) < 0)
2729 return ENXIO;
2730 if (cxm_msp_select_source(sc, source) < 0)
2731 return ENXIO;
2732 sc->source = source;
2733
2734 result = cxm_encoder_wait_for_lock(sc);
2735 if (result < 0)
2736 return ENXIO;
2737 else if (result == 0)
2738 return EINVAL;
2739
2740 if (cxm_unpause_encoder(sc) < 0)
2741 return ENXIO;
2742 break;
2743
2744 case METEORGSIGNAL:
2745 *(unsigned int *)ap->a_data = sc->enc_signal;
2746 break;
2747
2748 case METEORSSIGNAL:
2749 sig = *(unsigned int *)ap->a_data;
2750
2751 if (!_SIG_VALID(sig))
2752 return EINVAL;
2753
2754 /*
2755 * Historically, applications used METEOR_SIG_MODE_MASK
2756 * to reset signal delivery.
2757 */
2758 if (sig == METEOR_SIG_MODE_MASK)
2759 sig = 0;
2760
2761 crit_enter();
2762 sc->enc_proc = sig ? curproc : NULL;
2763 sc->enc_signal = sig;
2764 crit_exit();
2765 break;
2766
2767 case RADIO_GETFREQ:
2768 /* Convert from kHz to MHz * 100 */
2769 freq = sc->tuner_freq / 10;
2770
2771 *(unsigned int *)ap->a_data = freq;
2772 break;
2773
2774 case RADIO_SETFREQ:
2775 if (sc->source == cxm_fm_source)
2776 if (cxm_pause_encoder(sc) < 0)
2777 return ENXIO;
2778
2779 /* Convert from MHz * 100 to kHz */
2780 freq = *(unsigned int *)ap->a_data * 10;
2781
2782 if (cxm_tuner_select_frequency(sc, cxm_tuner_fm_freq_type,
2783 freq) < 0)
2784 return ENXIO;
2785
2786 /*
2787 * Explicitly wait for the tuner lock so we
2788 * can indicate if there's a station present.
2789 */
2790 if (cxm_tuner_wait_for_lock(sc) < 0)
2791 return EINVAL;
2792
2793 result = cxm_encoder_wait_for_lock(sc);
2794 if (result < 0)
2795 return ENXIO;
2796 else if (result == 0)
2797 return EINVAL;
2798
2799 if (sc->source == cxm_fm_source)
2800 if (cxm_unpause_encoder(sc) < 0)
2801 return ENXIO;
2802 break;
2803
2804 case TVTUNER_GETAFC:
2805 *(int *)ap->a_data = sc->tuner_afc;
2806 break;
2807
2808 case TVTUNER_SETAFC:
2809 sc->tuner_afc = (*(int *)ap->a_data != 0);
2810 break;
2811
2812 case TVTUNER_GETTYPE:
2813 *(unsigned int *)ap->a_data = cxm_tuner_selected_channel_set(sc);
2814 break;
2815
2816 case TVTUNER_SETTYPE:
2817 if (cxm_tuner_select_channel_set(sc, *(unsigned int *)ap->a_data) < 0)
2818 return EINVAL;
2819 break;
2820
2821 case TVTUNER_SETCHNL:
2822 if (sc->source == cxm_tuner_source)
2823 if (cxm_pause_encoder(sc) < 0)
2824 return ENXIO;
2825
2826 if (cxm_tuner_select_channel(sc, *(unsigned int *)ap->a_data) < 0)
2827 return ENXIO;
2828
2829 if (sc->tuner_afc)
2830 if (cxm_tuner_apply_afc(sc) < 0)
2831 return EINVAL;
2832
2833 /*
2834 * Explicitly wait for the tuner lock so we
2835 * can indicate if there's a station present.
2836 */
2837 if (cxm_tuner_wait_for_lock(sc) < 0)
2838 return EINVAL;
2839
2840 result = cxm_encoder_wait_for_lock(sc);
2841 if (result < 0)
2842 return ENXIO;
2843 else if (result == 0)
2844 return EINVAL;
2845
2846 if (sc->source == cxm_tuner_source)
2847 if (cxm_unpause_encoder(sc) < 0)
2848 return ENXIO;
2849 break;
2850
2851 case TVTUNER_GETFREQ:
2852 /* Convert from kHz to MHz * 16 */
2853 freq = (sc->tuner_freq * 16) / 1000;
2854
2855 *(unsigned int *)ap->a_data = freq;
2856 break;
2857
2858 case TVTUNER_SETFREQ:
2859 if (sc->source == cxm_tuner_source)
2860 if (cxm_pause_encoder(sc) < 0)
2861 return ENXIO;
2862
2863 /* Convert from MHz * 16 to kHz */
2864 freq = (*(unsigned int *)ap->a_data * 1000) / 16;
2865
2866 if (cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type,
2867 freq) < 0)
2868 return ENXIO;
2869
2870 /*
2871 * Explicitly wait for the tuner lock so we
2872 * can indicate if there's a station present.
2873 */
2874 if (cxm_tuner_wait_for_lock(sc) < 0)
2875 return EINVAL;
2876
2877 result = cxm_encoder_wait_for_lock(sc);
2878 if (result < 0)
2879 return ENXIO;
2880 else if (result == 0)
2881 return EINVAL;
2882
2883 if (sc->source == cxm_tuner_source)
2884 if (cxm_unpause_encoder(sc) < 0)
2885 return ENXIO;
2886
2887 break;
2888
2889 case TVTUNER_GETSTATUS:
2890 status = cxm_tuner_status(sc);
2891 if (status < 0)
2892 return ENXIO;
2893 *(unsigned long *)ap->a_data = status & 0xff;
2894 break;
2895
2896 case REMOTE_GETKEY:
2897 remote = (struct bktr_remote *)ap->a_data;
2898 if (cxm_ir_key(sc, (char *)remote, sizeof(*remote)) < 0)
2899 return ENXIO;
2900 break;
2901
2902 default:
2903 return ENOTTY;
2904 }
2905
2906 return 0;
2907}
2908
a8fbdc8b 2909static struct filterops cxm_filterops =
4c91dbc9 2910 { FILTEROP_ISFD, NULL, cxm_filter_detach, cxm_filter };
a8fbdc8b
SG
2911
2912static int
2913cxm_kqfilter(struct dev_kqfilter_args *ap)
2914{
2915 cdev_t dev = ap->a_head.a_dev;
2916 struct knote *kn = ap->a_kn;
2917 struct cxm_softc *sc;
2918 struct klist *klist;
2919 int unit;
2920
2921 ap->a_result = 0;
2922
2923 switch (kn->kn_filter) {
2924 case EVFILT_READ:
2925 unit = UNIT(minor(dev));
2926 /* Get the device data */
2927 sc = (struct cxm_softc *)devclass_get_softc(cxm_devclass, unit);
2928 kn->kn_fop = &cxm_filterops;
2929 kn->kn_hook = (caddr_t)sc;
2930 break;
2931 default:
b287d649 2932 ap->a_result = EOPNOTSUPP;
a8fbdc8b
SG
2933 return (0);
2934 }
2935
5b22f1a7
SG
2936 klist = &sc->enc_kq.ki_note;
2937 knote_insert(klist, kn);
a8fbdc8b
SG
2938
2939 return (0);
2940}
2941
2942static void
2943cxm_filter_detach(struct knote *kn)
2944{
2945 struct cxm_softc *sc = (struct cxm_softc *)kn->kn_hook;
5b22f1a7 2946 struct klist *klist = &sc->enc_kq.ki_note;
a8fbdc8b 2947
5b22f1a7 2948 knote_remove(klist, kn);
a8fbdc8b
SG
2949}
2950
2951static int
2952cxm_filter(struct knote *kn, long hint)
2953{
2954 struct cxm_softc *sc = (struct cxm_softc *)kn->kn_hook;
2955 int ready = 0;
2956
2957 if (sc == NULL) {
2958 /* the device is no longer valid/functioning */
2959 kn->kn_flags |= EV_EOF;
2960 return (1);
2961 }
2962
2963 crit_enter();
2964 if (sc->enc_pool.read != sc->enc_pool.write)
2965 ready = 1;
2966 crit_exit();
2967
2968 return (ready);
2969}