kernel: Replace struct device* by device_t
[dragonfly.git] / sys / dev / video / cxm / cxm.c
blobd3b2cd8e329853951b711acc29747b42e7400303
1 /*
2 * Copyright (c) 2003, 2004, 2005
3 * John Wehle <john@feith.com>. All rights reserved.
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.
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.
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.
37 * This driver was written using the invaluable information
38 * compiled by The IvyTV Project (ivtv.sourceforge.net).
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>
48 #include <sys/event.h>
49 #include <sys/proc.h>
50 #include <sys/signalvar.h>
51 #include <sys/thread2.h>
52 #include <sys/vnode.h>
53 #include <sys/resource.h>
54 #include <sys/bus.h>
55 #include <sys/rman.h>
57 #include <machine/clock.h>
59 #include <dev/video/meteor/ioctl_meteor.h>
60 #include <dev/video/bktr/ioctl_bt848.h>
62 #include <bus/pci/pcireg.h>
63 #include <bus/pci/pcivar.h>
65 #include <dev/video/cxm/cxm.h>
67 #include <bus/iicbus/iiconf.h>
70 * Various supported device vendors/types and their names.
72 static 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 }
81 static int cxm_probe(device_t dev);
82 static int cxm_attach(device_t dev);
83 static int cxm_detach(device_t dev);
84 static int cxm_shutdown(device_t dev);
85 static void cxm_intr(void *arg);
87 static void cxm_child_detached(device_t dev, device_t child);
88 static int cxm_read_ivar(device_t bus, device_t dev,
89 int index, uintptr_t* val);
90 static int cxm_write_ivar(device_t bus, device_t dev,
91 int index, uintptr_t val);
94 static 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),
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),
108 DEVMETHOD_END
111 static driver_t cxm_driver = {
112 "cxm",
113 cxm_methods,
114 sizeof(struct cxm_softc),
117 static devclass_t cxm_devclass;
119 static d_open_t cxm_open;
120 static d_close_t cxm_close;
121 static d_read_t cxm_read;
122 static d_ioctl_t cxm_ioctl;
123 static d_kqfilter_t cxm_kqfilter;
125 static void cxm_filter_detach(struct knote *);
126 static int cxm_filter(struct knote *, long);
128 static struct dev_ops cxm_ops = {
129 { "cxm", 0, 0 },
130 .d_open = cxm_open,
131 .d_close = cxm_close,
132 .d_read = cxm_read,
133 .d_ioctl = cxm_ioctl,
134 .d_kqfilter = cxm_kqfilter
137 MODULE_DEPEND(cxm, cxm_iic, 1, 1, 1);
138 DRIVER_MODULE(cxm, pci, cxm_driver, cxm_devclass, NULL, NULL);
141 static struct cxm_codec_audio_format codec_audio_formats[] = {
142 { 44100, 0xb8 }, /* 44.1 Khz, MPEG-1 Layer II, 224 kb/s */
143 { 48000, 0xe9 } /* 48 Khz, MPEG-1 Layer II, 384 kb/s */
148 * Various profiles.
150 static struct cxm_codec_profile vcd_ntsc_profile = {
151 "MPEG-1 VideoCD NTSC video and MPEG audio",
152 CXM_FW_STREAM_TYPE_VCD,
154 352, 240, 480,
155 { 10, 12, 21 },
158 { 1, 1150000, 0 },
159 { 1, 15, 3},
161 * Spatial filter = Manual, Temporal filter = Manual
162 * Median filter = Horizontal / Vertical
163 * Spatial filter value = 1, Temporal filter value = 4
165 { 0, 3, 1, 4 },
166 44100
169 static struct cxm_codec_profile vcd_pal_profile = {
170 "MPEG-1 VideoCD PAL video and MPEG audio",
171 CXM_FW_STREAM_TYPE_VCD,
173 352, 288, 576,
174 { 6, 17, 22 },
177 { 1, 1150000, 0 },
178 { 1, 12, 3},
180 * Spatial filter = Manual, Temporal filter = Manual
181 * Median filter = Horizontal / Vertical
182 * Spatial filter value = 1, Temporal filter value = 4
184 { 0, 3, 1, 4 },
185 44100
188 static struct cxm_codec_profile svcd_ntsc_profile = {
189 "MPEG-2 SuperVCD NTSC video and MPEG audio",
190 CXM_FW_STREAM_TYPE_SVCD,
192 480, 480, 480,
193 { 10, 12, 21 },
196 /* 2.5 Mb/s peak limit to keep bbdmux followed by mplex -f 4 happy */
197 { 0, 1150000, 2500000 },
198 { 1, 15, 3},
200 * Spatial filter = Manual, Temporal filter = Manual
201 * Median filter = Horizontal / Vertical
202 * Spatial filter value = 1, Temporal filter value = 4
204 { 0, 3, 1, 4 },
205 44100
208 static struct cxm_codec_profile svcd_pal_profile = {
209 "MPEG-2 SuperVCD PAL video and MPEG audio",
210 CXM_FW_STREAM_TYPE_SVCD,
212 480, 576, 576,
213 { 6, 17, 22 },
216 /* 2.5 Mb/s peak limit to keep bbdmux followed by mplex -f 4 happy */
217 { 0, 1150000, 2500000 },
218 { 1, 12, 3},
220 * Spatial filter = Manual, Temporal filter = Manual
221 * Median filter = Horizontal / Vertical
222 * Spatial filter value = 1, Temporal filter value = 4
224 { 0, 3, 1, 4 },
225 44100
228 static struct cxm_codec_profile dvd_half_d1_ntsc_profile = {
229 "MPEG-2 DVD NTSC video and MPEG audio",
230 CXM_FW_STREAM_TYPE_DVD,
232 352, 480, 480,
233 { 10, 12, 21 },
236 { 0, 4000000, 4520000 }, /* 4 hours on 8.54 GB media */
237 { 1, 15, 3},
239 * Spatial filter = Manual, Temporal filter = Manual
240 * Median filter = Horizontal / Vertical
241 * Spatial filter value = 1, Temporal filter value = 4
243 { 0, 3, 1, 4 },
244 48000
247 static struct cxm_codec_profile dvd_half_d1_pal_profile = {
248 "MPEG-2 DVD PAL video and MPEG audio",
249 CXM_FW_STREAM_TYPE_DVD,
251 352, 576, 576,
252 { 6, 17, 22 },
255 { 0, 4000000, 4520000 }, /* 4 hours on 8.54 GB media */
256 { 1, 12, 3},
258 * Spatial filter = Manual, Temporal filter = Manual
259 * Median filter = Horizontal / Vertical
260 * Spatial filter value = 1, Temporal filter value = 4
262 { 0, 3, 1, 4 },
263 48000
266 static struct cxm_codec_profile dvd_full_d1_ntsc_profile = {
267 "MPEG-2 DVD NTSC video and MPEG audio",
268 CXM_FW_STREAM_TYPE_DVD,
270 720, 480, 480,
271 { 10, 12, 21 },
274 /* 9.52 Mb/s peak limit to keep bbdmux followed by mplex -f 8 happy */
275 { 0, 9000000, 9520000 }, /* 1 hour on 4.7 GB media */
276 { 1, 15, 3},
278 * Spatial filter = Manual, Temporal filter = Manual
279 * Median filter = Horizontal / Vertical
280 * Spatial filter value = 1, Temporal filter value = 4
282 { 0, 3, 1, 4 },
283 48000
286 static struct cxm_codec_profile dvd_full_d1_pal_profile = {
287 "MPEG-2 DVD PAL video and MPEG audio",
288 CXM_FW_STREAM_TYPE_DVD,
290 720, 576, 576,
291 { 6, 17, 22 },
294 /* 9.52 Mb/s peak limit to keep bbdmux followed by mplex -f 8 happy */
295 { 0, 9000000, 9520000 }, /* 1 hour on 4.7 GB media */
296 { 1, 12, 3},
298 * Spatial filter = Manual, Temporal filter = Manual
299 * Median filter = Horizontal / Vertical
300 * Spatial filter value = 1, Temporal filter value = 4
302 { 0, 3, 1, 4 },
303 48000
307 static const struct cxm_codec_profile
308 *codec_profiles[] = {
309 &vcd_ntsc_profile,
310 &vcd_pal_profile,
311 &svcd_ntsc_profile,
312 &svcd_pal_profile,
313 &dvd_half_d1_ntsc_profile,
314 &dvd_half_d1_pal_profile,
315 &dvd_full_d1_ntsc_profile,
316 &dvd_full_d1_pal_profile
320 static unsigned int
321 cxm_queue_firmware_command(struct cxm_softc *sc,
322 enum cxm_mailbox_name mbx_name, uint32_t cmd,
323 uint32_t *parameters, unsigned int nparameters)
325 unsigned int i;
326 unsigned int mailbox;
327 uint32_t completed_command;
328 uint32_t flags;
330 if (nparameters > CXM_MBX_MAX_PARAMETERS) {
331 device_printf(sc->dev, "too many parameters for mailbox\n");
332 return -1;
335 mailbox = 0;
337 switch (mbx_name) {
338 case cxm_dec_mailbox:
339 mailbox = sc->dec_mbx
340 + CXM_MBX_FW_CMD_MAILBOX *sizeof(struct cxm_mailbox);
341 break;
343 case cxm_enc_mailbox:
344 mailbox = sc->enc_mbx
345 + CXM_MBX_FW_CMD_MAILBOX *sizeof(struct cxm_mailbox);
346 break;
348 default:
349 return -1;
352 crit_enter();
353 for (i = 0; i < CXM_MBX_FW_CMD_MAILBOXES; i++) {
354 flags = CSR_READ_4(sc,
355 mailbox
356 + offsetof(struct cxm_mailbox, flags));
357 if (!(flags & CXM_MBX_FLAG_IN_USE))
358 break;
361 * Mail boxes containing certain completed commands
362 * for which the results are never needed can be reused.
365 if ((flags & (CXM_MBX_FLAG_DRV_DONE | CXM_MBX_FLAG_FW_DONE))
366 == (CXM_MBX_FLAG_DRV_DONE | CXM_MBX_FLAG_FW_DONE)) {
367 completed_command
368 = CSR_READ_4(sc,
369 mailbox
370 + offsetof(struct cxm_mailbox, command));
373 * DMA results are always check by reading the
374 * DMA status register ... never by checking
375 * the mailbox after the command has completed.
378 if (completed_command == CXM_FW_CMD_SCHED_DMA_TO_HOST)
379 break;
382 mailbox += sizeof(struct cxm_mailbox);
385 if (i >= CXM_MBX_FW_CMD_MAILBOXES) {
386 crit_exit();
387 return -1;
390 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags),
391 CXM_MBX_FLAG_IN_USE);
394 * PCI writes may be buffered so force the
395 * write to complete by reading the last
396 * location written.
399 CSR_READ_4(sc, mailbox + offsetof(struct cxm_mailbox, flags));
401 crit_exit();
403 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, command), cmd);
404 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, timeout),
405 CXM_FW_STD_TIMEOUT);
407 for (i = 0; i < nparameters; i++)
408 CSR_WRITE_4(sc,
409 mailbox
410 + offsetof(struct cxm_mailbox, parameters)
411 + i * sizeof(uint32_t),
412 *(parameters + i));
414 for (; i < CXM_MBX_MAX_PARAMETERS; i++)
415 CSR_WRITE_4(sc,
416 mailbox
417 + offsetof(struct cxm_mailbox, parameters)
418 + i * sizeof(uint32_t), 0);
420 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags),
421 CXM_MBX_FLAG_IN_USE | CXM_MBX_FLAG_DRV_DONE);
423 return mailbox;
427 static int
428 cxm_firmware_command(struct cxm_softc *sc,
429 enum cxm_mailbox_name mbx_name, uint32_t cmd,
430 uint32_t *parameters, unsigned int nparameters)
432 const char *wmesg;
433 unsigned int *bmp;
434 unsigned int i;
435 unsigned int mailbox;
436 uint32_t flags;
437 uint32_t result;
439 bmp = NULL;
440 wmesg = "";
442 switch (mbx_name) {
443 case cxm_dec_mailbox:
444 bmp = &sc->dec_mbx;
445 wmesg = "cxmdfw";
446 break;
448 case cxm_enc_mailbox:
449 bmp = &sc->enc_mbx;
450 wmesg = "cxmefw";
451 break;
453 default:
454 return -1;
457 mailbox = cxm_queue_firmware_command(sc, mbx_name, cmd,
458 parameters, nparameters);
459 if (mailbox == -1) {
460 device_printf(sc->dev, "no free mailboxes\n");
461 return -1;
464 /* Give the firmware a chance to start processing the request */
465 tsleep(bmp, 0, wmesg, hz / 100);
467 for (i = 0; i < 100; i++) {
468 flags = CSR_READ_4(sc,
469 mailbox
470 + offsetof(struct cxm_mailbox, flags));
471 if ((flags & CXM_MBX_FLAG_FW_DONE))
472 break;
474 /* Wait for 10ms */
475 tsleep(bmp, 0, wmesg, hz / 100);
478 if (i >= 100) {
479 device_printf(sc->dev, "timeout\n");
480 return -1;
483 result = CSR_READ_4(sc,
484 mailbox
485 + offsetof(struct cxm_mailbox, result));
487 for (i = 0; i < nparameters; i++)
488 *(parameters + i)
489 = CSR_READ_4(sc,
490 mailbox
491 + offsetof(struct cxm_mailbox, parameters)
492 + i * sizeof(uint32_t));
494 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags), 0);
496 return result == 0 ? 0 : -1;
500 static int
501 cxm_firmware_command_nosleep(struct cxm_softc *sc,
502 enum cxm_mailbox_name mbx_name, uint32_t cmd,
503 uint32_t *parameters, unsigned int nparameters)
505 unsigned int i;
506 unsigned int mailbox;
507 uint32_t flags;
508 uint32_t result;
510 for (i = 0; i < 100; i++) {
511 mailbox = cxm_queue_firmware_command(sc, mbx_name, cmd,
512 parameters, nparameters);
513 if (mailbox != -1)
514 break;
516 /* Wait for 10ms */
517 DELAY(10000);
520 if (i >= 100) {
521 device_printf(sc->dev, "no free mailboxes\n");
522 return -1;
525 /* Give the firmware a chance to start processing the request */
526 DELAY(10000);
528 for (i = 0; i < 100; i++) {
529 flags = CSR_READ_4(sc,
530 mailbox
531 + offsetof(struct cxm_mailbox, flags));
532 if ((flags & CXM_MBX_FLAG_FW_DONE))
533 break;
535 /* Wait for 10ms */
536 DELAY(10000);
539 if (i >= 100) {
540 device_printf(sc->dev, "timeout\n");
541 return -1;
544 result = CSR_READ_4(sc,
545 mailbox
546 + offsetof(struct cxm_mailbox, result));
548 for (i = 0; i < nparameters; i++)
549 *(parameters + i)
550 = CSR_READ_4(sc,
551 mailbox
552 + offsetof(struct cxm_mailbox, parameters)
553 + i * sizeof(uint32_t));
555 CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags), 0);
557 return result == 0 ? 0 : -1;
561 static int
562 cxm_stop_firmware(struct cxm_softc *sc)
565 if (cxm_firmware_command_nosleep(sc, cxm_enc_mailbox,
566 CXM_FW_CMD_ENC_HALT_FW, NULL, 0) < 0)
567 return -1;
569 if (sc->type == cxm_iTVC15_type
570 && cxm_firmware_command_nosleep(sc, cxm_dec_mailbox,
571 CXM_FW_CMD_DEC_HALT_FW,
572 NULL, 0) < 0)
573 return -1;
575 /* Wait for 10ms */
576 DELAY(10000);
578 return 0;
582 static void
583 cxm_set_irq_mask(struct cxm_softc *sc, uint32_t mask)
585 crit_enter();
587 CSR_WRITE_4(sc, CXM_REG_IRQ_MASK, mask);
590 * PCI writes may be buffered so force the
591 * write to complete by reading the last
592 * location written.
595 CSR_READ_4(sc, CXM_REG_IRQ_MASK);
597 sc->irq_mask = mask;
599 crit_exit();
603 static void
604 cxm_set_irq_status(struct cxm_softc *sc, uint32_t status)
607 CSR_WRITE_4(sc, CXM_REG_IRQ_STATUS, status);
610 * PCI writes may be buffered so force the
611 * write to complete by reading the last
612 * location written.
615 CSR_READ_4(sc, CXM_REG_IRQ_STATUS);
619 static int
620 cxm_stop_hardware(struct cxm_softc *sc)
622 if (sc->cxm_iic) {
623 if (cxm_saa7115_mute(sc) < 0)
624 return -1;
625 if (cxm_msp_mute(sc) < 0)
626 return -1;
629 /* Halt the firmware */
630 if (sc->enc_mbx != -1) {
631 if (cxm_stop_firmware(sc) < 0)
632 return -1;
635 /* Mask all interrupts */
636 cxm_set_irq_mask(sc, 0xffffffff);
638 /* Stop VDM */
639 CSR_WRITE_4(sc, CXM_REG_VDM, CXM_CMD_VDM_STOP);
641 /* Stop AO */
642 CSR_WRITE_4(sc, CXM_REG_AO, CXM_CMD_AO_STOP);
644 /* Ping (?) APU */
645 CSR_WRITE_4(sc, CXM_REG_APU, CXM_CMD_APU_PING);
647 /* Stop VPU */
648 CSR_WRITE_4(sc, CXM_REG_VPU, sc->type == cxm_iTVC15_type
649 ? CXM_CMD_VPU_STOP15
650 : CXM_CMD_VPU_STOP16);
652 /* Reset Hw Blocks */
653 CSR_WRITE_4(sc, CXM_REG_HW_BLOCKS, CXM_CMD_HW_BLOCKS_RST);
655 /* Stop SPU */
656 CSR_WRITE_4(sc, CXM_REG_SPU, CXM_CMD_SPU_STOP);
658 /* Wait for 10ms */
659 DELAY(10000);
661 return 0;
665 static int
666 cxm_download_firmware(struct cxm_softc *sc)
668 unsigned int i;
669 const uint32_t *fw;
671 /* Check if firmware is compiled in */
672 if (strncmp((const char *)cxm_enc_fw, "NOFW", 4) == 0) {
673 device_printf(sc->dev, "encoder firmware not compiled in\n");
674 return -1;
675 } else if (strncmp((const char *)cxm_dec_fw, "NOFW", 4) == 0) {
676 device_printf(sc->dev, "decoder firmware not compiled in\n");
677 return -1;
680 /* Download the encoder firmware */
681 fw = (const uint32_t *)cxm_enc_fw;
682 for (i = 0; i < CXM_FW_SIZE; i += sizeof(*fw))
683 CSR_WRITE_4(sc, CXM_MEM_ENC + i, *fw++);
685 /* Download the decoder firmware */
686 if (sc->type == cxm_iTVC15_type) {
687 fw = (const uint32_t *)cxm_dec_fw;
688 for (i = 0; i < CXM_FW_SIZE; i += sizeof(*fw))
689 CSR_WRITE_4(sc, CXM_MEM_DEC + i, *fw++);
692 return 0;
696 static int
697 cxm_init_hardware(struct cxm_softc *sc)
699 unsigned int i;
700 unsigned int mailbox;
701 uint32_t parameter;
703 if (cxm_stop_hardware(sc) < 0)
704 return -1;
706 /* Initialize encoder SDRAM pre-charge */
707 CSR_WRITE_4(sc, CXM_REG_ENC_SDRAM_PRECHARGE,
708 CXM_CMD_SDRAM_PRECHARGE_INIT);
710 /* Initialize encoder SDRAM refresh to 1us */
711 CSR_WRITE_4(sc, CXM_REG_ENC_SDRAM_REFRESH,
712 CXM_CMD_SDRAM_REFRESH_INIT);
714 /* Initialize decoder SDRAM pre-charge */
715 CSR_WRITE_4(sc, CXM_REG_DEC_SDRAM_PRECHARGE,
716 CXM_CMD_SDRAM_PRECHARGE_INIT);
718 /* Initialize decoder SDRAM refresh to 1us */
719 CSR_WRITE_4(sc, CXM_REG_DEC_SDRAM_REFRESH,
720 CXM_CMD_SDRAM_REFRESH_INIT);
722 /* Wait for 600ms */
723 DELAY(600000);
725 if (cxm_download_firmware(sc) < 0)
726 return -1;
728 /* Enable SPU */
729 CSR_WRITE_4(sc, CXM_REG_SPU,
730 CSR_READ_4(sc, CXM_REG_SPU) & CXM_MASK_SPU_ENABLE);
732 /* Wait for 1 second */
733 DELAY(1000000);
735 /* Enable VPU */
736 CSR_WRITE_4(sc, CXM_REG_VPU,
737 CSR_READ_4(sc, CXM_REG_VPU)
738 & (sc->type == cxm_iTVC15_type
739 ? CXM_MASK_VPU_ENABLE15
740 : CXM_MASK_VPU_ENABLE16));
742 /* Wait for 1 second */
743 DELAY(1000000);
745 /* Locate encoder mailbox */
746 mailbox = CXM_MEM_ENC;
747 for (i = 0; i < CXM_MEM_ENC_SIZE; i += 0x100)
748 if (CSR_READ_4(sc, mailbox + i) == 0x12345678
749 && CSR_READ_4(sc, mailbox + i + 4) == 0x34567812
750 && CSR_READ_4(sc, mailbox + i + 8) == 0x56781234
751 && CSR_READ_4(sc, mailbox + i + 12) == 0x78123456)
752 break;
754 if (i >= CXM_MEM_ENC_SIZE)
755 return -1;
757 sc->enc_mbx = mailbox + i + 16;
759 /* Locate decoder mailbox */
760 if (sc->type == cxm_iTVC15_type) {
761 mailbox = CXM_MEM_DEC;
762 for (i = 0; i < CXM_MEM_DEC_SIZE; i += 0x100)
763 if (CSR_READ_4(sc, mailbox + i) == 0x12345678
764 && CSR_READ_4(sc, mailbox + i + 4) == 0x34567812
765 && CSR_READ_4(sc, mailbox + i + 8) == 0x56781234
766 && CSR_READ_4(sc, mailbox + i + 12) == 0x78123456)
767 break;
769 if (i >= CXM_MEM_DEC_SIZE)
770 return -1;
772 sc->dec_mbx = mailbox + i + 16;
775 /* Get encoder firmware version */
776 parameter = 0;
777 if (cxm_firmware_command_nosleep(sc, cxm_enc_mailbox,
778 CXM_FW_CMD_ENC_GET_FW_VER,
779 &parameter, 1) < 0)
780 return -1;
782 device_printf(sc->dev, "encoder firmware version %#x\n",
783 (unsigned int)parameter);
785 /* Get decoder firmware version */
786 if (sc->type == cxm_iTVC15_type) {
787 parameter = 0;
788 if (cxm_firmware_command_nosleep(sc, cxm_dec_mailbox,
789 CXM_FW_CMD_DEC_GET_FW_VER,
790 &parameter, 1) < 0)
791 return -1;
793 device_printf(sc->dev, "decoder firmware version %#x\n",
794 (unsigned int)parameter);
797 return 0;
801 static int
802 cxm_configure_encoder(struct cxm_softc *sc)
804 int fps;
805 unsigned int i;
806 uint32_t parameters[12];
807 const struct cxm_codec_profile *cpp;
809 if (sc->source == cxm_fm_source)
810 switch (cxm_tuner_selected_channel_set(sc)) {
811 case CHNLSET_NABCST:
812 case CHNLSET_CABLEIRC:
813 case CHNLSET_JPNBCST:
814 case CHNLSET_JPNCABLE:
815 fps = 30;
816 break;
818 default:
819 fps = 25;
820 break;
822 else
823 fps = cxm_saa7115_detected_fps(sc);
825 if (fps < 0)
826 return -1;
828 if (sc->profile->fps != fps) {
831 * Pick a profile with the correct fps using the
832 * chosen stream type and width to decide between
833 * the VCD, SVCD, or DVD profiles.
836 for (i = 0; i < NUM_ELEMENTS(codec_profiles); i++)
837 if (codec_profiles[i]->fps == fps
838 && codec_profiles[i]->stream_type
839 == sc->profile->stream_type
840 && codec_profiles[i]->width == sc->profile->width)
841 break;
843 if (i >= NUM_ELEMENTS(codec_profiles))
844 return -1;
846 sc->profile = codec_profiles[i];
849 cpp = sc->profile;
851 if (cxm_saa7115_configure(sc,
852 cpp->width, cpp->source_height, fps,
853 cpp->audio_sample_rate) < 0)
854 return -1;
856 /* assign dma block len */
857 parameters[0] = 1; /* Transfer block size = 1 */
858 parameters[1] = 1; /* Units = 1 (frames) */
859 if (cxm_firmware_command(sc, cxm_enc_mailbox,
860 CXM_FW_CMD_ASSIGN_DMA_BLOCKLEN,
861 parameters, 2) != 0)
862 return -1;
865 /* assign program index info */
866 parameters[0] = 0; /* Picture mask = 0 (don't generate index) */
867 parameters[1] = 0; /* Num_req = 0 */
868 if (cxm_firmware_command(sc, cxm_enc_mailbox,
869 CXM_FW_CMD_ASSIGN_PGM_INDEX_INFO,
870 parameters, 2) != 0)
871 return -1;
873 /* assign stream type */
874 parameters[0] = cpp->stream_type;
875 if (cxm_firmware_command(sc, cxm_enc_mailbox,
876 CXM_FW_CMD_ASSIGN_STREAM_TYPE,
877 parameters, 1) != 0)
878 return -1;
880 /* assign output port */
881 parameters[0] = 0; /* 0 (Memory) */
882 if (cxm_firmware_command(sc, cxm_enc_mailbox,
883 CXM_FW_CMD_ASSIGN_OUTPUT_PORT,
884 parameters, 1) != 0)
885 return -1;
887 /* assign framerate */
888 parameters[0] = cpp->fps == 30 ? 0 : 1;
889 if (cxm_firmware_command(sc, cxm_enc_mailbox,
890 CXM_FW_CMD_ASSIGN_FRAME_RATE,
891 parameters, 1) != 0)
892 return -1;
894 /* assign frame size */
895 parameters[0] = cpp->height;
896 parameters[1] = cpp->width;
897 if (cxm_firmware_command(sc, cxm_enc_mailbox,
898 CXM_FW_CMD_ASSIGN_FRAME_SIZE,
899 parameters, 2) != 0)
900 return -1;
902 /* assign aspect ratio */
903 parameters[0] = cpp->aspect;
904 if (cxm_firmware_command(sc, cxm_enc_mailbox,
905 CXM_FW_CMD_ASSIGN_ASPECT_RATIO,
906 parameters, 1) != 0)
907 return -1;
909 /* assign bitrates */
910 parameters[0] = cpp->bitrate.mode;
911 parameters[1] = cpp->bitrate.average;
912 parameters[2] = cpp->bitrate.peak / 400;
913 if (cxm_firmware_command(sc, cxm_enc_mailbox,
914 CXM_FW_CMD_ASSIGN_BITRATES,
915 parameters, 3) != 0)
916 return -1;
918 /* assign gop closure */
919 parameters[0] = cpp->gop.closure;
920 if (cxm_firmware_command(sc, cxm_enc_mailbox,
921 CXM_FW_CMD_ASSIGN_GOP_CLOSURE,
922 parameters, 1) != 0)
923 return -1;
925 /* assign gop properties */
926 parameters[0] = cpp->gop.frames;
927 parameters[1] = cpp->gop.bframes;
928 if (cxm_firmware_command(sc, cxm_enc_mailbox,
929 CXM_FW_CMD_ASSIGN_GOP_PROPERTIES,
930 parameters, 2) != 0)
931 return -1;
933 /* assign 3 2 pulldown */
934 parameters[0] = cpp->pulldown;
935 if (cxm_firmware_command(sc, cxm_enc_mailbox,
936 CXM_FW_CMD_ASSIGN_3_2_PULLDOWN,
937 parameters, 1) != 0)
938 return -1;
940 /* assign dnr filter mode */
941 parameters[0] = cpp->dnr.mode;
942 parameters[1] = cpp->dnr.type;
943 if (cxm_firmware_command(sc, cxm_enc_mailbox,
944 CXM_FW_CMD_ASSIGN_DNR_FILTER_MODE,
945 parameters, 2) != 0)
946 return -1;
948 /* assign dnr filter props */
949 parameters[0] = cpp->dnr.spatial;
950 parameters[1] = cpp->dnr.temporal;
951 if (cxm_firmware_command(sc, cxm_enc_mailbox,
952 CXM_FW_CMD_ASSIGN_DNR_FILTER_PROPERTIES,
953 parameters, 2) != 0)
954 return -1;
957 * assign audio properties
960 for (i = 0; i < NUM_ELEMENTS(codec_audio_formats); i++)
961 if (codec_audio_formats[i].sample_rate
962 == cpp->audio_sample_rate)
963 break;
965 if (i >= NUM_ELEMENTS(codec_audio_formats))
966 return -1;
968 parameters[0] = codec_audio_formats[i].format;
969 if (cxm_firmware_command(sc, cxm_enc_mailbox,
970 CXM_FW_CMD_ASSIGN_AUDIO_PROPERTIES,
971 parameters, 1) != 0)
972 return -1;
974 /* assign coring levels */
975 parameters[0] = 0; /* luma_h */
976 parameters[1] = 255; /* luma_l */
977 parameters[2] = 0; /* chroma_h */
978 parameters[3] = 255; /* chroma_l */
979 if (cxm_firmware_command(sc, cxm_enc_mailbox,
980 CXM_FW_CMD_ASSIGN_CORING_LEVELS,
981 parameters, 4) != 0)
982 return -1;
984 /* assign spatial filter type */
985 parameters[0] = 3; /* Luminance filter = 3 (2D H/V Separable) */
986 parameters[1] = 1; /* Chrominance filter = 1 (1D Horizontal) */
987 if (cxm_firmware_command(sc, cxm_enc_mailbox,
988 CXM_FW_CMD_ASSIGN_SPATIAL_FILTER_TYPE,
989 parameters, 2) != 0)
990 return -1;
992 /* assign frame drop rate */
993 parameters[0] = 0;
994 if (cxm_firmware_command(sc, cxm_enc_mailbox,
995 CXM_FW_CMD_ASSIGN_FRAME_DROP_RATE,
996 parameters, 1) != 0)
997 return -1;
999 /* assign placeholder */
1000 parameters[0] = 0; /* type = 0 (Extension / UserData) */
1001 parameters[1] = 0; /* period */
1002 parameters[2] = 0; /* size_t */
1003 parameters[3] = 0; /* arg0 */
1004 parameters[4] = 0; /* arg1 */
1005 parameters[5] = 0; /* arg2 */
1006 parameters[6] = 0; /* arg3 */
1007 parameters[7] = 0; /* arg4 */
1008 parameters[8] = 0; /* arg5 */
1009 parameters[9] = 0; /* arg6 */
1010 parameters[10] = 0; /* arg7 */
1011 parameters[11] = 0; /* arg8 */
1012 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1013 CXM_FW_CMD_ASSIGN_PLACEHOLDER,
1014 parameters, 12) != 0)
1015 return -1;
1017 /* assign VBI properties */
1018 parameters[0] = 0xbd04; /* mode = 0 (sliced), stream and user data */
1019 parameters[1] = 0; /* frames per interrupt (only valid in raw mode) */
1020 parameters[2] = 0; /* total raw VBI frames (only valid in raw mode) */
1021 parameters[3] = 0x25256262; /* ITU 656 start codes (saa7115 table 24)*/
1022 parameters[4] = 0x38387f7f; /* ITU 656 stop codes (saa7115 table 24) */
1023 parameters[5] = cpp->vbi.nlines; /* lines per frame */
1024 parameters[6] = 1440; /* bytes per line = 720 pixels */
1025 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1026 CXM_FW_CMD_ASSIGN_VBI_PROPERTIES,
1027 parameters, 7) != 0)
1028 return -1;
1030 /* assign VBI lines */
1031 parameters[0] = 0xffffffff; /* all lines */
1032 parameters[1] = 0; /* disable VBI features */
1033 parameters[2] = 0;
1034 parameters[3] = 0;
1035 parameters[4] = 0;
1036 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1037 CXM_FW_CMD_ASSIGN_VBI_LINE,
1038 parameters, 5) != 0)
1039 return -1;
1041 /* assign number of lines in fields 1 and 2 */
1042 parameters[0] = cpp->source_height / 2 + cpp->vbi.nlines;
1043 parameters[1] = cpp->source_height / 2 + cpp->vbi.nlines;
1044 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1045 CXM_FW_CMD_ASSIGN_NUM_VSYNC_LINES,
1046 parameters, 2) != 0)
1047 return -1;
1049 return 0;
1053 static int
1054 cxm_start_encoder(struct cxm_softc *sc)
1056 uint32_t parameters[4];
1057 uint32_t subtype;
1058 uint32_t type;
1061 if (sc->encoding)
1062 return 0;
1064 if (cxm_configure_encoder(sc) < 0)
1065 return -1;
1067 /* Mute the video input if necessary. */
1068 parameters[0] = sc->source == cxm_fm_source ? 1 : 0;
1069 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1070 CXM_FW_CMD_MUTE_VIDEO_INPUT,
1071 parameters, 1) != 0)
1072 return -1;
1074 /* Clear pending encoder interrupts (which are currently masked) */
1075 cxm_set_irq_status(sc, CXM_IRQ_ENC);
1077 /* Enable event notification */
1078 parameters[0] = 0; /* Event = 0 (refresh encoder input) */
1079 parameters[1] = 1; /* Notification = 1 (enable) */
1080 parameters[2] = 0x10000000; /* Interrupt bit */
1081 parameters[3] = -1; /* Mailbox = -1 (no mailbox) */
1082 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1083 CXM_FW_CMD_ENC_EVENT_NOTIFICATION,
1084 parameters, 4) != 0)
1085 return -1;
1087 if (cxm_saa7115_mute(sc) < 0)
1088 return -1;
1089 if (cxm_msp_mute(sc) < 0)
1090 return -1;
1092 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1093 CXM_FW_CMD_INITIALIZE_VIDEO_INPUT,
1094 NULL, 0) < 0)
1095 return -1;
1097 if (cxm_saa7115_unmute(sc) < 0)
1098 return -1;
1099 if (cxm_msp_unmute(sc) < 0)
1100 return -1;
1102 /* Wait for 100ms */
1103 tsleep(&sc->encoding, 0, "cxmce", hz / 10);
1105 type = sc->mpeg ? CXM_FW_CAPTURE_STREAM_TYPE_MPEG
1106 : CXM_FW_CAPTURE_STREAM_TYPE_RAW;
1107 subtype = ((sc->mpeg || sc->source == cxm_fm_source)
1108 ? CXM_FW_CAPTURE_STREAM_PCM_AUDIO : 0)
1109 | ((sc->mpeg || sc->source != cxm_fm_source)
1110 ? CXM_FW_CAPTURE_STREAM_YUV : 0);
1112 /* Start the encoder */
1113 parameters[0] = type;
1114 parameters[1] = subtype;
1115 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1116 CXM_FW_CMD_BEGIN_CAPTURE, parameters, 2) != 0)
1117 return -1;
1119 sc->enc_pool.offset = 0;
1120 sc->enc_pool.read = 0;
1121 sc->enc_pool.write = 0;
1123 sc->encoding_eos = 0;
1125 sc->encoding = 1;
1127 /* Enable interrupts */
1128 cxm_set_irq_mask(sc, sc->irq_mask & ~CXM_IRQ_ENC);
1130 return 0;
1134 static int
1135 cxm_stop_encoder(struct cxm_softc *sc)
1137 uint32_t parameters[4];
1138 uint32_t subtype;
1139 uint32_t type;
1141 if (!sc->encoding)
1142 return 0;
1144 type = sc->mpeg ? CXM_FW_CAPTURE_STREAM_TYPE_MPEG
1145 : CXM_FW_CAPTURE_STREAM_TYPE_RAW;
1146 subtype = ((sc->mpeg || sc->source == cxm_fm_source)
1147 ? CXM_FW_CAPTURE_STREAM_PCM_AUDIO : 0)
1148 | ((sc->mpeg || sc->source != cxm_fm_source)
1149 ? CXM_FW_CAPTURE_STREAM_YUV : 0);
1151 /* Stop the encoder */
1152 parameters[0] = sc->mpeg ? 0 : 1; /* When = 0 (end of GOP) */
1153 parameters[1] = type;
1154 parameters[2] = subtype;
1155 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1156 CXM_FW_CMD_END_CAPTURE, parameters, 3) != 0)
1157 return -1;
1159 /* Wait for up to 1 second */
1160 crit_enter();
1161 if (!sc->encoding_eos)
1162 tsleep(&sc->encoding_eos, 0, "cxmeos", hz);
1163 crit_exit();
1165 if (sc->mpeg && !sc->encoding_eos)
1166 device_printf(sc->dev, "missing encoder EOS\n");
1168 /* Disable event notification */
1169 parameters[0] = 0; /* Event = 0 (refresh encoder input) */
1170 parameters[1] = 0; /* Notification = 0 (disable) */
1171 parameters[2] = 0x10000000; /* Interrupt bit */
1172 parameters[3] = -1; /* Mailbox = -1 (no mailbox) */
1173 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1174 CXM_FW_CMD_ENC_EVENT_NOTIFICATION,
1175 parameters, 4) != 0)
1176 return -1;
1178 /* Disable interrupts */
1179 cxm_set_irq_mask(sc, sc->irq_mask | CXM_IRQ_ENC);
1181 sc->encoding = 0;
1183 return 0;
1187 static int
1188 cxm_pause_encoder(struct cxm_softc *sc)
1190 uint32_t parameter;
1192 /* Pause the encoder */
1193 parameter = 0;
1194 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1195 CXM_FW_CMD_PAUSE_ENCODER, &parameter, 1) != 0)
1196 return -1;
1198 return 0;
1202 static int
1203 cxm_unpause_encoder(struct cxm_softc *sc)
1205 uint32_t parameter;
1207 /* Unpause the encoder */
1208 parameter = 1;
1209 if (cxm_firmware_command(sc, cxm_enc_mailbox,
1210 CXM_FW_CMD_PAUSE_ENCODER, &parameter, 1) != 0)
1211 return -1;
1213 return 0;
1217 static unsigned int
1218 cxm_encoder_fixup_byte_order(struct cxm_softc *sc,
1219 unsigned int current, size_t offset)
1221 unsigned int strips;
1222 unsigned int i;
1223 unsigned int j;
1224 unsigned int k;
1225 unsigned int macroblocks_per_line;
1226 unsigned int scratch;
1227 unsigned int words_per_line;
1228 uint32_t *ptr;
1229 uint32_t *src;
1230 size_t nbytes;
1232 switch (sc->enc_pool.bufs[current].byte_order) {
1233 case cxm_device_mpeg_byte_order:
1236 * Convert each 32 bit word to the proper byte ordering.
1239 for (nbytes = 0,
1240 ptr = (uint32_t *)sc->enc_pool.bufs[current].vaddr;
1241 nbytes != sc->enc_pool.bufs[current].size;
1242 nbytes += sizeof(*ptr), ptr++)
1243 *ptr = bswap32(*ptr);
1244 break;
1246 case cxm_device_yuv12_byte_order:
1249 * Convert each macro block to planar using
1250 * a scratch buffer (the buffer prior to the
1251 * current buffer is always free since it marks
1252 * the end of the ring buffer).
1255 scratch = (current + (CXM_SG_BUFFERS - 1)) % CXM_SG_BUFFERS;
1257 if (offset) {
1258 current = scratch;
1259 break;
1262 src = (uint32_t *)sc->enc_pool.bufs[current].vaddr;
1263 words_per_line = sc->profile->width / sizeof(*ptr);
1264 macroblocks_per_line
1265 = sc->profile->width / CXM_MACROBLOCK_WIDTH;
1266 strips = sc->enc_pool.bufs[current].size
1267 / (macroblocks_per_line * CXM_MACROBLOCK_SIZE);
1269 for (i = 0; i < strips; i++) {
1270 ptr = (uint32_t *)sc->enc_pool.bufs[scratch].vaddr
1271 + i * macroblocks_per_line * CXM_MACROBLOCK_SIZE
1272 / sizeof(*ptr);
1273 for (j = 0; j < macroblocks_per_line; j++) {
1274 for (k = 0; k < CXM_MACROBLOCK_HEIGHT; k++) {
1275 #if CXM_MACROBLOCK_WIDTH != 16
1276 # error CXM_MACROBLOCK_WIDTH != 16
1277 #endif
1278 *(ptr + k * words_per_line)
1279 = *src++;
1280 *(ptr + k * words_per_line + 1)
1281 = *src++;
1282 *(ptr + k * words_per_line + 2)
1283 = *src++;
1284 *(ptr + k * words_per_line + 3)
1285 = *src++;
1287 ptr += CXM_MACROBLOCK_WIDTH / sizeof(*ptr);
1291 sc->enc_pool.bufs[scratch].size
1292 = sc->enc_pool.bufs[current].size;
1294 current = scratch;
1295 break;
1297 default:
1298 break;
1301 sc->enc_pool.bufs[current].byte_order = cxm_host_byte_order;
1303 return current;
1307 static void
1308 cxm_encoder_dma_discard(struct cxm_softc *sc)
1310 uint32_t parameters[3];
1312 /* Discard the DMA request */
1313 parameters[0] = 0;
1314 parameters[1] = 0;
1315 parameters[2] = 0;
1316 if (cxm_queue_firmware_command(sc, cxm_enc_mailbox,
1317 CXM_FW_CMD_SCHED_DMA_TO_HOST,
1318 parameters, 3) == -1) {
1319 device_printf(sc->dev,
1320 "failed to discard encoder dma request\n");
1321 return;
1324 sc->encoding_dma = -1;
1328 static void
1329 cxm_encoder_dma_done(struct cxm_softc *sc)
1331 int buffers_pending;
1332 uint32_t status;
1334 if (!sc->encoding_dma) {
1335 device_printf(sc->dev,
1336 "encoder dma not already in progress\n");
1337 return;
1340 buffers_pending = sc->encoding_dma;
1341 sc->encoding_dma = 0;
1343 if (buffers_pending < 0)
1344 return;
1346 status = CSR_READ_4(sc, CXM_REG_DMA_STATUS) & 0x0000000f;
1348 if ((status
1349 & (CXM_DMA_ERROR_LIST | CXM_DMA_ERROR_WRITE | CXM_DMA_SUCCESS))
1350 != CXM_DMA_SUCCESS) {
1351 device_printf(sc->dev, "encoder dma status %#x\n",
1352 (unsigned int)status);
1353 return;
1356 /* Update the books */
1357 crit_enter();
1358 sc->enc_pool.write = (sc->enc_pool.write + buffers_pending)
1359 % CXM_SG_BUFFERS;
1360 crit_exit();
1362 /* signal anyone requesting notification */
1363 if (sc->enc_proc)
1364 ksignal (sc->enc_proc, sc->enc_signal);
1366 /* wakeup anyone waiting for data */
1367 wakeup(&sc->enc_pool.read);
1369 /* wakeup anyone polling for data */
1370 KNOTE(&sc->enc_kq.ki_note, 0);
1374 static void
1375 cxm_encoder_dma_request(struct cxm_softc *sc)
1377 enum cxm_byte_order byte_order;
1378 int buffers_free;
1379 int buffers_pending;
1380 unsigned int current;
1381 unsigned int i;
1382 unsigned int mailbox;
1383 unsigned int macroblocks_per_line;
1384 unsigned int nrequests;
1385 unsigned int strips;
1386 uint32_t parameters[CXM_MBX_MAX_PARAMETERS];
1387 uint32_t type;
1388 size_t max_sg_segment;
1389 struct {
1390 size_t offset;
1391 size_t size;
1392 } requests[2];
1394 if (sc->encoding_dma) {
1395 device_printf(sc->dev, "encoder dma already in progress\n");
1396 cxm_encoder_dma_discard(sc);
1397 return;
1400 mailbox = sc->enc_mbx
1401 + CXM_MBX_FW_DMA_MAILBOX * sizeof(struct cxm_mailbox);
1403 for (i = 0; i < CXM_MBX_MAX_PARAMETERS; i++)
1404 parameters[i]
1405 = CSR_READ_4(sc,
1406 mailbox
1407 + offsetof(struct cxm_mailbox, parameters)
1408 + i * sizeof(uint32_t)
1411 byte_order = cxm_device_mpeg_byte_order;
1412 max_sg_segment = CXM_SG_SEGMENT;
1413 nrequests = 0;
1414 type = parameters[0];
1416 switch (type) {
1417 case 0: /* MPEG */
1418 requests[nrequests].offset = parameters[1];
1419 requests[nrequests++].size = parameters[2];
1420 break;
1422 case 1: /* YUV */
1423 byte_order = cxm_device_yuv12_byte_order;
1426 * Simplify macroblock unpacking by ensuring
1427 * that strips don't span buffers.
1430 #if CXM_MACROBLOCK_SIZE % 256
1431 # error CXM_MACROBLOCK_SIZE not a multiple of 256
1432 #endif
1434 macroblocks_per_line = sc->profile->width
1435 / CXM_MACROBLOCK_WIDTH;
1436 strips = CXM_SG_SEGMENT
1437 / (macroblocks_per_line * CXM_MACROBLOCK_SIZE);
1438 max_sg_segment = strips
1439 * macroblocks_per_line * CXM_MACROBLOCK_SIZE;
1441 requests[nrequests].offset = parameters[1]; /* Y */
1442 requests[nrequests++].size = parameters[2];
1443 requests[nrequests].offset = parameters[3]; /* UV */
1444 requests[nrequests++].size = parameters[4];
1445 break;
1447 case 2: /* PCM (audio) */
1448 case 3: /* VBI */
1449 default:
1450 device_printf(sc->dev, "encoder dma type %#x unsupported\n",
1451 (unsigned int)type);
1452 cxm_encoder_dma_discard(sc);
1453 return;
1457 * Determine the number of buffers free at this * instant *
1458 * taking into consideration that the ring buffer wraps.
1460 crit_enter();
1461 buffers_free = sc->enc_pool.read - sc->enc_pool.write;
1462 if (buffers_free <= 0)
1463 buffers_free += CXM_SG_BUFFERS;
1464 crit_exit();
1467 * Build the scatter / gather list taking in
1468 * consideration that the ring buffer wraps,
1469 * at least one free buffer must always be
1470 * present to mark the end of the ring buffer,
1471 * and each transfer must be a multiple of 256.
1474 buffers_pending = 0;
1475 current = sc->enc_pool.write;
1477 for (i = 0; i < nrequests; i++) {
1478 if (!requests[i].size) {
1479 device_printf(sc->dev, "encoder dma size is zero\n");
1480 cxm_encoder_dma_discard(sc);
1481 return;
1484 while (requests[i].size) {
1485 sc->enc_pool.bufs[current].size
1486 = requests[i].size > max_sg_segment
1487 ? max_sg_segment : requests[i].size;
1488 sc->enc_pool.bufs[current].byte_order = byte_order;
1490 sc->enc_sg.vaddr[buffers_pending].src
1491 = requests[i].offset;
1492 sc->enc_sg.vaddr[buffers_pending].dst
1493 = sc->enc_pool.bufs[current].baddr;
1494 sc->enc_sg.vaddr[buffers_pending].size
1495 = (sc->enc_pool.bufs[current].size + 0x000000ff)
1496 & 0xffffff00;
1498 requests[i].offset += sc->enc_pool.bufs[current].size;
1499 requests[i].size -= sc->enc_pool.bufs[current].size;
1500 buffers_pending++;
1501 current = (current + 1) % CXM_SG_BUFFERS;
1503 if (buffers_pending >= buffers_free) {
1504 device_printf(sc->dev,
1505 "encoder dma not enough buffer space free\n");
1506 cxm_encoder_dma_discard(sc);
1507 return;
1512 /* Mark the last transfer in the list */
1513 sc->enc_sg.vaddr[buffers_pending - 1].size |= 0x80000000;
1515 /* Schedule the DMA */
1516 parameters[0] = sc->enc_sg.baddr;
1517 parameters[1] = buffers_pending * sizeof(sc->enc_sg.vaddr[0]);
1518 parameters[2] = type;
1519 if (cxm_queue_firmware_command(sc, cxm_enc_mailbox,
1520 CXM_FW_CMD_SCHED_DMA_TO_HOST,
1521 parameters, 3) == -1) {
1522 device_printf(sc->dev,
1523 "failed to schedule encoder dma request\n");
1524 return;
1528 * Record the number of pending buffers for the
1529 * benefit of cxm_encoder_dma_done. Doing this
1530 * after queuing the command doesn't introduce
1531 * a race condition since we're already in the
1532 * interrupt handler.
1535 sc->encoding_dma = buffers_pending;
1539 static int
1540 cxm_encoder_wait_for_lock(struct cxm_softc *sc)
1542 int muted;
1543 int locked;
1544 int result;
1546 locked = 1;
1549 * Wait for the tuner to lock.
1551 if (sc->source == cxm_fm_source || sc->source == cxm_tuner_source) {
1552 result = cxm_tuner_wait_for_lock(sc);
1553 if (result <= 0)
1554 return result;
1558 * Wait for the video decoder to lock.
1560 if (sc->source != cxm_fm_source) {
1561 result = cxm_saa7115_wait_for_lock(sc);
1562 if (result < 0)
1563 return result;
1564 else if (result == 0)
1565 locked = 0;
1569 * Wait for the audio decoder to lock.
1571 if (sc->source == cxm_tuner_source) {
1572 muted = cxm_msp_is_muted(sc);
1574 result = cxm_msp_autodetect_standard(sc);
1575 if (result < 0)
1576 return result;
1577 else if (result == 0)
1578 locked = 0;
1580 if (muted == 0 && cxm_msp_unmute(sc) < 0)
1581 return -1;
1584 return locked;
1588 static void
1589 cxm_mapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1591 bus_addr_t *busaddrp;
1594 * Only the first bus space address is needed
1595 * since it's known that the memory is physically
1596 * contiguous due to bus_dmamem_alloc.
1599 busaddrp = (bus_addr_t *)arg;
1600 *busaddrp = segs->ds_addr;
1605 * the boot time probe routine.
1607 static int
1608 cxm_probe(device_t dev)
1610 struct cxm_dev *t;
1612 t = cxm_devs;
1614 while(t->name != NULL) {
1615 if ((pci_get_vendor(dev) == t->vid) &&
1616 (pci_get_device(dev) == t->did)) {
1617 device_set_desc(dev, t->name);
1618 return 0;
1620 t++;
1623 return ENXIO;
1628 * the attach routine.
1630 static int
1631 cxm_attach(device_t dev)
1633 int error;
1634 int rid;
1635 int unit;
1636 unsigned int i;
1637 uint32_t command;
1638 struct cxm_softc *sc;
1640 /* Get the device data */
1641 sc = device_get_softc(dev);
1642 unit = device_get_unit(dev);
1644 sc->dev = dev;
1645 sc->type = cxm_iTVC15_type;
1647 switch(pci_get_device(dev)) {
1648 case PCI_PRODUCT_ICOMPRESSION_ITVC16:
1649 sc->type = cxm_iTVC16_type;
1650 break;
1652 default:
1653 break;
1657 * Enable bus mastering and memory mapped I/O.
1659 pci_enable_busmaster(dev);
1660 pci_enable_io(dev, SYS_RES_MEMORY);
1661 command = pci_read_config(dev, PCIR_COMMAND, 4);
1663 if (!(command & PCIM_CMD_MEMEN)) {
1664 device_printf(dev, "failed to enable memory mappings\n");
1665 error = ENXIO;
1666 goto fail;
1670 * Map control/status registers.
1672 rid = CXM_RID;
1673 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
1674 0, ~0, 1, RF_ACTIVE);
1676 if (!sc->mem_res) {
1677 device_printf(dev, "could not map memory\n");
1678 error = ENXIO;
1679 goto fail;
1682 sc->btag = rman_get_bustag(sc->mem_res);
1683 sc->bhandle = rman_get_bushandle(sc->mem_res);
1686 * Attach the I2C bus.
1688 sc->cxm_iic = device_add_child(dev, "cxm_iic", unit);
1690 if (!sc->cxm_iic) {
1691 device_printf(dev, "could not add cxm_iic\n");
1692 error = ENXIO;
1693 goto fail;
1696 error = device_probe_and_attach(sc->cxm_iic);
1698 if (error) {
1699 device_printf(dev, "could not attach cxm_iic\n");
1700 goto fail;
1704 * Initialize the tuner.
1706 if (cxm_tuner_init(sc) < 0) {
1707 device_printf(dev, "could not initialize tuner\n");
1708 error = ENXIO;
1709 goto fail;
1713 * Initialize the SAA7115.
1715 if (cxm_saa7115_init(sc) < 0) {
1716 device_printf(dev, "could not initialize video decoder\n");
1717 error = ENXIO;
1718 goto fail;
1722 * Initialize the MSP3400.
1724 if (cxm_msp_init(sc) < 0) {
1725 device_printf(dev, "could not initialize audio decoder\n");
1726 error = ENXIO;
1727 goto fail;
1731 * Initialize the IR Remote.
1733 if (cxm_ir_init(sc) < 0) {
1734 device_printf(dev, "could not initialize IR remote\n");
1735 error = ENXIO;
1736 goto fail;
1739 sc->dec_mbx = -1;
1740 sc->enc_mbx = -1;
1743 * Disable the Conexant device.
1745 * This is done * after * attaching the I2C bus so
1746 * cxm_stop_hardware can mute the video and audio
1747 * decoders.
1749 cxm_stop_hardware(sc);
1752 * Allocate our interrupt.
1754 rid = 0;
1755 sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
1756 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
1758 if (sc->irq_res == NULL) {
1759 device_printf(dev, "could not map interrupt\n");
1760 error = ENXIO;
1761 goto fail;
1764 error = bus_setup_intr(dev, sc->irq_res, 0,
1765 cxm_intr, sc, &sc->ih_cookie, NULL);
1766 if (error) {
1767 device_printf(dev, "could not setup irq\n");
1768 goto fail;
1773 * Allocate a DMA tag for the parent bus.
1775 error = bus_dma_tag_create(NULL, 1, 0,
1776 BUS_SPACE_MAXADDR_32BIT,
1777 BUS_SPACE_MAXADDR, NULL, NULL,
1778 BUS_SPACE_MAXSIZE_32BIT, 1,
1779 BUS_SPACE_MAXSIZE_32BIT, 0,
1780 &sc->parent_dmat);
1781 if (error) {
1782 device_printf(dev, "could not create parent bus DMA tag\n");
1783 goto fail;
1787 * Allocate a DMA tag for the encoder buffers.
1789 error = bus_dma_tag_create(sc->parent_dmat, 256, 0,
1790 BUS_SPACE_MAXADDR_32BIT,
1791 BUS_SPACE_MAXADDR, NULL, NULL,
1792 CXM_SG_SEGMENT, 1,
1793 BUS_SPACE_MAXSIZE_32BIT, 0,
1794 &sc->enc_pool.dmat);
1795 if (error) {
1796 device_printf(dev,
1797 "could not create encoder buffer DMA tag\n");
1798 goto fail;
1801 for (i = 0; i < CXM_SG_BUFFERS; i++) {
1804 * Allocate the encoder buffer.
1806 error = bus_dmamem_alloc(sc->enc_pool.dmat,
1807 (void **)&sc->enc_pool.bufs[i].vaddr,
1808 BUS_DMA_NOWAIT,
1809 &sc->enc_pool.bufs[i].dmamap);
1810 if (error) {
1811 device_printf(dev,
1812 "could not allocate encoder buffer\n");
1813 goto fail;
1817 * Map the encoder buffer.
1819 error = bus_dmamap_load(sc->enc_pool.dmat,
1820 sc->enc_pool.bufs[i].dmamap,
1821 sc->enc_pool.bufs[i].vaddr,
1822 CXM_SG_SEGMENT,
1823 cxm_mapmem,
1824 &sc->enc_pool.bufs[i].baddr, 0);
1825 if (error) {
1826 device_printf(dev, "could not map encoder buffer\n");
1827 goto fail;
1832 * Allocate a DMA tag for the scatter / gather list.
1834 error = bus_dma_tag_create(sc->parent_dmat, 1, 0,
1835 BUS_SPACE_MAXADDR_32BIT,
1836 BUS_SPACE_MAXADDR, NULL, NULL,
1837 CXM_SG_BUFFERS
1838 * sizeof(struct cxm_sg_entry), 1,
1839 BUS_SPACE_MAXSIZE_32BIT, 0,
1840 &sc->enc_sg.dmat);
1841 if (error) {
1842 device_printf(dev,
1843 "could not create scatter / gather DMA tag\n");
1844 goto fail;
1848 * Allocate the scatter / gather list.
1850 error = bus_dmamem_alloc(sc->enc_sg.dmat, (void **)&sc->enc_sg.vaddr,
1851 BUS_DMA_NOWAIT, &sc->enc_sg.dmamap);
1852 if (error) {
1853 device_printf(dev,
1854 "could not allocate scatter / gather list\n");
1855 goto fail;
1859 * Map the scatter / gather list.
1861 error = bus_dmamap_load(sc->enc_sg.dmat, sc->enc_sg.dmamap,
1862 sc->enc_sg.vaddr,
1863 CXM_SG_BUFFERS * sizeof(struct cxm_sg_entry),
1864 cxm_mapmem, &sc->enc_sg.baddr, 0);
1865 if (error) {
1866 device_printf(dev, "could not map scatter / gather list\n");
1867 goto fail;
1871 * Initialize the hardware.
1873 if (cxm_init_hardware(sc) < 0) {
1874 device_printf(dev, "could not initialize hardware\n");
1875 error = ENXIO;
1876 goto fail;
1879 sc->profile = &dvd_full_d1_ntsc_profile;
1881 sc->source = cxm_tuner_source;
1884 /* make the device entries */
1885 sc->cxm_dev_t = make_dev(&cxm_ops, unit,
1886 0, 0, 0444, "cxm%d", unit);
1888 return 0;
1890 fail:
1891 if (sc->enc_sg.baddr)
1892 bus_dmamap_unload(sc->enc_sg.dmat, sc->enc_sg.dmamap);
1893 if (sc->enc_sg.vaddr)
1894 bus_dmamem_free(sc->enc_sg.dmat, sc->enc_sg.vaddr,
1895 sc->enc_sg.dmamap);
1896 if (sc->enc_sg.dmat)
1897 bus_dma_tag_destroy(sc->enc_sg.dmat);
1899 for (i = 0; i < CXM_SG_BUFFERS; i++) {
1900 if (sc->enc_pool.bufs[i].baddr)
1901 bus_dmamap_unload(sc->enc_pool.dmat,
1902 sc->enc_pool.bufs[i].dmamap);
1903 if (sc->enc_pool.bufs[i].vaddr)
1904 bus_dmamem_free(sc->enc_pool.dmat,
1905 sc->enc_pool.bufs[i].vaddr,
1906 sc->enc_pool.bufs[i].dmamap);
1909 if (sc->enc_pool.dmat)
1910 bus_dma_tag_destroy(sc->enc_pool.dmat);
1912 if (sc->parent_dmat)
1913 bus_dma_tag_destroy(sc->parent_dmat);
1916 * Detach the I2C bus.
1918 * This is done * after * deallocating the scatter / gather
1919 * list and buffers so the kernel has a better chance of
1920 * gracefully handling a memory shortage.
1922 * Detach the children before recursively deleting
1923 * in case a child has a pointer to a grandchild
1924 * which is used by the child's detach routine.
1926 bus_generic_detach(dev);
1927 if (sc->cxm_iic)
1928 device_delete_child(dev, sc->cxm_iic);
1930 if (sc->ih_cookie)
1931 bus_teardown_intr(dev, sc->irq_res, sc->ih_cookie);
1932 if (sc->irq_res)
1933 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
1934 if (sc->mem_res)
1935 bus_release_resource(dev, SYS_RES_MEMORY, CXM_RID, sc->mem_res);
1937 return error;
1941 * the detach routine.
1943 static int
1944 cxm_detach(device_t dev)
1946 unsigned int i;
1947 struct cxm_softc *sc;
1948 device_t child;
1950 /* Get the device data */
1951 sc = device_get_softc(dev);
1953 /* Disable the Conexant device. */
1954 cxm_stop_hardware(sc);
1956 /* Unregister the /dev/cxmN device. */
1957 dev_ops_remove_minor(&cxm_ops, /*0, */device_get_unit(dev));
1960 * Deallocate scatter / gather list and buffers.
1962 bus_dmamap_unload(sc->enc_sg.dmat, sc->enc_sg.dmamap);
1963 bus_dmamem_free(sc->enc_sg.dmat, sc->enc_sg.vaddr, sc->enc_sg.dmamap);
1965 bus_dma_tag_destroy(sc->enc_sg.dmat);
1967 for (i = 0; i < CXM_SG_BUFFERS; i++) {
1968 bus_dmamap_unload(sc->enc_pool.dmat,
1969 sc->enc_pool.bufs[i].dmamap);
1970 bus_dmamem_free(sc->enc_pool.dmat, sc->enc_pool.bufs[i].vaddr,
1971 sc->enc_pool.bufs[i].dmamap);
1974 bus_dma_tag_destroy(sc->enc_pool.dmat);
1976 bus_dma_tag_destroy(sc->parent_dmat);
1979 * Detach the I2C bus.
1981 * This is done * after * deallocating the scatter / gather
1982 * list and buffers so the kernel has a better chance of
1983 * gracefully handling a memory shortage.
1985 * Detach the children before recursively deleting
1986 * in case a child has a pointer to a grandchild
1987 * which is used by the child's detach routine.
1989 * Remember the child before detaching so we can
1990 * delete it (bus_generic_detach indirectly zeroes
1991 * sc->child_dev).
1993 child = sc->cxm_iic;
1994 bus_generic_detach(dev);
1995 if (child)
1996 device_delete_child(dev, child);
1998 /* Deallocate resources. */
1999 bus_teardown_intr(dev, sc->irq_res, sc->ih_cookie);
2000 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
2001 bus_release_resource(dev, SYS_RES_MEMORY, CXM_RID, sc->mem_res);
2003 return 0;
2007 * the shutdown routine.
2009 static int
2010 cxm_shutdown(device_t dev)
2012 struct cxm_softc *sc = device_get_softc(dev);
2014 /* Disable the Conexant device. */
2015 cxm_stop_hardware(sc);
2017 return 0;
2021 * the interrupt routine.
2023 static void
2024 cxm_intr(void *arg)
2026 uint32_t status;
2027 struct cxm_softc *sc;
2029 /* Get the device data */
2030 sc = (struct cxm_softc *)arg;
2032 status = CSR_READ_4(sc, CXM_REG_IRQ_STATUS);
2034 status &= ~sc->irq_mask;
2036 if (!status)
2037 return;
2039 /* Process DMA done before handling a new DMA request or EOS */
2040 if (status & CXM_IRQ_ENC_DMA_DONE)
2041 cxm_encoder_dma_done(sc);
2043 if (status & CXM_IRQ_ENC_DMA_REQUEST)
2044 cxm_encoder_dma_request(sc);
2046 if (status & CXM_IRQ_ENC_EOS) {
2047 sc->encoding_eos = 1;
2048 wakeup(&sc->encoding_eos);
2051 cxm_set_irq_status(sc, status);
2056 * the child detached routine.
2058 static void
2059 cxm_child_detached(device_t dev, device_t child)
2061 struct cxm_softc *sc;
2063 /* Get the device data */
2064 sc = device_get_softc(dev);
2066 if (child == sc->cxm_iic)
2067 sc->cxm_iic = NULL;
2071 static int
2072 cxm_read_ivar(device_t dev, device_t child, int index, uintptr_t* val)
2074 struct cxm_softc *sc;
2076 /* Get the device data */
2077 sc = device_get_softc(dev);
2079 switch (index) {
2080 case CXM_IVAR_BHANDLE:
2081 *(bus_space_handle_t **)val = &sc->bhandle;
2082 break;
2084 case CXM_IVAR_BTAG:
2085 *(bus_space_tag_t **)val = &sc->btag;
2086 break;
2088 case CXM_IVAR_IICBUS:
2089 *(device_t **)val = &sc->iicbus;
2090 break;
2092 default:
2093 return ENOENT;
2096 return 0;
2100 static int
2101 cxm_write_ivar(device_t dev, device_t child, int index, uintptr_t val)
2103 struct cxm_softc *sc;
2105 /* Get the device data */
2106 sc = device_get_softc(dev);
2108 switch (index) {
2109 case CXM_IVAR_BHANDLE:
2110 return EINVAL;
2112 case CXM_IVAR_BTAG:
2113 return EINVAL;
2115 case CXM_IVAR_IICBUS:
2116 if (sc->iicbus)
2117 return EINVAL;
2118 sc->iicbus = val ? *(device_t *)val : NULL;
2119 break;
2121 default:
2122 return ENOENT;
2125 return 0;
2129 /*---------------------------------------------------------
2131 ** Conexant iTVC15 / iTVC16 character device driver routines
2133 **---------------------------------------------------------
2136 #define UNIT(x) ((x) & 0x0f)
2137 #define FUNCTION(x) (x >> 4)
2143 cxm_open(struct dev_open_args *ap)
2145 cdev_t dev = ap->a_head.a_dev;
2146 int unit;
2147 struct cxm_softc *sc;
2149 unit = UNIT(minor(dev));
2151 /* Get the device data */
2152 sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit);
2153 if (sc == NULL) {
2154 /* the device is no longer valid/functioning */
2155 return ENXIO;
2158 if (sc->is_opened)
2159 return EBUSY;
2161 sc->is_opened = 1;
2162 sc->mpeg = 1;
2164 /* Record that the device is now busy */
2165 device_busy(devclass_get_device(cxm_devclass, unit));
2167 return 0;
2175 cxm_close(struct dev_close_args *ap)
2177 cdev_t dev = ap->a_head.a_dev;
2178 int unit;
2179 struct cxm_softc *sc;
2181 unit = UNIT(minor(dev));
2183 /* Get the device data */
2184 sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit);
2185 if (sc == NULL) {
2186 /* the device is no longer valid/functioning */
2187 return ENXIO;
2190 if (cxm_stop_encoder(sc) < 0)
2191 return ENXIO;
2193 sc->enc_pool.offset = 0;
2194 sc->enc_pool.read = 0;
2195 sc->enc_pool.write = 0;
2197 sc->enc_proc = NULL;
2198 sc->enc_signal = 0;
2200 device_unbusy(devclass_get_device(cxm_devclass, unit));
2202 sc->is_opened = 0;
2204 return 0;
2212 cxm_read(struct dev_read_args *ap)
2214 cdev_t dev = ap->a_head.a_dev;
2215 int buffers_available;
2216 int buffers_read;
2217 int error;
2218 int unit;
2219 unsigned int current;
2220 unsigned int i;
2221 size_t nbytes;
2222 size_t offset;
2223 struct cxm_softc *sc;
2225 unit = UNIT(minor(dev));
2227 /* Get the device data */
2228 sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit);
2229 if (sc == NULL) {
2230 /* the device is no longer valid/functioning */
2231 return ENXIO;
2234 /* Only trigger the encoder if the ring buffer is empty */
2235 if (!sc->encoding && sc->enc_pool.read == sc->enc_pool.write) {
2236 if (cxm_start_encoder(sc) < 0)
2237 return ENXIO;
2238 if (ap->a_ioflag & IO_NDELAY)
2239 return EWOULDBLOCK;
2242 buffers_available = 0;
2244 crit_enter();
2245 while (sc->enc_pool.read == sc->enc_pool.write) {
2246 error = tsleep(&sc->enc_pool.read, PCATCH, "cxmrd", 0);
2247 if (error) {
2248 crit_exit();
2249 return error;
2254 * Determine the number of buffers available at this * instant *
2255 * taking in consideration that the ring buffer wraps.
2257 buffers_available = sc->enc_pool.write - sc->enc_pool.read;
2258 if (buffers_available < 0)
2259 buffers_available += CXM_SG_BUFFERS;
2260 crit_exit();
2262 offset = sc->enc_pool.offset;
2264 for (buffers_read = 0, i = sc->enc_pool.read;
2265 buffers_read != buffers_available && ap->a_uio->uio_resid;
2266 buffers_read++, i = (i + 1) % CXM_SG_BUFFERS) {
2268 current = cxm_encoder_fixup_byte_order (sc, i, offset);
2270 nbytes = sc->enc_pool.bufs[current].size - offset;
2272 /* Don't transfer more than requested */
2273 if (nbytes > ap->a_uio->uio_resid)
2274 nbytes = ap->a_uio->uio_resid;
2276 error = uiomove(sc->enc_pool.bufs[current].vaddr + offset,
2277 nbytes, ap->a_uio);
2278 if (error)
2279 return error;
2281 offset += nbytes;
2283 /* Handle a partial read of a buffer */
2284 if (!ap->a_uio->uio_resid && offset != sc->enc_pool.bufs[i].size)
2285 break;
2287 offset = 0;
2290 sc->enc_pool.offset = offset;
2292 /* Update the books */
2293 crit_enter();
2294 sc->enc_pool.read = (sc->enc_pool.read + buffers_read)
2295 % CXM_SG_BUFFERS;
2296 crit_exit();
2298 return 0;
2306 cxm_ioctl(struct dev_ioctl_args *ap)
2308 cdev_t dev = ap->a_head.a_dev;
2309 int brightness;
2310 int chroma_saturation;
2311 int contrast;
2312 int fps;
2313 int hue;
2314 int result;
2315 int status;
2316 int unit;
2317 unsigned int i;
2318 unsigned int sig;
2319 unsigned long freq;
2320 struct cxm_softc *sc;
2321 enum cxm_source source;
2322 struct bktr_capture_area *cap;
2323 struct bktr_remote *remote;
2325 unit = UNIT(minor(dev));
2327 /* Get the device data */
2328 sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit);
2329 if (sc == NULL) {
2330 /* the device is no longer valid/functioning */
2331 return ENXIO;
2334 switch (ap->a_cmd) {
2335 case BT848_GAUDIO:
2336 switch (cxm_msp_selected_source(sc)) {
2337 case cxm_tuner_source:
2338 *(int *) ap->a_data = AUDIO_TUNER;
2339 break;
2341 case cxm_line_in_source_composite:
2342 case cxm_line_in_source_svideo:
2343 *(int *) ap->a_data = AUDIO_EXTERN;
2344 break;
2346 case cxm_fm_source:
2347 *(int *) ap->a_data = AUDIO_INTERN;
2348 break;
2350 default:
2351 return ENXIO;
2354 if (cxm_msp_is_muted(sc) == 1)
2355 *(int *) ap->a_data |= AUDIO_MUTE;
2356 break;
2358 case BT848_SAUDIO:
2359 source = cxm_unknown_source;
2361 switch (*(int *) ap->a_data) {
2362 case AUDIO_TUNER:
2363 source = cxm_tuner_source;
2364 break;
2366 case AUDIO_EXTERN:
2367 source = cxm_line_in_source_composite;
2368 break;
2370 case AUDIO_INTERN:
2371 source = cxm_fm_source;
2372 break;
2374 case AUDIO_MUTE:
2375 if (cxm_msp_mute(sc) < 0)
2376 return ENXIO;
2377 return 0;
2379 case AUDIO_UNMUTE:
2380 if (cxm_msp_unmute(sc) < 0)
2381 return ENXIO;
2382 return 0;
2384 default:
2385 return EINVAL;
2388 if (sc->encoding) {
2391 * Switching between audio + video and audio only
2392 * subtypes isn't supported while encoding.
2395 if (source != sc->source
2396 && (source == cxm_fm_source
2397 || sc->source == cxm_fm_source))
2398 return EBUSY;
2401 if (cxm_pause_encoder(sc) < 0)
2402 return ENXIO;
2404 if (cxm_msp_select_source(sc, source) < 0)
2405 return ENXIO;
2407 if (source == cxm_fm_source)
2408 sc->source = source;
2410 result = cxm_encoder_wait_for_lock(sc);
2411 if (result < 0)
2412 return ENXIO;
2413 else if (result == 0)
2414 return EINVAL;
2416 if (cxm_unpause_encoder(sc) < 0)
2417 return ENXIO;
2418 break;
2420 case BT848_GBRIG:
2421 brightness = cxm_saa7115_get_brightness(sc);
2423 if (brightness < 0)
2424 return ENXIO;
2427 * Brooktree brightness:
2428 * 0x80 = -50.0%, 0x00 = +0.0%, 0x7f = +49.6%
2430 *(int *)ap->a_data = (int)(unsigned char)brightness - 128;
2431 break;
2433 case BT848_SBRIG:
2436 * Brooktree brightness:
2437 * 0x80 = -50.0%, 0x00 = +0.0%, 0x7f = +49.6%
2439 brightness = *(int *)ap->a_data + 128;
2441 if (cxm_saa7115_set_brightness(sc, brightness) < 0)
2442 return ENXIO;
2443 break;
2445 case METEORGBRIG:
2446 brightness = cxm_saa7115_get_brightness(sc);
2448 if (brightness < 0)
2449 return ENXIO;
2451 *(unsigned char *)ap->a_data = (unsigned char)brightness;
2452 break;
2454 case METEORSBRIG:
2455 brightness = *(unsigned char *)ap->a_data;
2457 if (cxm_saa7115_set_brightness(sc, brightness) < 0)
2458 return ENXIO;
2459 break;
2461 case BT848_GCSAT:
2462 chroma_saturation = cxm_saa7115_get_chroma_saturation(sc);
2464 if (chroma_saturation < 0)
2465 return ENXIO;
2468 * Brooktree chroma saturation:
2469 * 0x000 = 0%, 0x0fe = 100%, 0x1ff = 201.18%
2471 *(int *)ap->a_data = ((signed char)chroma_saturation > 0)
2472 ? (chroma_saturation * 4 - 2) : 0;
2473 break;
2475 case BT848_SCSAT:
2478 * Brooktree chroma saturation:
2479 * 0x000 = 0%, 0x0fe = 100%, 0x1ff = 201.18%
2481 chroma_saturation = (*(int *)ap->a_data & 0x1ff) < 510
2482 ? ((*(int *)ap->a_data & 0x1ff) + 2) / 4 : 127;
2484 if (cxm_saa7115_set_chroma_saturation(sc, chroma_saturation)
2485 < 0)
2486 return ENXIO;
2488 break;
2490 case METEORGCSAT:
2491 chroma_saturation = cxm_saa7115_get_chroma_saturation(sc);
2493 if (chroma_saturation < 0)
2494 return ENXIO;
2496 *(unsigned char *)ap->a_data = (unsigned char)chroma_saturation;
2497 break;
2499 case METEORSCSAT:
2500 chroma_saturation = *(unsigned char *)ap->a_data;
2502 if (cxm_saa7115_set_chroma_saturation(sc, chroma_saturation)
2503 < 0)
2504 return ENXIO;
2505 break;
2507 case METEORGCONT:
2508 contrast = cxm_saa7115_get_contrast(sc);
2510 if (contrast < 0)
2511 return ENXIO;
2513 *(unsigned char *)ap->a_data = (unsigned char)contrast;
2514 break;
2516 case METEORSCONT:
2517 contrast = *(unsigned char *)ap->a_data;
2519 if (cxm_saa7115_set_contrast(sc, contrast) < 0)
2520 return ENXIO;
2521 break;
2523 case BT848_GHUE:
2524 hue = cxm_saa7115_get_hue(sc);
2526 if (hue < 0)
2527 return ENXIO;
2529 *(int *)ap->a_data = (signed char)hue;
2530 break;
2532 case BT848_SHUE:
2533 hue = *(int *)ap->a_data;
2535 if (cxm_saa7115_set_hue(sc, hue) < 0)
2536 return ENXIO;
2537 break;
2539 case METEORGHUE:
2540 hue = cxm_saa7115_get_hue(sc);
2542 if (hue < 0)
2543 return ENXIO;
2545 *(signed char *)ap->a_data = (signed char)hue;
2546 break;
2548 case METEORSHUE:
2549 hue = *(signed char *)ap->a_data;
2551 if (cxm_saa7115_set_hue(sc, hue) < 0)
2552 return ENXIO;
2553 break;
2555 case METEORCAPTUR:
2556 switch (*(int *) ap->a_data) {
2557 case METEOR_CAP_CONTINOUS:
2558 if (cxm_start_encoder(sc) < 0)
2559 return ENXIO;
2560 break;
2562 case METEOR_CAP_STOP_CONT:
2563 if (cxm_stop_encoder(sc) < 0)
2564 return ENXIO;
2565 break;
2567 default:
2568 return EINVAL;
2570 break;
2572 case BT848_GCAPAREA:
2573 cap = (struct bktr_capture_area *)ap->a_data;
2574 memset (cap, 0, sizeof (*cap));
2575 cap->x_offset = 0;
2576 cap->y_offset = 0;
2577 cap->x_size = sc->profile->width;
2578 cap->y_size = sc->profile->height;
2579 break;
2581 case BT848_SCAPAREA:
2582 if (sc->encoding)
2583 return EBUSY;
2585 cap = (struct bktr_capture_area *)ap->a_data;
2586 if (cap->x_offset || cap->y_offset
2587 || (cap->x_size % CXM_MACROBLOCK_WIDTH)
2588 || (cap->y_size % CXM_MACROBLOCK_HEIGHT))
2589 return EINVAL;
2592 * Setting the width and height has the side effect of
2593 * chosing between the VCD, SVCD, and DVD profiles.
2596 for (i = 0; i < NUM_ELEMENTS(codec_profiles); i++)
2597 if (codec_profiles[i]->width == cap->x_size
2598 && codec_profiles[i]->height == cap->y_size)
2599 break;
2601 if (i >= NUM_ELEMENTS(codec_profiles))
2602 return EINVAL;
2604 sc->profile = codec_profiles[i];
2605 break;
2607 case BT848GFMT:
2608 switch (cxm_saa7115_detected_format(sc)) {
2609 case cxm_ntsc_60hz_source_format:
2610 *(unsigned long *)ap->a_data = BT848_IFORM_F_NTSCM;
2611 break;
2613 case cxm_pal_50hz_source_format:
2614 *(unsigned long *)ap->a_data = BT848_IFORM_F_PALBDGHI;
2615 break;
2617 case cxm_secam_50hz_source_format:
2618 *(unsigned long *)ap->a_data = BT848_IFORM_F_SECAM;
2619 break;
2621 case cxm_pal_60hz_source_format:
2622 *(unsigned long *)ap->a_data = BT848_IFORM_F_PALM;
2623 break;
2625 case cxm_bw_50hz_source_format:
2626 case cxm_bw_60hz_source_format:
2627 case cxm_ntsc_50hz_source_format:
2628 *(unsigned long *)ap->a_data = BT848_IFORM_F_AUTO;
2629 break;
2631 default:
2632 return ENXIO;
2634 break;
2636 case METEORGFMT:
2637 switch (cxm_saa7115_detected_format(sc)) {
2638 case cxm_ntsc_60hz_source_format:
2639 *(unsigned long *)ap->a_data = METEOR_FMT_NTSC;
2640 break;
2642 case cxm_pal_50hz_source_format:
2643 *(unsigned long *)ap->a_data = METEOR_FMT_PAL;
2644 break;
2646 case cxm_secam_50hz_source_format:
2647 *(unsigned long *)ap->a_data = METEOR_FMT_SECAM;
2648 break;
2650 case cxm_bw_50hz_source_format:
2651 case cxm_bw_60hz_source_format:
2652 case cxm_ntsc_50hz_source_format:
2653 case cxm_pal_60hz_source_format:
2654 *(unsigned long *)ap->a_data = METEOR_FMT_AUTOMODE;
2655 break;
2657 default:
2658 return ENXIO;
2660 break;
2662 case METEORGFPS:
2663 fps = cxm_saa7115_detected_fps(sc);
2665 if (fps < 0)
2666 return ENXIO;
2668 *(unsigned short *)ap->a_data = fps;
2669 break;
2671 case METEORGINPUT:
2672 switch (sc->source) {
2673 case cxm_tuner_source:
2674 *(unsigned long *)ap->a_data = METEOR_INPUT_DEV1;
2675 break;
2677 case cxm_line_in_source_composite:
2678 *(unsigned long *)ap->a_data = METEOR_INPUT_DEV2;
2679 break;
2681 case cxm_line_in_source_svideo:
2682 *(unsigned long *)ap->a_data = METEOR_INPUT_DEV_SVIDEO;
2683 break;
2685 default:
2686 return ENXIO;
2688 break;
2690 case METEORSINPUT:
2691 source = cxm_unknown_source;
2693 switch (*(unsigned long *)ap->a_data & 0xf000) {
2694 case METEOR_INPUT_DEV1:
2695 source = cxm_tuner_source;
2696 break;
2698 case METEOR_INPUT_DEV2:
2699 source = cxm_line_in_source_composite;
2700 break;
2702 case METEOR_INPUT_DEV_SVIDEO:
2703 source = cxm_line_in_source_svideo;
2704 break;
2706 default:
2707 return EINVAL;
2710 if (sc->encoding) {
2713 * Switching between audio + video and audio only
2714 * subtypes isn't supported while encoding.
2717 if (source != sc->source
2718 && (source == cxm_fm_source
2719 || sc->source == cxm_fm_source))
2720 return EBUSY;
2723 if (cxm_pause_encoder(sc) < 0)
2724 return ENXIO;
2726 if (cxm_saa7115_select_source(sc, source) < 0)
2727 return ENXIO;
2728 if (cxm_msp_select_source(sc, source) < 0)
2729 return ENXIO;
2730 sc->source = source;
2732 result = cxm_encoder_wait_for_lock(sc);
2733 if (result < 0)
2734 return ENXIO;
2735 else if (result == 0)
2736 return EINVAL;
2738 if (cxm_unpause_encoder(sc) < 0)
2739 return ENXIO;
2740 break;
2742 case METEORGSIGNAL:
2743 *(unsigned int *)ap->a_data = sc->enc_signal;
2744 break;
2746 case METEORSSIGNAL:
2747 sig = *(unsigned int *)ap->a_data;
2749 if (!_SIG_VALID(sig))
2750 return EINVAL;
2753 * Historically, applications used METEOR_SIG_MODE_MASK
2754 * to reset signal delivery.
2756 if (sig == METEOR_SIG_MODE_MASK)
2757 sig = 0;
2759 crit_enter();
2760 sc->enc_proc = sig ? curproc : NULL;
2761 sc->enc_signal = sig;
2762 crit_exit();
2763 break;
2765 case RADIO_GETFREQ:
2766 /* Convert from kHz to MHz * 100 */
2767 freq = sc->tuner_freq / 10;
2769 *(unsigned int *)ap->a_data = freq;
2770 break;
2772 case RADIO_SETFREQ:
2773 if (sc->source == cxm_fm_source)
2774 if (cxm_pause_encoder(sc) < 0)
2775 return ENXIO;
2777 /* Convert from MHz * 100 to kHz */
2778 freq = *(unsigned int *)ap->a_data * 10;
2780 if (cxm_tuner_select_frequency(sc, cxm_tuner_fm_freq_type,
2781 freq) < 0)
2782 return ENXIO;
2785 * Explicitly wait for the tuner lock so we
2786 * can indicate if there's a station present.
2788 if (cxm_tuner_wait_for_lock(sc) < 0)
2789 return EINVAL;
2791 result = cxm_encoder_wait_for_lock(sc);
2792 if (result < 0)
2793 return ENXIO;
2794 else if (result == 0)
2795 return EINVAL;
2797 if (sc->source == cxm_fm_source)
2798 if (cxm_unpause_encoder(sc) < 0)
2799 return ENXIO;
2800 break;
2802 case TVTUNER_GETAFC:
2803 *(int *)ap->a_data = sc->tuner_afc;
2804 break;
2806 case TVTUNER_SETAFC:
2807 sc->tuner_afc = (*(int *)ap->a_data != 0);
2808 break;
2810 case TVTUNER_GETTYPE:
2811 *(unsigned int *)ap->a_data = cxm_tuner_selected_channel_set(sc);
2812 break;
2814 case TVTUNER_SETTYPE:
2815 if (cxm_tuner_select_channel_set(sc, *(unsigned int *)ap->a_data) < 0)
2816 return EINVAL;
2817 break;
2819 case TVTUNER_SETCHNL:
2820 if (sc->source == cxm_tuner_source)
2821 if (cxm_pause_encoder(sc) < 0)
2822 return ENXIO;
2824 if (cxm_tuner_select_channel(sc, *(unsigned int *)ap->a_data) < 0)
2825 return ENXIO;
2827 if (sc->tuner_afc)
2828 if (cxm_tuner_apply_afc(sc) < 0)
2829 return EINVAL;
2832 * Explicitly wait for the tuner lock so we
2833 * can indicate if there's a station present.
2835 if (cxm_tuner_wait_for_lock(sc) < 0)
2836 return EINVAL;
2838 result = cxm_encoder_wait_for_lock(sc);
2839 if (result < 0)
2840 return ENXIO;
2841 else if (result == 0)
2842 return EINVAL;
2844 if (sc->source == cxm_tuner_source)
2845 if (cxm_unpause_encoder(sc) < 0)
2846 return ENXIO;
2847 break;
2849 case TVTUNER_GETFREQ:
2850 /* Convert from kHz to MHz * 16 */
2851 freq = (sc->tuner_freq * 16) / 1000;
2853 *(unsigned int *)ap->a_data = freq;
2854 break;
2856 case TVTUNER_SETFREQ:
2857 if (sc->source == cxm_tuner_source)
2858 if (cxm_pause_encoder(sc) < 0)
2859 return ENXIO;
2861 /* Convert from MHz * 16 to kHz */
2862 freq = (*(unsigned int *)ap->a_data * 1000) / 16;
2864 if (cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type,
2865 freq) < 0)
2866 return ENXIO;
2869 * Explicitly wait for the tuner lock so we
2870 * can indicate if there's a station present.
2872 if (cxm_tuner_wait_for_lock(sc) < 0)
2873 return EINVAL;
2875 result = cxm_encoder_wait_for_lock(sc);
2876 if (result < 0)
2877 return ENXIO;
2878 else if (result == 0)
2879 return EINVAL;
2881 if (sc->source == cxm_tuner_source)
2882 if (cxm_unpause_encoder(sc) < 0)
2883 return ENXIO;
2885 break;
2887 case TVTUNER_GETSTATUS:
2888 status = cxm_tuner_status(sc);
2889 if (status < 0)
2890 return ENXIO;
2891 *(unsigned long *)ap->a_data = status & 0xff;
2892 break;
2894 case REMOTE_GETKEY:
2895 remote = (struct bktr_remote *)ap->a_data;
2896 if (cxm_ir_key(sc, (char *)remote, sizeof(*remote)) < 0)
2897 return ENXIO;
2898 break;
2900 default:
2901 return ENOTTY;
2904 return 0;
2907 static struct filterops cxm_filterops =
2908 { FILTEROP_ISFD, NULL, cxm_filter_detach, cxm_filter };
2910 static int
2911 cxm_kqfilter(struct dev_kqfilter_args *ap)
2913 cdev_t dev = ap->a_head.a_dev;
2914 struct knote *kn = ap->a_kn;
2915 struct cxm_softc *sc;
2916 struct klist *klist;
2917 int unit;
2919 ap->a_result = 0;
2921 switch (kn->kn_filter) {
2922 case EVFILT_READ:
2923 unit = UNIT(minor(dev));
2924 /* Get the device data */
2925 sc = (struct cxm_softc *)devclass_get_softc(cxm_devclass, unit);
2926 kn->kn_fop = &cxm_filterops;
2927 kn->kn_hook = (caddr_t)sc;
2928 break;
2929 default:
2930 ap->a_result = EOPNOTSUPP;
2931 return (0);
2934 klist = &sc->enc_kq.ki_note;
2935 knote_insert(klist, kn);
2937 return (0);
2940 static void
2941 cxm_filter_detach(struct knote *kn)
2943 struct cxm_softc *sc = (struct cxm_softc *)kn->kn_hook;
2944 struct klist *klist = &sc->enc_kq.ki_note;
2946 knote_remove(klist, kn);
2949 static int
2950 cxm_filter(struct knote *kn, long hint)
2952 struct cxm_softc *sc = (struct cxm_softc *)kn->kn_hook;
2953 int ready = 0;
2955 if (sc == NULL) {
2956 /* the device is no longer valid/functioning */
2957 kn->kn_flags |= (EV_EOF | EV_NODATA);
2958 return (1);
2961 crit_enter();
2962 if (sc->enc_pool.read != sc->enc_pool.write)
2963 ready = 1;
2964 crit_exit();
2966 return (ready);