From owner-freebsd-multimedia@FreeBSD.ORG Sun Mar 14 08:31:58 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id D689416A4CE for ; Sun, 14 Mar 2004 08:31:58 -0800 (PST) Received: from 159163.vserver.de (159163.vserver.de [62.75.159.163]) by mx1.FreeBSD.org (Postfix) with SMTP id B392B43D1D for ; Sun, 14 Mar 2004 08:31:57 -0800 (PST) (envelope-from bofh@m-wesemeyer.de) Received: (qmail 6088 invoked by uid 0); 14 Mar 2004 16:31:42 -0000 Received: from unknown (HELO bofh.hell) (bofh@217.88.132.169) by 0 with SMTP; 14 Mar 2004 16:31:42 -0000 Date: Sun, 14 Mar 2004 16:38:16 +0100 From: Michael Wesemeyer To: multimedia@freebsd.org Message-Id: <20040314163816.6aba41ab.bofh@m-wesemeyer.de> Organization: eigener server X-Mailer: Sylpheed version 0.9.10 (GTK+ 1.2.10; i386-portbld-freebsd4.8) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Subject: fxtv X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 14 Mar 2004 16:31:58 -0000 Hi I could need some help with fxtv. I recorded with MPEG ready and all i get is a file foo.sh and foo.AVraw . When I record with MPEG i get at first conversion in Progress and the I get an Error message Video conversion failed CMD = ./foo.sh Status = 0x0100 Another question is about a text pasage in the README There is written and finally, put this env var setting in your profile: MPEGTABLES=/usr/local/lib/mpegaudio/tables In which Profile shall I write it? I have no clue. Thanx From owner-freebsd-multimedia@FreeBSD.ORG Sun Mar 14 10:17:33 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id B7F4516A4CE for ; Sun, 14 Mar 2004 10:17:33 -0800 (PST) Received: from lakemtao08.cox.net (lakemtao08.cox.net [68.1.17.113]) by mx1.FreeBSD.org (Postfix) with ESMTP id 0996643D1F for ; Sun, 14 Mar 2004 10:17:33 -0800 (PST) (envelope-from kitbsdlists@HotPOP.com) Received: from vixen42 ([68.109.49.234]) by lakemtao08.cox.net (InterMail vM.5.01.06.08 201-253-122-130-108-20031117) with SMTP id <20040314181732.IWI10550.lakemtao08.cox.net@vixen42> for ; Sun, 14 Mar 2004 13:17:32 -0500 Date: Sun, 14 Mar 2004 10:14:51 -0600 From: Vulpes Velox To: freebsd-multimedia@freebsd.org Message-Id: <20040314101451.33075201@vixen42.> In-Reply-To: <20040314163816.6aba41ab.bofh@m-wesemeyer.de> References: <20040314163816.6aba41ab.bofh@m-wesemeyer.de> X-Mailer: Sylpheed version 0.9.9claws (GTK+ 1.2.10; i386-portbld-freebsd4.9) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Subject: Re: fxtv X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 14 Mar 2004 18:17:33 -0000 On Sun, 14 Mar 2004 16:38:16 +0100 Michael Wesemeyer wrote: > Hi > I could need some help with fxtv. I recorded with MPEG ready and all > i get is a file foo.sh and foo.AVraw . When I record with MPEG i get > at first conversion in Progress and the I get an Error message Video > conversion failed > CMD = ./foo.sh > Status = 0x0100 > > Another question is about a text pasage in the README > There is written > > and finally, put this env var setting in your profile: > > MPEGTABLES=/usr/local/lib/mpegaudio/tables > > In which Profile shall I write it? I have no clue. Hmm, when I saw that error, it had something to do with a bad script... I had to rework the script to get it to stop with the error on 4x when using pcm for sound. From owner-freebsd-multimedia@FreeBSD.ORG Mon Mar 15 04:43:45 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 037AF16A4CF for ; Mon, 15 Mar 2004 04:43:45 -0800 (PST) Received: from teena.dahlen.ws (h96n2fls33o990.telia.com [213.67.6.96]) by mx1.FreeBSD.org (Postfix) with ESMTP id EB32643D31 for ; Mon, 15 Mar 2004 04:43:43 -0800 (PST) (envelope-from andreas@dahlen.ws) Received: from mikaela (mikaela.dahlen.ws [10.0.1.100]) by teena.dahlen.ws (8.12.9p2/8.12.8) with ESMTP id i2FChkKL098009 for ; Mon, 15 Mar 2004 13:43:46 +0100 (CET) (envelope-from andreas@dahlen.ws) From: =?iso-8859-1?Q?Andreas_Dahl=E9n?= To: Date: Mon, 15 Mar 2004 13:44:01 +0100 Message-ID: <000c01c40a8b$31a58700$6401000a@mikaela> MIME-Version: 1.0 X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook, Build 10.0.4024 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165 Importance: Normal X-AntiVirus: checked by AntiVir Milter 1.0.6; AVE 6.24.0.6; VDF 6.24.0.55 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable X-Content-Filtered-By: Mailman/MimeDel 2.1.1 Subject: Haupauge WinTV PVR250 X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Mar 2004 12:43:45 -0000 Hi! =20 I=92ve just bought a Haupauge WinTV PVR250 and installed it in my machin = e running FreeBSD 4.9 =20 I followed the instructions from John in http://docs.freebsd.org/cgi/getmsg.cgi?fetch=3D85121+0+/usr/local/www/db/= t ext/2004/freebsd-multimedia/20040208.freebsd-multimedia and also found the problem that Christoph (http://lists.freebsd.org/pipermail/freebsd-multimedia/2004-February/000 840.html) had. =20 When I run the following commands; =20 kldload cxm_iic kldload_cxm =20 I get the following =20 cxm0: mem 0xdc000000-0xdfffffff irq 10 at device 11.0 on pci0 cxm_iic0: on cxm0 iicbb0: on cxm_iic0 iicbus0: on iicbb0 master-only cxm0: unknown tuner code 0x30 cxm0: could not initialize tuner iicbus0: detached iicbb0: detached cxm_iic0: detached device_probe_and_attach: cxm0 attach returned 6 =20 =20 lspci =96v 00:0b.0 Multimedia video controller: Internext Compression Inc: Unknown device 0016 (rev 01) Subsystem: Hauppauge computer works Inc.: Unknown device 4009 Flags: bus master, medium devsel, latency 32, IRQ 10 Memory at dc000000 (32-bit, prefetchable) Capabilities: [44] Power Management version 2 =20 =20 pciconf -lv none1@pci0:11:0: class=3D0x040000 card=3D0x40090070 = chip=3D0x00164444 rev=3D0x01 hdr=3D0x00 vendor =3D 'Conexant Inc (Was: Globespan, ICompression Inc)' class =3D multimedia subclass =3D video =20 =20 I=92ve looked at the components of the card and found the following; Card: Hauppauge PVR250 model 986 (according to package) Model 32034, PAL B/G, rev. B148 (according to card) Tuner: LG TP18PSB11D MPEG 2 enc: Conexant CD23416-12 Sound encoder: MSP 3215G Assembeled: Week 47, 2003 =20 I guess that the drivers aren=92t updated to handle this new card. Does anyone (John?) have some hints what I should do modify the drivers to work? =20 /Andreas =20 From owner-freebsd-multimedia@FreeBSD.ORG Mon Mar 15 13:16:13 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 2FAD516A4CE for ; Mon, 15 Mar 2004 13:16:13 -0800 (PST) Received: from mpls-qmqp-04.inet.qwest.net (mpls-qmqp-04.inet.qwest.net [63.231.195.115]) by mx1.FreeBSD.org (Postfix) with SMTP id AC84443D1F for ; Mon, 15 Mar 2004 13:16:12 -0800 (PST) (envelope-from pete_mckenna@qwest.net) Received: (qmail 8510 invoked by uid 0); 15 Mar 2004 21:16:12 -0000 Received: from mpls-pop-04.inet.qwest.net (63.231.195.4) by mpls-qmqp-04.inet.qwest.net with QMQP; 15 Mar 2004 21:16:12 -0000 Received: from 63-231-169-227.mpls.qwest.net (HELO ?10.0.0.22?) (63.231.169.227) by mpls-pop-04.inet.qwest.net with SMTP; 15 Mar 2004 21:16:12 -0000 Date: Mon, 15 Mar 2004 10:13:41 -0600 Message-Id: From: "Pete McKenna" To: freebsd-multimedia@freebsd.org Mime-Version: 1.0 (Apple Message framework v612) Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed X-Mailer: Apple Mail (2.612) Subject: mplayer and lirc with X10 mp3anywhere remote X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Mar 2004 21:16:13 -0000 Does anyone have this working? I'm uncertain if version 0.6.6 of lirc supports the X10 mp3anywhere hardware. my log looks like this if I try to run irexec Mar 15 15:09:03 blotto lircd 0.6.6: lircd(any) ready Mar 15 15:09:32 blotto lircd 0.6.6: accepted new client on /dev/lircd Mar 15 15:09:32 blotto lircd 0.6.6: could not open mp3anywhere Mar 15 15:09:32 blotto lircd 0.6.6: default_init(): No such file or directory Mar 15 15:09:32 blotto lircd 0.6.6: caught signal I pulled the lircd.conf for the mp3anywhere from the lirc CVS. Should this work with the .0.6.6 lircd? If not what drivers etc need to be updated and recompiled? dev listing lrwxr-xr-x 1 root wheel 5 Mar 15 15:05 /dev/lirc -> ttyd0 srw-rw-rw- 1 root wheel 0 Mar 15 15:11 /dev/lircd lrwxr-xr-x 1 root wheel 5 Feb 3 01:04 /dev/lircm -> ttyd0 ~,lircrc begin flags = startup_mode mode = browser end begin remote = mp3anywhere button = PC prog = irexec repeat = 0 config = echo "Hello world!" end Thanks Pete From owner-freebsd-multimedia@FreeBSD.ORG Mon Mar 15 13:33:34 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 7CBE916A4CE for ; Mon, 15 Mar 2004 13:33:34 -0800 (PST) Received: from mail006.syd.optusnet.com.au (mail006.syd.optusnet.com.au [211.29.132.63]) by mx1.FreeBSD.org (Postfix) with ESMTP id 0166843D1F for ; Mon, 15 Mar 2004 13:33:32 -0800 (PST) (envelope-from akm@theinternet.com.au) Received: from theinternet.com.au (c211-30-103-113.carlnfd1.nsw.optusnet.com.au [211.30.103.113]) i2FLXRw28979; Tue, 16 Mar 2004 08:33:28 +1100 Received: from theinternet.com.au (localhost [127.0.0.1]) by theinternet.com.au (8.12.11/8.12.11) with ESMTP id i2FLXHBo021173; Tue, 16 Mar 2004 08:33:17 +1100 (EST) (envelope-from akm@theinternet.com.au) Received: (from akm@localhost) by theinternet.com.au (8.12.11/8.12.11/Submit) id i2FLXDid021169; Tue, 16 Mar 2004 08:33:13 +1100 (EST) (envelope-from akm) Date: Tue, 16 Mar 2004 08:33:13 +1100 From: Andrew Milton To: Pete McKenna Message-ID: <20040315213313.GN797@camelot.theinternet.com.au> Mail-Followup-To: Pete McKenna , freebsd-multimedia@freebsd.org References: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.6i cc: freebsd-multimedia@freebsd.org Subject: Re: mplayer and lirc with X10 mp3anywhere remote X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Mar 2004 21:33:34 -0000 +-------[ Pete McKenna ]---------------------- | Does anyone have this working? | I'm uncertain if version 0.6.6 of lirc | supports the X10 mp3anywhere hardware. | I pulled the lircd.conf for the mp3anywhere from the lirc CVS. | Should this work with the .0.6.6 lircd? If not what drivers etc | need to be updated and recompiled? lircd wants proper devices it can send ioctls to. Most if not all of the drivers are kernel modules and aren't ported, and the serial ones require that there be no serial driver in the kernel (at least for Linux). I've got a userland thing lying around that can spit out lirc compatible strings but, it only currently works for the cheap/nasty one wire PackardBell things (I don't have any other remote hardware to play with). If there's interest I'm happy to start a project somewhere with it so people can add more hardware to it. I use it to control freevo, so I know it works on at least a basic level. -- Totally Holistic Enterprises Internet| | Andrew Milton The Internet (Aust) Pty Ltd | M:+61 416 022 411 | ACN: 082 081 472 ABN: 83 082 081 472 |akm@theinternet.com.au| Carpe Daemon From owner-freebsd-multimedia@FreeBSD.ORG Tue Mar 16 23:20:19 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id D313816A4CF for ; Tue, 16 Mar 2004 23:20:19 -0800 (PST) Received: from teena.dahlen.ws (h96n2fls33o990.telia.com [213.67.6.96]) by mx1.FreeBSD.org (Postfix) with ESMTP id A31E343D3F for ; Tue, 16 Mar 2004 23:20:05 -0800 (PST) (envelope-from andreas@dahlen.ws) Received: from mikaela (mikaela.dahlen.ws [10.0.1.100]) by teena.dahlen.ws (8.12.9p2/8.12.8) with ESMTP id i2H7K6KL059046 for ; Wed, 17 Mar 2004 08:20:06 +0100 (CET) (envelope-from andreas@dahlen.ws) From: =?iso-8859-1?Q?Andreas_Dahl=E9n?= To: Date: Wed, 17 Mar 2004 08:20:30 +0100 Message-ID: <005201c40bf0$54345970$6401000a@mikaela> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook, Build 10.0.4024 In-Reply-To: <000c01c40a8b$31a58700$6401000a@mikaela> X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165 Importance: Normal X-AntiVirus: checked by AntiVir Milter 1.0.6; AVE 6.24.0.7; VDF 6.24.0.59 Subject: RE: Haupauge WinTV PVR250 X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Mar 2004 07:20:20 -0000 Hi, I've got some further information that may help solving the problem. To test my installation I downloaded the Linux-distribution KnoppMyth (http://mysettopbox.tv/knoppmyth.html) and installed it. After some tweaking of the configfiles I got the card to work. When loading the ivtv-drivers (http://ivtv.sourceforge.net) I get the following information about the card: tvee: Hauppauge: model=3D32034, rev=3DB148, serial#=3D6960535 tvee: tuner=3DLG TP18PSB11D (idx=3D48, type=3D29) tvee: tuner fmt=3DPAL(B/G) (eeprom=3D0x04, v4l2=3D0x00000007) tvee: audio_processor=3DMSP3415 (type=3D6) The cxm-driver in FreeBSD reports the card as type=3D0x30. The = ivtv-driver reports the card as type=3D29. I guesss that these values should be the same? Could it be the extraction of the firmware that differs? When looking through the code for the cxm-driver LG-tuners isn't mentioned anywhere. I guess that they should be added, but I don't know enough of the drivers/tuner to do the modification. Can anyone give me som information on what I need to change?=20 /Andreas -----Original Message----- From: owner-freebsd-multimedia@freebsd.org [mailto:owner-freebsd-multimedia@freebsd.org] On Behalf Of Andreas Dahl=E9n Sent: den 15 mars 2004 13:44 To: freebsd-multimedia@freebsd.org Subject: Haupauge WinTV PVR250 Hi! =20 I=92ve just bought a Haupauge WinTV PVR250 and installed it in my machin = e running FreeBSD 4.9 =20 I followed the instructions from John in http://docs.freebsd.org/cgi/getmsg.cgi?fetch=3D85121+0+/usr/local/www/db/= t ext/2004/freebsd-multimedia/20040208.freebsd-multimedia and also found the problem that Christoph (http://lists.freebsd.org/pipermail/freebsd-multimedia/2004-February/000 840.html) had. =20 When I run the following commands; =20 kldload cxm_iic kldload_cxm =20 I get the following =20 cxm0: mem 0xdc000000-0xdfffffff irq 10 at device 11.0 on pci0 cxm_iic0: on cxm0 iicbb0: on cxm_iic0 iicbus0: on iicbb0 master-only cxm0: unknown tuner code 0x30 cxm0: could not initialize tuner iicbus0: detached iicbb0: detached cxm_iic0: detached device_probe_and_attach: cxm0 attach returned 6 =20 =20 lspci =96v 00:0b.0 Multimedia video controller: Internext Compression Inc: Unknown device 0016 (rev 01) Subsystem: Hauppauge computer works Inc.: Unknown device 4009 Flags: bus master, medium devsel, latency 32, IRQ 10 Memory at dc000000 (32-bit, prefetchable) Capabilities: [44] Power Management version 2 =20 =20 pciconf -lv none1@pci0:11:0: class=3D0x040000 card=3D0x40090070 = chip=3D0x00164444 rev=3D0x01 hdr=3D0x00 vendor =3D 'Conexant Inc (Was: Globespan, ICompression Inc)' class =3D multimedia subclass =3D video =20 =20 I=92ve looked at the components of the card and found the following; Card: Hauppauge PVR250 model 986 (according to package) Model 32034, PAL B/G, rev. B148 (according to card) Tuner: LG TP18PSB11D MPEG 2 enc: Conexant CD23416-12 Sound encoder: MSP 3215G Assembeled: Week 47, 2003 =20 I guess that the drivers aren=92t updated to handle this new card. Does anyone (John?) have some hints what I should do modify the drivers to work? =20 /Andreas =20 _______________________________________________ freebsd-multimedia@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-multimedia To unsubscribe, send any mail to "freebsd-multimedia-unsubscribe@freebsd.org" From owner-freebsd-multimedia@FreeBSD.ORG Wed Mar 17 02:01:19 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id A765F16A4CE for ; Wed, 17 Mar 2004 02:01:19 -0800 (PST) Received: from raven.yorksj.ac.uk (raven.yorksj.ac.uk [193.61.224.236]) by mx1.FreeBSD.org (Postfix) with ESMTP id 78BC043D1D for ; Wed, 17 Mar 2004 02:01:19 -0800 (PST) (envelope-from yann@raven.yorksj.ac.uk) Received: from yann by raven.yorksj.ac.uk with local (Exim 4.30; FreeBSD) id 1B3XsC-000OvE-80 for freebsd-multimedia@freebsd.org; Wed, 17 Mar 2004 10:02:04 +0000 Date: Wed, 17 Mar 2004 10:02:04 +0000 From: Yann Golanski To: freebsd-multimedia@freebsd.org Message-ID: <20040317100204.GA95488@kierun.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.6i Sender: "Yann Golanski,University of York,+44(0)1904-433088" Subject: Surround sound. X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Mar 2004 10:01:19 -0000 I have a Creative sound blaster card with a 4:1 surround sound system -- also from Creative. It works fine under windows but when I try to use it with BSD, I can only get the front two speakers to output sound. Does anyone know how to solve this? Details of my system follow: Mar 16 20:59:42 rivendell kernel: pcm0: port 0xdc00-0xdc1f irq 5 at device 9.0 on pci0 Mar 16 20:59:42 rivendell kernel: pcm0: FreeBSD rivendell.neverness.org 5.1-RELEASE-p14 FreeBSD 5.1-RELEASE-p14 #0: Wed Mar 10 21:22:07 GMT 2004 root@rivendell.neverness.org:/usr/obj/usr/src/sys/GENERIC i386 -- yann@kierun.org -=*=- www.kierun.org PGP: 009D 7287 C4A7 FD4F 1680 06E4 F751 7006 9DE2 6318 From owner-freebsd-multimedia@FreeBSD.ORG Thu Mar 18 10:20:19 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 8A7B416A4E0 for ; Thu, 18 Mar 2004 10:20:19 -0800 (PST) Received: from mail014.syd.optusnet.com.au (mail014.syd.optusnet.com.au [211.29.132.160]) by mx1.FreeBSD.org (Postfix) with ESMTP id 3E25143D1D for ; Thu, 18 Mar 2004 10:20:07 -0800 (PST) (envelope-from akm@theinternet.com.au) Received: from theinternet.com.au (c211-30-103-113.carlnfd1.nsw.optusnet.com.au [211.30.103.113]) i2IIK5F11161 for ; Fri, 19 Mar 2004 05:20:05 +1100 Received: from theinternet.com.au (localhost [127.0.0.1]) by theinternet.com.au (8.12.11/8.12.11) with ESMTP id i2IIJwxC057698 for ; Fri, 19 Mar 2004 05:19:58 +1100 (EST) (envelope-from akm@theinternet.com.au) Received: (from akm@localhost) by theinternet.com.au (8.12.11/8.12.11/Submit) id i2IIJwQ0057697 for freebsd-multimedia@freebsd.org; Fri, 19 Mar 2004 05:19:58 +1100 (EST) (envelope-from akm) Date: Fri, 19 Mar 2004 05:19:58 +1100 From: Andrew Milton To: freebsd-multimedia@freebsd.org Message-ID: <20040318181958.GT54758@camelot.theinternet.com.au> Mail-Followup-To: freebsd-multimedia@freebsd.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.6i Subject: device bktr and smbus X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Mar 2004 18:20:19 -0000 I've been trying off and on (with cvsups in between) to compile a kernel with bktr and smbus support under -current. if I define options BKTR_USE_FREEBSD_SMBUS then the compile fails in bktr_core.c ../../../dev/bktr/bktr_core.c: In function `msp_dpl_write': ../../../dev/bktr/bktr_core.c:3910: error: structure has no member named `iicbus' there's two dozen or more places where it dies, related to this macro; #define IICBUS(bktr) ((bktr)->i2c_sc.iicbus) Is the BKTR_USE_FREEBSD_SMBUS option needed? (I can't access the remote control on this board, or do any smb ioctls without it anyway). Is there some simple fix for this? I'm happy to test patches / hacks d8) I've got these related options, I can post a full config if needed. device smbus device iicbus device iicbb device iicsmb device smb device iic device bktr options BKTR_GPIO_ACCESS options BKTR_SYSTEM_DEFAULT=BROOKTREE_PAL options BKTR_ALLOC_PAGES=532 options BKTR_NEW_MSP34XX_DRIVER options BKTR_USE_FREEBSD_SMBUS -- Totally Holistic Enterprises Internet| | Andrew Milton The Internet (Aust) Pty Ltd | M:+61 416 022 411 | ACN: 082 081 472 ABN: 83 082 081 472 |akm@theinternet.com.au| Carpe Daemon From owner-freebsd-multimedia@FreeBSD.ORG Thu Mar 18 22:46:28 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 64F3116A4CE for ; Thu, 18 Mar 2004 22:46:28 -0800 (PST) Received: from natsmtp01.rzone.de (natsmtp01.rzone.de [81.169.145.166]) by mx1.FreeBSD.org (Postfix) with ESMTP id CD3BC43D2F for ; Thu, 18 Mar 2004 22:46:27 -0800 (PST) (envelope-from wrips@kordel.de) Received: from nova.kordel.de (p5089F633.dip.t-dialin.net [80.137.246.51]) by post.webmailer.de (8.12.10/8.12.10) with ESMTP id i2J6kOlI013182 for ; Fri, 19 Mar 2004 07:46:26 +0100 (MET) Received: from mail.kordel.de (mail.kordel.de [192.6.1.245]) by nova.kordel.de (8.12.3/8.12.3) with ESMTP id i2J6aFK7069005 for ; Fri, 19 Mar 2004 07:36:24 +0100 (CET) (envelope-from wrips@kordel.de) Received: from kordel.de (edv-3.kordel.de [192.6.1.94]) by mail.kordel.de (8.12.9p2/8.12.9) with ESMTP id i2J6cLHu018496 for ; Fri, 19 Mar 2004 07:38:21 +0100 (CET) (envelope-from wrips@kordel.de) Message-ID: <405A9507.5040904@kordel.de> Date: Fri, 19 Mar 2004 07:36:55 +0100 From: Werner Rips User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 X-Accept-Language: de, en-us, en MIME-Version: 1.0 To: freebsd-multimedia@freebsd.org Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-AntiVirus: checked by AntiVir Milter 1.0.6; AVE 6.24.0.7; VDF 6.24.0.63 Subject: sound recording question with wavrec X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Mar 2004 06:46:28 -0000 Hello all, AMD CPU on K7S5A board with onboard sound FreeBSD 4.9 Try to record my favorite vinyl records into wave files. I connect the lineout of the stereo to the linein of the pc. When i start playing i get the sound signal on the lineout of the pc so i can listen to that sound (speakers connected). Now i start wavrec, but the resulting .wav file contains no sound even if all mixer channels are set to 75:75. The only way i get some sound into .wav file is when i connect the lineout of the stereo to the mic in of the pc. But that's very bad quality and no stereo signal even if i set wavrec -S -s 44100 -b 16. Please tell me how to adjust wavrec that it records from linein. Thanks in advance Werner From owner-freebsd-multimedia@FreeBSD.ORG Fri Mar 19 00:19:30 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 372A216A4CF for ; Fri, 19 Mar 2004 00:19:30 -0800 (PST) Received: from maestro.tackymt.homeip.net (YahooBB219181148140.bbtec.net [219.181.148.140]) by mx1.FreeBSD.org (Postfix) with ESMTP id 861F943D2F for ; Fri, 19 Mar 2004 00:19:27 -0800 (PST) (envelope-from taku@cent.saitama-u.ac.jp) Received: from YahooBB219181148140.bbtec.net (localhost [IPv6:::1]) i2J8JKEZ006254; Fri, 19 Mar 2004 17:19:21 +0900 (JST) (envelope-from taku@cent.saitama-u.ac.jp) Date: Fri, 19 Mar 2004 17:19:20 +0900 From: Taku YAMAMOTO To: Werner Rips Message-Id: <20040319171920.2e05d9ef.taku@cent.saitama-u.ac.jp> In-Reply-To: <405A9507.5040904@kordel.de> References: <405A9507.5040904@kordel.de> Organization: Advanced Computer and Communication Studies Society X-Mailer: Sylpheed version 0.9.8a-gtk2-20040109 (GTK+ 2.2.4; i386-portbld-freebsd5.2) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit cc: freebsd-multimedia@freebsd.org Subject: Re: sound recording question with wavrec X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Mar 2004 08:19:30 -0000 Have you set recording source properly? What does the command `mixer recsrc` say? Hint: mixer =rec line -- -|-__ YAMAMOTO, Taku | __ < From owner-freebsd-multimedia@FreeBSD.ORG Fri Mar 19 04:58:13 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 00C0916A4CE for ; Fri, 19 Mar 2004 04:58:13 -0800 (PST) Received: from smtp-out3.blueyonder.co.uk (smtp-out3.blueyonder.co.uk [195.188.213.6]) by mx1.FreeBSD.org (Postfix) with ESMTP id 3D6A243D39 for ; Fri, 19 Mar 2004 04:58:12 -0800 (PST) (envelope-from steve@pepcross.dyndns.org) Received: from pepcross.dyndns.org ([82.33.88.87]) by smtp-out3.blueyonder.co.uk with Microsoft SMTPSVC(5.0.2195.5600); Fri, 19 Mar 2004 12:58:11 +0000 Received: (from steve@localhost) by pepcross.dyndns.org (8.12.10/8.12.9/Submit) id i2JCwFJ7000687 for freebsd-multimedia@freebsd.org; Fri, 19 Mar 2004 12:58:15 GMT Date: Fri, 19 Mar 2004 12:58:15 +0000 From: Steve Roome To: freebsd-multimedia@freebsd.org Message-ID: <20040319125815.GA559@dylan.home> Mail-Followup-To: Steve Roome , freebsd-multimedia@freebsd.org References: <405A9507.5040904@kordel.de> <20040319171920.2e05d9ef.taku@cent.saitama-u.ac.jp> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20040319171920.2e05d9ef.taku@cent.saitama-u.ac.jp> User-Agent: Mutt/1.4.1i X-OriginalArrivalTime: 19 Mar 2004 12:58:11.0398 (UTC) FILETIME=[D5686E60:01C40DB1] Subject: Re: sound recording question with wavrec X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Mar 2004 12:58:13 -0000 On Fri, Mar 19, 2004 at 05:19:20PM +0900, Taku YAMAMOTO wrote: > Have you set recording source properly? > What does the command `mixer recsrc` say? > > Hint: mixer =rec line It should probably mention in the manpage that some shell users will need to escape the equals as in "mixer \=rec line". I may be stupid, but failing that, mixer doesn't appear to work properly, or at least not as advertised, I've pondered whining about this one for a while. For example, in plain old /bin/sh $ mixer -rec line mixer: illegal option -- r mixer: illegal option -- e mixer: illegal option -- c usage: mixer [-f device] [-s] [dev [+|-][voll[:[+|-]volr]] ... mixer [-f device] [-s] recsrc ... mixer [-f device] [-s] {^|+|-|=}rec rdev ... devices: vol, pcm, speaker, line, mic, cd, rec, ogain, line1, phin, phout, video rec devices: vol, line, mic, cd, line1, phin, phout, video $ mixer +rec line Recording source: line $ mixer --rec line Mixer line is currently set to 75:75 $ mixer =rec line Recording source: line $ mixer Mixer vol is currently set to 75:75 Mixer pcm is currently set to 75:75 Mixer speaker is currently set to 75:75 Mixer line is currently set to 75:75 Mixer mic is currently set to 0:0 Mixer cd is currently set to 75:75 Mixer rec is currently set to 0:0 Mixer ogain is currently set to 50:50 Mixer line1 is currently set to 75:75 Mixer phin is currently set to 0:0 Mixer phout is currently set to 0:0 Mixer video is currently set to 75:75 Recording source: mic $ mixer ^rec line Recording source: line $ mixer \^rec line Recording source: mic $ mixer ^rec line Recording source: line Note how ^ doesn't seem toggle recording devices properly. Obviously the toggle and possibility of having multiple record devices might be due to the driver/mixer api. (i.e. mixer asks something to be done, and driver says yes, but the mixer program doesn't ask the driver about the value it just set afterwards and beleives that if the ioctl worked then the parameter was changed correctly... or something like that.) Steve Roome From owner-freebsd-multimedia@FreeBSD.ORG Fri Mar 19 05:37:29 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 3E8FB16A4CE for ; Fri, 19 Mar 2004 05:37:29 -0800 (PST) Received: from mail1.ewetel.de (mail1-106.ewetel.de [212.6.122.106]) by mx1.FreeBSD.org (Postfix) with ESMTP id A8C3F43D2D for ; Fri, 19 Mar 2004 05:37:28 -0800 (PST) (envelope-from uwe@laverenz.de) Received: from athena.laverenz.de (dialin-72159.ewetel.net [212.6.72.159]) by mail1.ewetel.de (8.12.1/8.12.9) with ESMTP id i2JDbPMN006526 for ; Fri, 19 Mar 2004 14:37:27 +0100 (MET) Received: from localhost (localhost.laverenz.de [127.0.0.1]) by athena.laverenz.de (Postfix) with ESMTP id 1EA3457F0D for ; Fri, 19 Mar 2004 14:37:25 +0100 (CET) Received: from athena.laverenz.de ([127.0.0.1]) by localhost (athena.laverenz.de [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 20641-02 for ; Fri, 19 Mar 2004 14:37:21 +0100 (CET) Received: from laverenz.de (voodoo.laverenz.de [192.168.100.3]) by athena.laverenz.de (Postfix) with ESMTP id DF2C957EBD for ; Fri, 19 Mar 2004 14:37:20 +0100 (CET) Message-ID: <405AF77A.6070800@laverenz.de> Date: Fri, 19 Mar 2004 14:36:58 +0100 From: Uwe Laverenz Organization: private site User-Agent: Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040319 X-Accept-Language: en-us, en MIME-Version: 1.0 To: freebsd-multimedia@freebsd.org References: <405A9507.5040904@kordel.de> In-Reply-To: <405A9507.5040904@kordel.de> Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: by amavisd-new at laverenz.de X-CheckCompat: OK Subject: Re: sound recording question with wavrec X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Mar 2004 13:37:29 -0000 Werner Rips wrote: > Please tell me how to adjust wavrec that it records from linein. Use the utility "mixer": $ mixer \=rec line For more details, have a look at the man page, mixer(8). cu, Uwe From owner-freebsd-multimedia@FreeBSD.ORG Sat Mar 20 21:28:35 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id C88FC16A4CE for ; Sat, 20 Mar 2004 21:28:35 -0800 (PST) Received: from feith1.FEITH.COM (feith1.FEITH.COM [192.251.93.1]) by mx1.FreeBSD.org (Postfix) with ESMTP id 714F943D31 for ; Sat, 20 Mar 2004 21:28:34 -0800 (PST) (envelope-from john@feith.com) Received: from jwlab.FEITH.COM (jwlab.FEITH.COM [192.251.93.16]) by feith1.FEITH.COM (8.12.10+Sun/8.12.9) with ESMTP id i2L5STIt019805; Sun, 21 Mar 2004 00:28:29 -0500 (EST) Received: (from john@localhost) by jwlab.FEITH.COM (8.11.7p1+Sun/8.11.7) id i2L5SOv13936; Sun, 21 Mar 2004 00:28:24 -0500 (EST) Date: Sun, 21 Mar 2004 00:28:24 -0500 (EST) From: John Wehle Message-Id: <200403210528.i2L5SOv13936@jwlab.FEITH.COM> To: christoph.schnauss@berlin.de Content-Type: text X-Scanned-By: MIMEDefang 2.39 X-Archived: cashew.FEITH.COM cc: freebsd-multimedia@freebsd.org Subject: Re: Hauppauge WinTV PVR 250 for FreeBSD 5.2 X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Mar 2004 05:28:36 -0000 > cxm0: unknown tuner code 0x30 Enclosed is a current snapshot of my source tree which supports the LG Innotek tuners. > he falls out to the "db>"-prompt. This happens when cxm_attach fails or cxm_detach is called due to a problem with iicbb. The patch to iicbb.c which implements iicbb_child_detached fixes the problem. It sounds like somehow you're using a module which is missing that fix. If that's not the case then you'll have to debug it further. -- John ------------------8<------------------------8<------------------------ [ This is the Mar 20, 2004 snapshot of my source tree. Included are changes to support some more ioctls and various PAL tuners. ] To use the Hauppauge PVR-250 / 350 on FreeBSD 4.9 / 5.2: 1) Use patch to apply Patch.iicbb so cxm can use the i2c bus and avoid a crash when unloading. 2) Unshar the enclosed archive into /sys. 3) Place a current version of hcwpvrp2.sys from the Hauppauge drivers into /sys/dev/cxm. Extract the the firmware by: # cd /sys/dev/cxm # cc -o cxm_extract_fw cxm_extract_fw.c # ./cxm_extract_fw hcwpvrp2.sys 4) Rebuilt your kernel with: device iicbus device iicbb as part of the configuration. 5) Install the new kernel and reboot. 6) Make and install the cxm driver by: # cd /sys/modules/cxm # make # cp cxm/cxm.ko cxm_iic/cxm_iic.ko /modules # kldload cxm_iic # kldload cxm At which point your console should say something like: cxm0: mem 0xd8000000-0xdbffffff irq 12 at device 10 .0 on pci0 cxm_iic0: on cxm0 iicbb0: on cxm_iic0 cxm0: Philips FI1236 MK2 tuner cxm0: SAA7115 rev 1 video decoder cxm0: MSP3435G-B6 audio decoder cxm0: IR Remote cxm0: encoder firmware version 0x2040011 cxm0: decoder firmware version 0x2020023 7) On FreeBSD 4.9 make the device nodes by: # cd /dev # ./MAKEDEV bktr0 On FreeBSD 5.2 the device node is /dev/cxm0 and magically appears when the cxm modules is loaded. A subset of the bt848 and meteor ioctls are supported. The more interesting ones being: TVTUNER_SETCHNL - Set the channel (default to 4). BT848_SCAPAREA - Set the capture area / format (defaults to DVD). VCD: 352 x 240 or 352 x 288 SVCD: 480 x 480 or 480 x 576 DVD: 720 x 480 or 720 x 576 METEORCAPTUR - Start / stop the capture. Capture is also started if a read occurs when the data buffer is empty. To capture a MPEG program stream from the current channel simply cat /dev/bktr0 > filename.mpeg. Though to ensure a clean capture you probably want to do something like: 1) Read data until the TV show has ended. 2) Use METEORCAPTUR to end the capture. 3) Use poll to determine if there is any data remaining in the device. Read the data as long as poll says there's data in the buffer. otherwise the end of the mpeg program stream will probably be corrupt. ------------------8<------------------------8<------------------------ # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # dev/cxm # dev/cxm/Patch.iicbb # dev/cxm/cxm.c # dev/cxm/cxm.h # dev/cxm/cxm_audio.c # dev/cxm/cxm_eeprom.c # dev/cxm/cxm_i2c.c # dev/cxm/cxm_ir.c # dev/cxm/cxm_tuner.c # dev/cxm/cxm_video.c # dev/cxm/cxm_extract_fw.c # modules/cxm # modules/cxm/Makefile # modules/cxm/cxm # modules/cxm/cxm/Makefile # modules/cxm/cxm_iic # modules/cxm/cxm_iic/Makefile # echo c - dev/cxm mkdir -p dev/cxm > /dev/null 2>&1 echo x - dev/cxm/Patch.iicbb sed 's/^X//' >dev/cxm/Patch.iicbb << 'END-of-dev/cxm/Patch.iicbb' X*** dev/iicbus/iicbb.c.ORIGINAL Sat Apr 20 12:38:43 2002 X--- dev/iicbus/iicbb.c Thu Jan 29 01:46:55 2004 X*************** struct iicbb_softc { X*** 71,76 **** X--- 71,77 ---- X static int iicbb_probe(device_t); X static int iicbb_attach(device_t); X static int iicbb_detach(device_t); X+ static void iicbb_child_detached(device_t, device_t); X static int iicbb_print_child(device_t, device_t); X X static int iicbb_callback(device_t, int, caddr_t); X*************** static device_method_t iicbb_methods[] = X*** 87,92 **** X--- 88,94 ---- X DEVMETHOD(device_detach, iicbb_detach), X X /* bus interface */ X+ DEVMETHOD(bus_child_detached, iicbb_child_detached), X DEVMETHOD(bus_print_child, iicbb_print_child), X X /* iicbus interface */ X*************** static int iicbb_attach(device_t dev) X*** 135,149 **** X static int iicbb_detach(device_t dev) X { X struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); X X! if (sc->iicbus) { X! bus_generic_detach(dev); X! device_delete_child(dev, sc->iicbus); X! } X X return (0); X } X X static int X iicbb_print_child(device_t bus, device_t dev) X { X--- 137,170 ---- X static int iicbb_detach(device_t dev) X { X struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); X+ device_t child; X X! /* X! * Detach the children before recursively deleting X! * in case a child has a pointer to a grandchild X! * which is used by the child's detach routine. X! * X! * Remember the child before detaching so we can X! * delete it (bus_generic_detach indirectly zeroes X! * sc->child_dev). X! */ X! child = sc->iicbus; X! bus_generic_detach(dev); X! if (child) X! device_delete_child(dev, child); X X return (0); X } X X+ static void X+ iicbb_child_detached( device_t dev, device_t child ) X+ { X+ struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev); X+ X+ if (child == sc->iicbus) X+ sc->iicbus = NULL; X+ } X+ X static int X iicbb_print_child(device_t bus, device_t dev) X { X*************** static int iicbb_read(device_t dev, char X*** 345,349 **** X--- 366,371 ---- X } X X DRIVER_MODULE(iicbb, bti2c, iicbb_driver, iicbb_devclass, 0, 0); X+ DRIVER_MODULE(iicbb, cxm_iic, iicbb_driver, iicbb_devclass, 0, 0); X DRIVER_MODULE(iicbb, lpbb, iicbb_driver, iicbb_devclass, 0, 0); X DRIVER_MODULE(iicbb, viapm, iicbb_driver, iicbb_devclass, 0, 0); END-of-dev/cxm/Patch.iicbb echo x - dev/cxm/cxm.c sed 's/^X//' >dev/cxm/cxm.c << 'END-of-dev/cxm/cxm.c' X/* X * Copyright (c) 2003, 2004 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * Conexant MPEG-2 Codec driver. Supports the CX23415 / CX23416 X * chips that are on the Hauppauge PVR-250 and PVR-350 video X * capture cards. Currently only the encoder is supported. X * X * This driver was written using the invaluable information X * compiled by The IvyTV Project (ivtv.sourceforge.net). X */ X X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X X#if __FreeBSD_version >= 500014 X# include X#else X# include X#endif X X#include X#include X#include X#include X X#include X#include X X#include X#include X X#if __FreeBSD_version < 500000 X# include X# include X#else X# include X# include X#endif X X#include X X X/* X * Various supported device vendors/types and their names. X */ Xstatic struct cxm_dev cxm_devs[] = { X { CXM_VENDORID_CONEXANT, CXM_DEVICEID_CONEXANT_iTVC15, X "Conexant iTVC15 MPEG Coder" }, X { CXM_VENDORID_CONEXANT, CXM_DEVICEID_CONEXANT_iTVC16, X "Conexant iTVC16 MPEG Coder" }, X { 0, 0, NULL } X}; X X Xstatic int cxm_probe( device_t dev ); Xstatic int cxm_attach( device_t dev ); Xstatic int cxm_detach( device_t dev ); Xstatic int cxm_shutdown( device_t dev ); Xstatic void cxm_intr( void *arg ); X Xstatic void cxm_child_detached( device_t dev, device_t child ); Xstatic int cxm_read_ivar( device_t bus, device_t dev, X int index, uintptr_t* val); Xstatic int cxm_write_ivar( device_t bus, device_t dev, X int index, uintptr_t val); X X Xstatic device_method_t cxm_methods[] = { X /* Device interface */ X DEVMETHOD(device_probe, cxm_probe), X DEVMETHOD(device_attach, cxm_attach), X DEVMETHOD(device_detach, cxm_detach), X DEVMETHOD(device_shutdown, cxm_shutdown), X X /* bus interface */ X DEVMETHOD(bus_child_detached, cxm_child_detached), X DEVMETHOD(bus_print_child, bus_generic_print_child), X DEVMETHOD(bus_driver_added, bus_generic_driver_added), X DEVMETHOD(bus_read_ivar, cxm_read_ivar), X DEVMETHOD(bus_write_ivar, cxm_write_ivar), X X { 0, 0 } X}; X Xstatic driver_t cxm_driver = { X "cxm", X cxm_methods, X sizeof(struct cxm_softc), X}; X Xstatic devclass_t cxm_devclass; X Xstatic d_open_t cxm_open; Xstatic d_close_t cxm_close; Xstatic d_read_t cxm_read; Xstatic d_ioctl_t cxm_ioctl; Xstatic d_poll_t cxm_poll; X X#if __FreeBSD_version < 500000 X# define CDEV_MAJOR 92 X#else X# define CDEV_MAJOR MAJOR_AUTO X#endif X Xstatic struct cdevsw cxm_cdevsw = { X#if __FreeBSD_version < 500000 X .d_bmaj = -1, X#endif X .d_maj = CDEV_MAJOR, X .d_name = "cxm", X .d_open = cxm_open, X .d_close = cxm_close, X .d_read = cxm_read, X .d_ioctl = cxm_ioctl, X .d_poll = cxm_poll X}; X XMODULE_DEPEND(cxm, cxm_iic, 1, 1, 1); XDRIVER_MODULE(cxm, pci, cxm_driver, cxm_devclass, 0, 0); X X X/* X * Various profiles. X */ Xstatic struct cxm_codec_profile vcd_ntsc_profile = { X "MPEG-1 VideoCD NTSC video and MPEG audio", X CXM_FW_STREAM_TYPE_VCD, X 30, X 352, 240, 480, X { 10, 12, 21 }, X 12, X 0, X { 1, 1150000, 0 }, X { 0, 15, 3}, X /* X * Spatial filter = Manual, Temporal filter = Manual X * Median filter = Horizontal / Vertical X * Spatial filter value = 1, Temporal filter value = 4 X */ X { 0, 3, 1, 4 }, X /* 44.1 Khz, MPEG-1 Layer II, 224 kb/s */ X 0xb8 X}; X Xstatic struct cxm_codec_profile vcd_pal_profile = { X "MPEG-1 VideoCD PAL video and MPEG audio", X CXM_FW_STREAM_TYPE_VCD, X 25, X 352, 288, 576, X { 6, 17, 22 }, X 8, X 0, X { 1, 1150000, 0 }, X { 0, 12, 3}, X /* X * Spatial filter = Manual, Temporal filter = Manual X * Median filter = Horizontal / Vertical X * Spatial filter value = 1, Temporal filter value = 4 X */ X { 0, 3, 1, 4 }, X /* 44.1 Khz, MPEG-1 Layer II, 224 kb/s */ X 0xb8 X}; X Xstatic struct cxm_codec_profile svcd_ntsc_profile = { X "MPEG-2 SuperVCD NTSC video and MPEG audio", X CXM_FW_STREAM_TYPE_SVCD, X 30, X 480, 480, 480, X { 10, 12, 21 }, X 2, X 0, X /* 2.5 Mb/s peak limit to keep bbdmux followed by mplex -f 4 happy */ X { 0, 1150000, 2500000 }, X { 0, 15, 3}, X /* X * Spatial filter = Manual, Temporal filter = Manual X * Median filter = Horizontal / Vertical X * Spatial filter value = 1, Temporal filter value = 4 X */ X { 0, 3, 1, 4 }, X /* 44.1 Khz, MPEG-1 Layer II, 224 kb/s */ X 0xb8 X}; X Xstatic struct cxm_codec_profile svcd_pal_profile = { X "MPEG-2 SuperVCD PAL video and MPEG audio", X CXM_FW_STREAM_TYPE_SVCD, X 25, X 480, 576, 576, X { 6, 17, 22 }, X 2, X 0, X /* 2.5 Mb/s peak limit to keep bbdmux followed by mplex -f 4 happy */ X { 0, 1150000, 2500000 }, X { 0, 12, 3}, X /* X * Spatial filter = Manual, Temporal filter = Manual X * Median filter = Horizontal / Vertical X * Spatial filter value = 1, Temporal filter value = 4 X */ X { 0, 3, 1, 4 }, X /* 44.1 Khz, MPEG-1 Layer II, 224 kb/s */ X 0xb8 X}; X Xstatic struct cxm_codec_profile dvd_ntsc_profile = { X "MPEG-2 DVD NTSC video and MPEG audio", X CXM_FW_STREAM_TYPE_DVD, X 30, X 720, 480, 480, X { 10, 12, 21 }, X 2, X 0, X /* 9.52 Mb/s peak limit to keep bbdmux followed by mplex -f 8 happy */ X { 0, 9000000, 9520000 }, X { 0, 15, 3}, X /* X * Spatial filter = Manual, Temporal filter = Manual X * Median filter = Horizontal / Vertical X * Spatial filter value = 1, Temporal filter value = 4 X */ X { 0, 3, 1, 4 }, X /* 48 Khz, MPEG-1 Layer II, 384 kb/s */ X 0xe9 X}; X Xstatic struct cxm_codec_profile dvd_pal_profile = { X "MPEG-2 DVD PAL video and MPEG audio", X CXM_FW_STREAM_TYPE_DVD, X 25, X 720, 576, 576, X { 6, 17, 22 }, X 2, X 0, X /* 9.52 Mb/s peak limit to keep bbdmux followed by mplex -f 8 happy */ X { 0, 9000000, 9520000 }, X { 0, 12, 3}, X /* X * Spatial filter = Manual, Temporal filter = Manual X * Median filter = Horizontal / Vertical X * Spatial filter value = 1, Temporal filter value = 4 X */ X { 0, 3, 1, 4 }, X /* 48 Khz, MPEG-1 Layer II, 384 kb/s */ X 0xe9 X}; X Xstatic const struct cxm_codec_profile X*codec_profiles[] = { X &vcd_ntsc_profile, X &vcd_pal_profile, X &svcd_ntsc_profile, X &svcd_pal_profile, X &dvd_ntsc_profile, X &dvd_pal_profile X}; X X Xstatic unsigned int Xcxm_queue_firmware_command( struct cxm_softc *sc, X enum cxm_mailbox_name mbx_name, u_int32_t cmd, X u_int32_t *parameters, unsigned int nparameters ) X{ X unsigned int i; X unsigned int mailbox; X u_int32_t completed_command; X u_int32_t flags; X intrmask_t s; X X if (nparameters > CXM_MBX_MAX_PARAMETERS) { X printf("%s: too many parameters for mailbox\n", sc->name); X return -1; X } X X mailbox = 0; X X switch (mbx_name) { X case cxm_dec_mailbox: X mailbox = sc->dec_mbx X + CXM_MBX_FW_CMD_MAILBOX *sizeof(struct cxm_mailbox); X break; X X case cxm_enc_mailbox: X mailbox = sc->enc_mbx X + CXM_MBX_FW_CMD_MAILBOX *sizeof(struct cxm_mailbox); X break; X X default: X return -1; X } X X s = spltty(); X for (i = 0; i < CXM_MBX_FW_CMD_MAILBOXES; i++) { X flags = CSR_READ_4(sc, X mailbox X + offsetof(struct cxm_mailbox, flags)); X if (! (flags & CXM_MBX_FLAG_IN_USE) ) X break; X X /* X * Mail boxes containing certain completed commands X * for which the results are never needed can be reused. X */ X X if ((flags & (CXM_MBX_FLAG_DRV_DONE | CXM_MBX_FLAG_FW_DONE)) X == (CXM_MBX_FLAG_DRV_DONE | CXM_MBX_FLAG_FW_DONE)) { X completed_command X = CSR_READ_4(sc, X mailbox X + offsetof(struct cxm_mailbox, command)); X X /* X * DMA results are always check by reading the X * DMA status register ... never by checking X * the mailbox after the command has completed. X */ X X if (completed_command == CXM_FW_CMD_SCHED_DMA_TO_HOST) X break; X } X X mailbox += sizeof(struct cxm_mailbox); X } X X if (i >= CXM_MBX_FW_CMD_MAILBOXES) { X splx(s); X return -1; X } X X CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags), X CXM_MBX_FLAG_IN_USE); X splx(s); X X CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, command), cmd); X CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, timeout), X CXM_FW_STD_TIMEOUT); X X for (i = 0; i < nparameters; i++) X CSR_WRITE_4(sc, X mailbox X + offsetof(struct cxm_mailbox, parameters) X + i * sizeof(u_int32_t), X *(parameters + i)); X X for ( ; i < CXM_MBX_MAX_PARAMETERS; i++) X CSR_WRITE_4(sc, X mailbox X + offsetof(struct cxm_mailbox, parameters) X + i * sizeof(u_int32_t), 0); X X CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags), X CXM_MBX_FLAG_IN_USE | CXM_MBX_FLAG_DRV_DONE); X X return mailbox; X} X X Xstatic int Xcxm_firmware_command( struct cxm_softc *sc, X enum cxm_mailbox_name mbx_name, u_int32_t cmd, X u_int32_t *parameters, unsigned int nparameters ) X{ X const char *wmesg; X unsigned int *bmp; X unsigned int i; X unsigned int mailbox; X u_int32_t flags; X u_int32_t result; X X bmp = NULL; X wmesg = ""; X X switch (mbx_name) { X case cxm_dec_mailbox: X bmp = &sc->dec_mbx; X wmesg = "cxmdfw"; X break; X X case cxm_enc_mailbox: X bmp = &sc->enc_mbx; X wmesg = "cxmefw"; X break; X X default: X return -1; X } X X mailbox = cxm_queue_firmware_command(sc, mbx_name, cmd, X parameters, nparameters); X if (mailbox == -1) { X printf("%s: no free mailboxes\n", sc->name); X return -1; X } X X /* Give the firmware a chance to start processing the request */ X (void)tsleep(bmp, PWAIT, wmesg, hz / 100); X X for (i = 0; i < 100; i++) { X flags = CSR_READ_4(sc, X mailbox X + offsetof(struct cxm_mailbox, flags)); X if ( (flags & CXM_MBX_FLAG_FW_DONE) ) X break; X X /* Wait for 10ms */ X (void)tsleep(bmp, PWAIT, wmesg, hz / 100); X } X X if (i >= 100) { X printf("%s: timeout\n", sc->name); X return -1; X } X X result = CSR_READ_4(sc, X mailbox X + offsetof(struct cxm_mailbox, result)); X X for (i = 0; i < nparameters; i++) X *(parameters + i) X = CSR_READ_4(sc, X mailbox X + offsetof(struct cxm_mailbox, parameters) X + i * sizeof(u_int32_t)); X X CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags), 0); X X return result == 0 ? 0 : -1; X} X X Xstatic int Xcxm_firmware_command_nosleep( struct cxm_softc *sc, X enum cxm_mailbox_name mbx_name, u_int32_t cmd, X u_int32_t *parameters, unsigned int nparameters ) X{ X unsigned int i; X unsigned int mailbox; X u_int32_t flags; X u_int32_t result; X X for (i = 0; i < 100; i++) { X mailbox = cxm_queue_firmware_command(sc, mbx_name, cmd, X parameters, nparameters); X if (mailbox != -1) X break; X X /* Wait for 10ms */ X DELAY(10000); X } X X if (i >= 100) { X printf("%s: no free mailboxes\n", sc->name); X return -1; X } X X /* Give the firmware a chance to start processing the request */ X DELAY(10000); X X for (i = 0; i < 100; i++) { X flags = CSR_READ_4(sc, X mailbox X + offsetof(struct cxm_mailbox, flags)); X if ( (flags & CXM_MBX_FLAG_FW_DONE) ) X break; X X /* Wait for 10ms */ X DELAY(10000); X } X X if (i >= 100) { X printf("%s: timeout\n", sc->name); X return -1; X } X X result = CSR_READ_4(sc, X mailbox X + offsetof(struct cxm_mailbox, result)); X X for (i = 0; i < nparameters; i++) X *(parameters + i) X = CSR_READ_4(sc, X mailbox X + offsetof(struct cxm_mailbox, parameters) X + i * sizeof(u_int32_t)); X X CSR_WRITE_4(sc, mailbox + offsetof(struct cxm_mailbox, flags), 0); X X return result == 0 ? 0 : -1; X} X X Xstatic int Xcxm_stop_firmware( struct cxm_softc *sc ) X{ X X if (cxm_firmware_command_nosleep(sc, cxm_enc_mailbox, X CXM_FW_CMD_ENC_HALT_FW, NULL, 0) < 0) X return -1; X X if (sc->type == cxm_iTVC15_type X && cxm_firmware_command_nosleep(sc, cxm_dec_mailbox, X CXM_FW_CMD_DEC_HALT_FW, X NULL, 0) < 0) X return -1; X X /* Wait for 10ms */ X DELAY(10000); X X return 0; X} X X Xstatic void Xcxm_set_irq_mask( struct cxm_softc *sc, u_int32_t mask ) X{ X intrmask_t s; X X s = spltty(); X X CSR_WRITE_4(sc, CXM_REG_IRQ_MASK, mask); X X /* X * PCI writes may be buffered so force the X * write to complete by reading the last X * location written. X */ X X (void)CSR_READ_4(sc, CXM_REG_IRQ_MASK); X X sc->irq_mask = mask; X X splx(s); X} X X Xstatic void Xcxm_set_irq_status( struct cxm_softc *sc, u_int32_t status ) X{ X X CSR_WRITE_4(sc, CXM_REG_IRQ_STATUS, status); X X /* X * PCI writes may be buffered so force the X * write to complete by reading the last X * location written. X */ X X (void)CSR_READ_4(sc, CXM_REG_IRQ_STATUS); X} X X Xstatic int Xcxm_stop_hardware( struct cxm_softc *sc ) X{ X X if (sc->cxm_iic) { X if (cxm_saa7115_mute(sc) < 0) X return -1; X if (cxm_msp_mute(sc) < 0) X return -1; X } X X /* Halt the firmware */ X if (sc->enc_mbx != -1) { X if (cxm_stop_firmware(sc) < 0) X return -1; X } X X /* Mask all interrupts */ X cxm_set_irq_mask(sc, 0xffffffff); X X /* Stop VDM */ X CSR_WRITE_4(sc, CXM_REG_VDM, CXM_CMD_VDM_STOP); X X /* Stop AO */ X CSR_WRITE_4(sc, CXM_REG_AO, CXM_CMD_AO_STOP); X X /* Ping (?) APU */ X CSR_WRITE_4(sc, CXM_REG_APU, CXM_CMD_APU_PING); X X /* Stop VPU */ X CSR_WRITE_4(sc, CXM_REG_VPU, sc->type == cxm_iTVC15_type X ? CXM_CMD_VPU_STOP15 X : CXM_CMD_VPU_STOP16); X X /* Reset Hw Blocks */ X CSR_WRITE_4(sc, CXM_REG_HW_BLOCKS, CXM_CMD_HW_BLOCKS_RST); X X /* Stop SPU */ X CSR_WRITE_4(sc, CXM_REG_SPU, CXM_CMD_SPU_STOP); X X /* Wait for 10ms */ X DELAY(10000); X X return 0; X} X X Xstatic int Xcxm_download_firmware( struct cxm_softc *sc ) X{ X unsigned int i; X const u_int32_t *fw; X X /* Download the encoder firmware */ X fw = (const u_int32_t *)cxm_enc_fw; X for (i = 0; i < CXM_FW_SIZE; i += sizeof(*fw)) X CSR_WRITE_4(sc, CXM_MEM_ENC + i, *fw++); X X /* Download the decoder firmware */ X if (sc->type == cxm_iTVC15_type) { X fw = (const u_int32_t *)cxm_dec_fw; X for (i = 0; i < CXM_FW_SIZE; i += sizeof(*fw)) X CSR_WRITE_4(sc, CXM_MEM_DEC + i, *fw++); X } X X return 0; X} X X Xstatic int Xcxm_init_hardware( struct cxm_softc *sc ) X{ X unsigned int i; X unsigned int mailbox; X u_int32_t parameter; X X if (cxm_stop_hardware(sc) < 0) X return -1; X X /* Initialize encoder SDRAM pre-charge */ X CSR_WRITE_4(sc, CXM_REG_ENC_SDRAM_PRECHARGE, X CXM_CMD_SDRAM_PRECHARGE_INIT); X X /* Initialize encoder SDRAM refresh to 1us */ X CSR_WRITE_4(sc, CXM_REG_ENC_SDRAM_REFRESH, X CXM_CMD_SDRAM_REFRESH_INIT); X X /* Initialize decoder SDRAM pre-charge */ X CSR_WRITE_4(sc, CXM_REG_DEC_SDRAM_PRECHARGE, X CXM_CMD_SDRAM_PRECHARGE_INIT); X X /* Initialize decoder SDRAM refresh to 1us */ X CSR_WRITE_4(sc, CXM_REG_DEC_SDRAM_REFRESH, X CXM_CMD_SDRAM_REFRESH_INIT); X X /* Wait for 600ms */ X DELAY(600000); X X if (cxm_download_firmware(sc) < 0) X return -1; X X /* Enable SPU */ X CSR_WRITE_4(sc, CXM_REG_SPU, X CSR_READ_4(sc, CXM_REG_SPU) & CXM_MASK_SPU_ENABLE); X X /* Wait for 1 second */ X DELAY(1000000); X X /* Enable VPU */ X CSR_WRITE_4(sc, CXM_REG_VPU, X CSR_READ_4(sc, CXM_REG_VPU) X & (sc->type == cxm_iTVC15_type X ? CXM_MASK_VPU_ENABLE15 X : CXM_MASK_VPU_ENABLE16)); X X /* Wait for 1 second */ X DELAY(1000000); X X /* Locate encoder mailbox */ X mailbox = CXM_MEM_ENC; X for (i = 0; i < CXM_MEM_ENC_SIZE; i += 0x100) X if (CSR_READ_4(sc, mailbox + i) == 0x12345678 X && CSR_READ_4(sc, mailbox + i + 4) == 0x34567812 X && CSR_READ_4(sc, mailbox + i + 8) == 0x56781234 X && CSR_READ_4(sc, mailbox + i + 12) == 0x78123456) X break; X X if (i >= CXM_MEM_ENC_SIZE) X return -1; X X sc->enc_mbx = mailbox + i + 16; X X /* Locate decoder mailbox */ X if (sc->type == cxm_iTVC15_type) { X mailbox = CXM_MEM_DEC; X for (i = 0; i < CXM_MEM_DEC_SIZE; i += 0x100) X if (CSR_READ_4(sc, mailbox + i) == 0x12345678 X && CSR_READ_4(sc, mailbox + i + 4) == 0x34567812 X && CSR_READ_4(sc, mailbox + i + 8) == 0x56781234 X && CSR_READ_4(sc, mailbox + i + 12) == 0x78123456) X break; X X if (i >= CXM_MEM_DEC_SIZE) X return -1; X X sc->dec_mbx = mailbox + i + 16; X } X X /* Get encoder firmware version */ X parameter = 0; X if (cxm_firmware_command_nosleep(sc, cxm_enc_mailbox, X CXM_FW_CMD_ENC_GET_FW_VER, X ¶meter, 1) < 0) X return -1; X X printf("%s: encoder firmware version %#x\n", X sc->name, (unsigned int)parameter); X X /* Get decoder firmware version */ X if (sc->type == cxm_iTVC15_type) { X parameter = 0; X if (cxm_firmware_command_nosleep(sc, cxm_dec_mailbox, X CXM_FW_CMD_DEC_GET_FW_VER, X ¶meter, 1) < 0) X return -1; X X printf("%s: decoder firmware version %#x\n", X sc->name, (unsigned int)parameter); X } X X return 0; X} X X Xstatic int Xcxm_configure_encoder( struct cxm_softc *sc ) X{ X int fps; X unsigned int i; X u_int32_t parameters[12]; X const struct cxm_codec_profile *cpp; X X fps = cxm_saa7115_detected_fps(sc); X X if (fps < 0) X return -1; X X if (sc->profile->fps != fps) { X X /* X * Pick a profile with the correct fps using the chosen X * width to decide between the VCD, SVCD, or DVD profiles. X */ X X for (i = 0; i < NUM_ELEMENTS(codec_profiles); i++) X if (codec_profiles[i]->fps == fps X && codec_profiles[i]->width == sc->profile->width) X break; X X if (i >= NUM_ELEMENTS(codec_profiles)) X return -1; X X sc->profile = codec_profiles[i]; X } X X cpp = sc->profile; X X if (cxm_saa7115_configure_scaler(sc, X cpp->width, cpp->source_height) < 0) X return -1; X X /* assign dma block len */ X parameters[0] = 1; /* Transfer block size = 1 */ X parameters[1] = 1; /* Units = 1 (frames) */ X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_DMA_BLOCKLEN, X parameters, 2) != 0) X return -1; X X X /* assign program index info */ X parameters[0] = 0; /* Picture mask = 0 (don't generate index) */ X parameters[1] = 0; /* Num_req = 0 */ X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_PGM_INDEX_INFO, X parameters, 2) != 0) X return -1; X X /* assign stream type */ X parameters[0] = cpp->stream_type; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_STREAM_TYPE, X parameters, 1) != 0) X return -1; X X /* assign output port */ X parameters[0] = 0; /* 0 (Memory) */ X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_OUTPUT_PORT, X parameters, 1) != 0) X return -1; X X /* assign framerate */ X parameters[0] = cpp->fps == 30 ? 0 : 1; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_FRAME_RATE, X parameters, 1) != 0) X return -1; X X /* assign frame size */ X parameters[0] = cpp->height; X parameters[1] = cpp->width; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_FRAME_SIZE, X parameters, 2) != 0) X return -1; X X /* assign aspect ratio */ X parameters[0] = cpp->aspect; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_ASPECT_RATIO, X parameters, 1) != 0) X return -1; X X /* assign bitrates */ X parameters[0] = cpp->bitrate.mode; X parameters[1] = cpp->bitrate.average; X parameters[2] = cpp->bitrate.peak / 400; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_BITRATES, X parameters, 3) != 0) X return -1; X X /* assign gop closure */ X parameters[0] = cpp->gop.closure; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_GOP_CLOSURE, X parameters, 1) != 0) X return -1; X X /* assign gop properties */ X parameters[0] = cpp->gop.frames; X parameters[1] = cpp->gop.bframes; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_GOP_PROPERTIES, X parameters, 2) != 0) X return -1; X X /* assign 3 2 pulldown */ X parameters[0] = cpp->pulldown; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_3_2_PULLDOWN, X parameters, 1) != 0) X return -1; X X /* assign dnr filter mode */ X parameters[0] = cpp->dnr.mode; X parameters[1] = cpp->dnr.type; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_DNR_FILTER_MODE, X parameters, 2) != 0) X return -1; X X /* assign dnr filter props */ X parameters[0] = cpp->dnr.spatial; X parameters[1] = cpp->dnr.temporal; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_DNR_FILTER_PROPERTIES, X parameters, 2) != 0) X return -1; X X /* assign audio properties */ X parameters[0] = cpp->audio; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_AUDIO_PROPERTIES, X parameters, 1) != 0) X return -1; X X /* assign coring levels */ X parameters[0] = 0; /* luma_h */ X parameters[1] = 255; /* luma_l */ X parameters[2] = 0; /* chroma_h */ X parameters[3] = 255; /* chroma_l */ X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_CORING_LEVELS, X parameters, 4) != 0) X return -1; X X /* assign spatial filter type */ X parameters[0] = 3; /* Luminance filter = 3 (2D H/V Separable) */ X parameters[1] = 1; /* Chrominance filter = 1 (1D Horizontal) */ X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_SPATIAL_FILTER_TYPE, X parameters, 2) != 0) X return -1; X X /* assign frame drop rate */ X parameters[0] = 0; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_FRAME_DROP_RATE, X parameters, 1) != 0) X return -1; X X /* assign placeholder */ X parameters[0] = 0; /* type = 0 (Extension / UserData) */ X parameters[1] = 0; /* period */ X parameters[2] = 0; /* size_t */ X parameters[3] = 0; /* arg0 */ X parameters[4] = 0; /* arg1 */ X parameters[5] = 0; /* arg2 */ X parameters[6] = 0; /* arg3 */ X parameters[7] = 0; /* arg4 */ X parameters[8] = 0; /* arg5 */ X parameters[9] = 0; /* arg6 */ X parameters[10] = 0; /* arg7 */ X parameters[11] = 0; /* arg8 */ X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_PLACEHOLDER, X parameters, 12) != 0) X return -1; X X /* assign VBI properties */ X parameters[0] = 0xbd04; /* mode = 0 (sliced), stream and user data */ X parameters[1] = 0; /* frames per interrupt (only valid in raw mode) */ X parameters[2] = 0; /* total raw VBI frames (only valid in raw mode) */ X parameters[3] = 0x25256262; /* ITU 656 start codes (saa7115 table 24)*/ X parameters[4] = 0x38387f7f; /* ITU 656 stop codes (saa7115 table 24) */ X parameters[5] = cpp->vbi.nlines; /* lines per frame */ X parameters[6] = 1440; /* bytes per line = 720 pixels */ X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_VBI_PROPERTIES, X parameters, 7) != 0) X return -1; X X /* assign VBI lines */ X parameters[0] = 0xffffffff; /* all lines */ X parameters[1] = 0; /* disable VBI features */ X parameters[2] = 0; X parameters[3] = 0; X parameters[4] = 0; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_VBI_LINE, X parameters, 5) != 0) X return -1; X X /* assign number of lines in fields 1 and 2 */ X parameters[0] = cpp->source_height / 2 + cpp->vbi.nlines; X parameters[1] = cpp->source_height / 2 + cpp->vbi.nlines; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ASSIGN_NUM_VSYNC_LINES, X parameters, 2) != 0) X return -1; X X return 0; X} X X Xstatic int Xcxm_start_encoder( struct cxm_softc *sc ) X{ X u_int32_t parameters[4]; X u_int32_t subtype; X u_int32_t type; X X if (sc->encoding) X return 0; X X if (cxm_configure_encoder(sc) < 0) X return -1; X X /* Clear pending encoder interrupts (which are currently masked) */ X cxm_set_irq_status(sc, CXM_IRQ_ENC); X X /* Enable event notification */ X parameters[0] = 0; /* Event = 0 (refresh encoder input) */ X parameters[1] = 1; /* Notification = 1 (enable) */ X parameters[2] = 0x10000000; /* Interrupt bit */ X parameters[3] = -1; /* Mailbox = -1 (no mailbox) */ X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ENC_EVENT_NOTIFICATION, X parameters, 4) != 0) X return -1; X X if (cxm_saa7115_mute(sc) < 0) X return -1; X if (cxm_msp_mute(sc) < 0) X return -1; X X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_INITIALIZE_VIDEO_INPUT, X NULL, 0) < 0) X return -1; X X if (cxm_saa7115_unmute(sc) < 0) X return -1; X if (cxm_msp_unmute(sc) < 0) X return -1; X X /* Wait for 100ms */ X (void)tsleep(&sc->encoding, PWAIT, "cxmce", hz / 10); X X type = sc->mpeg ? CXM_FW_CAPTURE_STREAM_TYPE_MPEG X : CXM_FW_CAPTURE_STREAM_TYPE_RAW; X subtype = (sc->mpeg ? CXM_FW_CAPTURE_STREAM_PCM_AUDIO : 0) X | (sc->source == cxm_fm_source X ? 0 : CXM_FW_CAPTURE_STREAM_YUV); X X /* Start the encoder */ X parameters[0] = type; X parameters[1] = subtype; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_BEGIN_CAPTURE, parameters, 2) != 0) X return -1; X X sc->enc_pool.offset = 0; X sc->enc_pool.read = 0; X sc->enc_pool.write = 0; X X sc->encoding_eos = 0; X X sc->encoding = 1; X X /* Enable interrupts */ X cxm_set_irq_mask(sc, sc->irq_mask & ~CXM_IRQ_ENC); X X return 0; X} X X Xstatic int Xcxm_stop_encoder( struct cxm_softc *sc ) X{ X u_int32_t parameters[4]; X u_int32_t subtype; X u_int32_t type; X intrmask_t s; X X if (! sc->encoding ) X return 0; X X type = sc->mpeg ? CXM_FW_CAPTURE_STREAM_TYPE_MPEG X : CXM_FW_CAPTURE_STREAM_TYPE_RAW; X subtype = (sc->mpeg ? CXM_FW_CAPTURE_STREAM_PCM_AUDIO : 0) X | (sc->source == cxm_fm_source X ? 0 : CXM_FW_CAPTURE_STREAM_YUV); X X /* Stop the encoder */ X parameters[0] = sc->mpeg ? 0 : 1; /* When = 0 (end of GOP) */ X parameters[1] = type; X parameters[2] = subtype; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_END_CAPTURE, parameters, 3) != 0) X return -1; X X /* Wait for up to 1 second */ X s = spltty(); X if (! sc->encoding_eos ) X (void)tsleep(&sc->encoding_eos, PWAIT, "cxmeos", hz); X splx(s); X X if (sc->mpeg && ! sc->encoding_eos ) X printf("%s: missing encoder EOS\n", sc->name); X X /* Disable event notification */ X parameters[0] = 0; /* Event = 0 (refresh encoder input) */ X parameters[1] = 0; /* Notification = 0 (disable) */ X parameters[2] = 0x10000000; /* Interrupt bit */ X parameters[3] = -1; /* Mailbox = -1 (no mailbox) */ X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_ENC_EVENT_NOTIFICATION, X parameters, 4) != 0) X return -1; X X /* Disable interrupts */ X cxm_set_irq_mask(sc, sc->irq_mask | CXM_IRQ_ENC); X X sc->encoding = 0; X X return 0; X} X X Xstatic int Xcxm_pause_encoder( struct cxm_softc *sc ) X{ X u_int32_t parameter; X X /* Pause the encoder */ X parameter = 0; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_PAUSE_ENCODER, ¶meter, 1) != 0) X return -1; X X return 0; X} X X Xstatic int Xcxm_unpause_encoder( struct cxm_softc *sc ) X{ X u_int32_t parameter; X X /* Unpause the encoder */ X parameter = 1; X if (cxm_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_PAUSE_ENCODER, ¶meter, 1) != 0) X return -1; X X return 0; X} X X Xstatic unsigned int Xcxm_encoder_fixup_byte_order( struct cxm_softc *sc, X unsigned int current, size_t offset) X{ X unsigned int strips; X unsigned int i; X unsigned int j; X unsigned int k; X unsigned int macroblocks_per_line; X unsigned int scratch; X unsigned int words_per_line; X u_int32_t *ptr; X u_int32_t *src; X size_t nbytes; X X switch (sc->enc_pool.bufs[current].byte_order) { X case cxm_device_mpeg_byte_order: X X /* X * Convert each 32 bit word to the proper byte ordering. X */ X X for (nbytes = 0, X ptr = (u_int32_t *)sc->enc_pool.bufs[current].vaddr; X nbytes != sc->enc_pool.bufs[current].size; X nbytes += sizeof(*ptr), ptr++) X *ptr = bswap32(*ptr); X X break; X X case cxm_device_yuv12_byte_order: X X /* X * Convert each macro block to planar using X * a scratch buffer (the buffer prior to the X * current buffer is always free since it marks X * the end of the ring buffer). X */ X X scratch = (current + (CXM_SG_BUFFERS - 1)) % CXM_SG_BUFFERS; X X if (offset) { X current = scratch; X break; X } X X src = (u_int32_t *)sc->enc_pool.bufs[current].vaddr; X words_per_line = sc->profile->width / sizeof(*ptr); X macroblocks_per_line X = sc->profile->width / CXM_MACROBLOCK_WIDTH; X strips = sc->enc_pool.bufs[current].size X / (macroblocks_per_line * CXM_MACROBLOCK_SIZE); X X for (i = 0; i < strips; i++) { X ptr = (u_int32_t *)sc->enc_pool.bufs[scratch].vaddr X + i * macroblocks_per_line * CXM_MACROBLOCK_SIZE X / sizeof(*ptr); X for (j = 0; j < macroblocks_per_line; j++) { X for (k = 0; k < CXM_MACROBLOCK_HEIGHT; k++) { X#if CXM_MACROBLOCK_WIDTH != 16 X# error CXM_MACROBLOCK_WIDTH != 16 X#endif X *(ptr + k * words_per_line) X = *src++; X *(ptr + k * words_per_line + 1) X = *src++; X *(ptr + k * words_per_line + 2) X = *src++; X *(ptr + k * words_per_line + 3) X = *src++; X } X ptr += CXM_MACROBLOCK_WIDTH / sizeof(*ptr); X } X } X X sc->enc_pool.bufs[scratch].size X = sc->enc_pool.bufs[current].size; X X current = scratch; X break; X X default: X break; X } X X sc->enc_pool.bufs[current].byte_order = cxm_host_byte_order; X X return current; X} X X Xstatic void Xcxm_encoder_dma_discard( struct cxm_softc *sc ) X{ X u_int32_t parameters[3]; X X /* Discard the DMA request */ X parameters[0] = 0; X parameters[1] = 0; X parameters[2] = 0; X if (cxm_queue_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_SCHED_DMA_TO_HOST, X parameters, 3) == -1) { X printf("%s: failed to discard encoder dma request\n", X sc->name); X return; X } X X sc->encoding_dma = -1; X} X X Xstatic void Xcxm_encoder_dma_done( struct cxm_softc *sc ) X{ X int buffers_pending; X u_int32_t status; X intrmask_t s; X X if (! sc->encoding_dma) { X printf("%s: encoder dma not already in progress\n", X sc->name); X return; X } X X buffers_pending = sc->encoding_dma; X sc->encoding_dma = 0; X X if (buffers_pending < 0) X return; X X status = CSR_READ_4(sc, CXM_REG_DMA_STATUS) & 0x0000000f; X X if ((status X & (CXM_DMA_ERROR_LIST | CXM_DMA_ERROR_WRITE | CXM_DMA_SUCCESS)) X != CXM_DMA_SUCCESS) { X printf("%s: encoder dma status %#x\n", X sc->name, (unsigned int)status); X return; X } X X /* Update the books (spl is used since mutex is not available) */ X s = spltty(); X sc->enc_pool.write = (sc->enc_pool.write + buffers_pending) X % CXM_SG_BUFFERS; X splx(s); X X /* signal anyone requesting notification */ X if (sc->enc_proc) X psignal (sc->enc_proc, sc->enc_signal); X X /* wakeup anyone waiting for data */ X wakeup(&sc->enc_pool.read); X X /* wakeup anyone polling for data */ X selwakeup(&sc->enc_sel); X} X X Xstatic void Xcxm_encoder_dma_request( struct cxm_softc *sc ) X{ X enum cxm_byte_order byte_order; X int buffers_free; X int buffers_pending; X unsigned int current; X unsigned int i; X unsigned int mailbox; X unsigned int macroblocks_per_line; X unsigned int nrequests; X unsigned int strips; X u_int32_t parameters[CXM_MBX_MAX_PARAMETERS]; X u_int32_t type; X size_t max_sg_segment; X struct { X size_t offset; X size_t size; X } requests[2]; X intrmask_t s; X X if (sc->encoding_dma) { X printf("%s: encoder dma already in progress\n", X sc->name); X cxm_encoder_dma_discard(sc); X return; X } X X mailbox = sc->enc_mbx X + CXM_MBX_FW_DMA_MAILBOX * sizeof(struct cxm_mailbox); X X for (i = 0; i < CXM_MBX_MAX_PARAMETERS; i++) X parameters[i] X = CSR_READ_4(sc, X mailbox X + offsetof(struct cxm_mailbox, parameters) X + i * sizeof(u_int32_t)); X X byte_order = cxm_device_mpeg_byte_order; X max_sg_segment = CXM_SG_SEGMENT; X nrequests = 0; X type = parameters[0]; X X switch (type) { X case 0: /* MPEG */ X requests[nrequests].offset = parameters[1]; X requests[nrequests++].size = parameters[2]; X break; X X case 1: /* YUV */ X byte_order = cxm_device_yuv12_byte_order; X X /* X * Simplify macroblock unpacking by ensuring X * that strips don't span buffers. X */ X X#if CXM_MACROBLOCK_SIZE % 256 X# error CXM_MACROBLOCK_SIZE not a multiple of 256 X#endif X X macroblocks_per_line = sc->profile->width X / CXM_MACROBLOCK_WIDTH; X strips = CXM_SG_SEGMENT X / (macroblocks_per_line * CXM_MACROBLOCK_SIZE); X max_sg_segment = strips X * macroblocks_per_line * CXM_MACROBLOCK_SIZE; X X requests[nrequests].offset = parameters[1]; /* Y */ X requests[nrequests++].size = parameters[2]; X requests[nrequests].offset = parameters[3]; /* UV */ X requests[nrequests++].size = parameters[4]; X break; X X case 2: /* PCM (audio) */ X case 3: /* VBI */ X default: X printf("%s: encoder dma type %#x unsupported\n", X sc->name, (unsigned int)type); X cxm_encoder_dma_discard(sc); X return; X } X X /* X * Determine the number of buffers free at this * instant * X * taking into consideration that the ring buffer wraps. X */ X s = spltty(); X buffers_free = sc->enc_pool.read - sc->enc_pool.write; X if (buffers_free <= 0) X buffers_free += CXM_SG_BUFFERS; X splx(s); X X /* X * Build the scatter / gather list taking in X * consideration that the ring buffer wraps, X * at least one free buffer must always be X * present to mark the end of the ring buffer, X * and each transfer must be a multiple of 256. X */ X X buffers_pending = 0; X current = sc->enc_pool.write; X X for (i = 0; i < nrequests; i++) { X if (! requests[i].size ) { X printf("%s: encoder dma size is zero\n", sc->name); X cxm_encoder_dma_discard(sc); X return; X } X X while (requests[i].size) { X sc->enc_pool.bufs[current].size X = requests[i].size > max_sg_segment X ? max_sg_segment : requests[i].size; X sc->enc_pool.bufs[current].byte_order = byte_order; X X sc->enc_sg.vaddr[buffers_pending].src X = requests[i].offset; X sc->enc_sg.vaddr[buffers_pending].dst X = sc->enc_pool.bufs[current].baddr; X sc->enc_sg.vaddr[buffers_pending].size X = (sc->enc_pool.bufs[current].size + 0x000000ff) X & 0xffffff00; X X requests[i].offset += sc->enc_pool.bufs[current].size; X requests[i].size -= sc->enc_pool.bufs[current].size; X buffers_pending++; X current = (current + 1) % CXM_SG_BUFFERS; X X if (buffers_pending >= buffers_free) { X printf( X "%s: encoder dma not enough buffer space free\n", X sc->name); X cxm_encoder_dma_discard(sc); X return; X } X } X } X X /* Mark the last transfer in the list */ X sc->enc_sg.vaddr[buffers_pending - 1].size |= 0x80000000; X X /* Schedule the DMA */ X parameters[0] = sc->enc_sg.baddr; X parameters[1] = buffers_pending * sizeof(sc->enc_sg.vaddr[0]); X parameters[2] = type; X if (cxm_queue_firmware_command(sc, cxm_enc_mailbox, X CXM_FW_CMD_SCHED_DMA_TO_HOST, X parameters, 3) == -1) { X printf("%s: failed to schedule encoder dma request\n", X sc->name); X return; X } X X /* X * Record the number of pending buffers for the X * benefit of cxm_encoder_dma_done. Doing this X * after queuing the command doesn't introduce X * a race condition since we're already in the X * interrupt handler. X */ X X sc->encoding_dma = buffers_pending; X} X X Xstatic int Xcxm_encoder_wait_for_lock( struct cxm_softc *sc ) X{ X int muted; X int locked; X int result; X X locked = 1; X X /* X * Wait for the tuner to lock. X */ X if (sc->source == cxm_fm_source || sc->source == cxm_tuner_source) { X result = cxm_tuner_wait_for_lock(sc); X if (result <= 0) X return result; X } X X /* X * Wait for the video decoder to lock. X */ X if (sc->source != cxm_fm_source) { X result = cxm_saa7115_wait_for_lock(sc); X if (result < 0) X return result; X else if (result == 0) X locked = 0; X } X X /* X * Wait for the audio decoder to lock. X */ X if (sc->source == cxm_tuner_source) { X muted = cxm_msp_is_muted(sc); X X if (cxm_msp_autodetect_standard(sc) < 0) X return -1; X X result = cxm_msp_wait_for_lock(sc); X if (result < 0) X return result; X else if (result == 0) X locked = 0; X X if (muted == 0 && cxm_msp_unmute(sc) < 0) X return -1; X } X X return locked; X} X X Xstatic void Xcxm_mapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error) X{ X bus_addr_t *busaddrp; X X /* X * Only the first bus space address is needed X * since it's known that the memory is physically X * contiguous due to bus_dmamem_alloc. X */ X X busaddrp = (bus_addr_t *)arg; X *busaddrp = segs->ds_addr; X} X X X/* X * the boot time probe routine. X */ Xstatic int Xcxm_probe( device_t dev ) X{ X struct cxm_dev *t; X X t = cxm_devs; X X while(t->name != NULL) { X if ((pci_get_vendor(dev) == t->vid) && X (pci_get_device(dev) == t->did)) { X device_set_desc(dev, t->name); X return 0; X } X t++; X } X X return ENXIO; X} X X X/* X * the attach routine. X */ Xstatic int Xcxm_attach( device_t dev ) X{ X int error; X int rid; X int unit; X unsigned int i; X u_int32_t command; X struct cxm_softc *sc; X X /* Get the device data */ X sc = device_get_softc(dev); X unit = device_get_unit(dev); X X sc->type = cxm_iTVC15_type; X switch(pci_get_device(dev)) { X case CXM_DEVICEID_CONEXANT_iTVC16: X sc->type = cxm_iTVC16_type; X break; X X default: X break; X } X X /* build the device name */ X snprintf(sc->name, sizeof(sc->name), "cxm%d",unit); X X /* X * Enable bus mastering and memory mapped I/O. X */ X pci_enable_busmaster(dev); X pci_enable_io(dev, SYS_RES_MEMORY); X command = pci_read_config(dev, PCIR_COMMAND, 4); X X if (! (command & PCIM_CMD_MEMEN) ) { X device_printf(dev, "failed to enable memory mappings\n"); X error = ENXIO; X goto fail; X } X X /* X * Map control/status registers. X */ X rid = CXM_RID; X sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, X 0, ~0, 1, RF_ACTIVE); X X if (! sc->mem_res ) { X device_printf(dev, "could not map memory\n"); X error = ENXIO; X goto fail; X } X X sc->btag = rman_get_bustag(sc->mem_res); X sc->bhandle = rman_get_bushandle(sc->mem_res); X X /* X * Attach the I2C bus. X */ X sc->cxm_iic = device_add_child(dev, "cxm_iic", unit); X X if (! sc->cxm_iic ) { X device_printf(dev, "could not add cxm_iic\n"); X error = ENXIO; X goto fail; X } X X error = device_probe_and_attach(sc->cxm_iic); X X if (error) { X device_printf(dev, "could not attach cxm_iic\n"); X goto fail; X } X X /* X * Initialize the tuner. X */ X if (cxm_tuner_init(sc) < 0) { X device_printf(dev, "could not initialize tuner\n"); X error = ENXIO; X goto fail; X } X X /* X * Initialize the SAA7115. X */ X if (cxm_saa7115_init(sc) < 0) { X device_printf(dev, "could not initialize video decoder\n"); X error = ENXIO; X goto fail; X } X X /* X * Initialize the MSP3400. X */ X if (cxm_msp_init(sc) < 0) { X device_printf(dev, "could not initialize audio decoder\n"); X error = ENXIO; X goto fail; X } X X /* X * Initialize the IR Remote. X */ X if (cxm_ir_init(sc) < 0) { X device_printf(dev, "could not initialize IR remote\n"); X error = ENXIO; X goto fail; X } X X sc->dec_mbx = -1; X sc->enc_mbx = -1; X X /* X * Disable the Conexant device. X * X * This is done * after * attaching the I2C bus so X * cxm_stop_hardware can mute the video and audio X * decoders. X */ X cxm_stop_hardware(sc); X X /* X * Allocate our interrupt. X */ X rid = 0; X sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, X 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); X X if (sc->irq_res == NULL) { X device_printf(dev, "could not map interrupt\n"); X error = ENXIO; X goto fail; X } X X error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_TTY, X cxm_intr, sc, &sc->ih_cookie); X if (error) { X device_printf(dev, "could not setup irq\n"); X goto fail; X X } X X /* X * Allocate a DMA tag for the parent bus. X */ X error = bus_dma_tag_create(NULL, 1, 0, X BUS_SPACE_MAXADDR_32BIT, X BUS_SPACE_MAXADDR, NULL, NULL, X BUS_SPACE_MAXSIZE_32BIT, 1, X BUS_SPACE_MAXSIZE_32BIT, 0, X#if __FreeBSD_version >= 501102 X busdma_lock_mutex, &Giant, X#endif X &sc->parent_dmat); X if (error) { X device_printf(dev, "could not create parent bus DMA tag\n"); X goto fail; X } X X /* X * Allocate a DMA tag for the encoder buffers. X */ X error = bus_dma_tag_create(sc->parent_dmat, 256, 0, X BUS_SPACE_MAXADDR_32BIT, X BUS_SPACE_MAXADDR, NULL, NULL, X CXM_SG_SEGMENT, 1, X BUS_SPACE_MAXSIZE_32BIT, 0, X#if __FreeBSD_version >= 501102 X busdma_lock_mutex, &Giant, X#endif X &sc->enc_pool.dmat); X if (error) { X device_printf(dev, X "could not create encoder buffer DMA tag\n"); X goto fail; X } X X for (i = 0; i < CXM_SG_BUFFERS; i++) { X X /* X * Allocate the encoder buffer. X */ X error = bus_dmamem_alloc(sc->enc_pool.dmat, X (void **)&sc->enc_pool.bufs[i].vaddr, X BUS_DMA_NOWAIT, X &sc->enc_pool.bufs[i].dmamap); X if (error) { X device_printf(dev, X "could not allocate encoder buffer\n"); X goto fail; X } X X /* X * Map the encoder buffer. X */ X error = bus_dmamap_load(sc->enc_pool.dmat, X sc->enc_pool.bufs[i].dmamap, X sc->enc_pool.bufs[i].vaddr, X CXM_SG_SEGMENT, X cxm_mapmem, X &sc->enc_pool.bufs[i].baddr, 0); X if (error) { X device_printf(dev, "could not map encoder buffer\n"); X goto fail; X } X } X X /* X * Allocate a DMA tag for the scatter / gather list. X */ X error = bus_dma_tag_create(sc->parent_dmat, 1, 0, X BUS_SPACE_MAXADDR_32BIT, X BUS_SPACE_MAXADDR, NULL, NULL, X CXM_SG_BUFFERS X * sizeof(struct cxm_sg_entry), 1, X BUS_SPACE_MAXSIZE_32BIT, 0, X#if __FreeBSD_version >= 501102 X busdma_lock_mutex, &Giant, X#endif X &sc->enc_sg.dmat); X if (error) { X device_printf(dev, X "could not create scatter / gather DMA tag\n"); X goto fail; X } X X /* X * Allocate the scatter / gather list. X */ X error = bus_dmamem_alloc(sc->enc_sg.dmat, (void **)&sc->enc_sg.vaddr, X BUS_DMA_NOWAIT, &sc->enc_sg.dmamap); X if (error) { X device_printf(dev, X "could not allocate scatter / gather list\n"); X goto fail; X } X X /* X * Map the scatter / gather list. X */ X error = bus_dmamap_load(sc->enc_sg.dmat, sc->enc_sg.dmamap, X sc->enc_sg.vaddr, X CXM_SG_BUFFERS * sizeof(struct cxm_sg_entry), X cxm_mapmem, &sc->enc_sg.baddr, 0); X if (error) { X device_printf(dev, "could not map scatter / gather list\n"); X goto fail; X } X X /* X * Initialize the hardware. X */ X if (cxm_init_hardware(sc) < 0) { X device_printf(dev, "could not initialize hardware\n"); X error = ENXIO; X goto fail; X } X X sc->profile = &dvd_ntsc_profile; X X sc->source = cxm_tuner_source; X X /* make the device entries */ X sc->cxm_dev = make_dev(&cxm_cdevsw, unit, X 0, 0, 0444, "cxm%d", unit); X X return 0; X Xfail: X if (sc->enc_sg.baddr) X bus_dmamap_unload(sc->enc_sg.dmat, sc->enc_sg.dmamap); X if (sc->enc_sg.vaddr) X bus_dmamem_free(sc->enc_sg.dmat, sc->enc_sg.vaddr, X sc->enc_sg.dmamap); X if (sc->enc_sg.dmat) X bus_dma_tag_destroy(sc->enc_sg.dmat); X X for (i = 0; i < CXM_SG_BUFFERS; i++) { X if (sc->enc_pool.bufs[i].baddr) X bus_dmamap_unload(sc->enc_pool.dmat, X sc->enc_pool.bufs[i].dmamap); X if (sc->enc_pool.bufs[i].vaddr) X bus_dmamem_free(sc->enc_pool.dmat, X sc->enc_pool.bufs[i].vaddr, X sc->enc_pool.bufs[i].dmamap); X } X X if (sc->enc_pool.dmat) X bus_dma_tag_destroy(sc->enc_pool.dmat); X X if (sc->parent_dmat) X bus_dma_tag_destroy(sc->parent_dmat); X X /* X * Detach the I2C bus. X * X * This is done * after * deallocating the scatter / gather X * list and buffers so the kernel has a better chance of X * gracefully handling a memory shortage. X * X * Detach the children before recursively deleting X * in case a child has a pointer to a grandchild X * which is used by the child's detach routine. X */ X bus_generic_detach(dev); X if (sc->cxm_iic) X device_delete_child(dev, sc->cxm_iic); X X if (sc->ih_cookie) X bus_teardown_intr(dev, sc->irq_res, sc->ih_cookie); X if (sc->irq_res) X bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); X if (sc->mem_res) X bus_release_resource(dev, SYS_RES_MEMORY, CXM_RID, sc->mem_res); X X return error; X} X X/* X * the detach routine. X */ Xstatic int Xcxm_detach( device_t dev ) X{ X unsigned int i; X struct cxm_softc *sc; X device_t child; X X /* Get the device data */ X sc = device_get_softc(dev); X X /* Disable the Conexant device. */ X cxm_stop_hardware(sc); X X /* Unregister the /dev/cxmN device. */ X destroy_dev(sc->cxm_dev); X X /* X * Deallocate scatter / gather list and buffers. X */ X bus_dmamap_unload(sc->enc_sg.dmat, sc->enc_sg.dmamap); X bus_dmamem_free(sc->enc_sg.dmat, sc->enc_sg.vaddr, sc->enc_sg.dmamap); X X bus_dma_tag_destroy(sc->enc_sg.dmat); X X for (i = 0; i < CXM_SG_BUFFERS; i++) { X bus_dmamap_unload(sc->enc_pool.dmat, X sc->enc_pool.bufs[i].dmamap); X bus_dmamem_free(sc->enc_pool.dmat, sc->enc_pool.bufs[i].vaddr, X sc->enc_pool.bufs[i].dmamap); X } X X bus_dma_tag_destroy(sc->enc_pool.dmat); X X bus_dma_tag_destroy(sc->parent_dmat); X X /* X * Detach the I2C bus. X * X * This is done * after * deallocating the scatter / gather X * list and buffers so the kernel has a better chance of X * gracefully handling a memory shortage. X * X * Detach the children before recursively deleting X * in case a child has a pointer to a grandchild X * which is used by the child's detach routine. X * X * Remember the child before detaching so we can X * delete it (bus_generic_detach indirectly zeroes X * sc->child_dev). X */ X child = sc->cxm_iic; X bus_generic_detach(dev); X if (child) X device_delete_child(dev, child); X X /* Deallocate resources. */ X bus_teardown_intr(dev, sc->irq_res, sc->ih_cookie); X bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); X bus_release_resource(dev, SYS_RES_MEMORY, CXM_RID, sc->mem_res); X X return 0; X} X X/* X * the shutdown routine. X */ Xstatic int Xcxm_shutdown( device_t dev ) X{ X struct cxm_softc *sc = device_get_softc(dev); X X /* Disable the Conexant device. */ X cxm_stop_hardware(sc); X X return 0; X} X X/* X * the interrupt routine. X */ Xstatic void Xcxm_intr( void *arg ) X{ X u_int32_t status; X struct cxm_softc *sc; X X /* Get the device data */ X sc = (struct cxm_softc *)arg; X X status = CSR_READ_4(sc, CXM_REG_IRQ_STATUS); X X status &= ~sc->irq_mask; X X if (! status ) X return; X X /* Process DMA done before handling a new DMA request or EOS */ X if (status & CXM_IRQ_ENC_DMA_DONE) X cxm_encoder_dma_done(sc); X X if (status & CXM_IRQ_ENC_DMA_REQUEST) X cxm_encoder_dma_request(sc); X X if (status & CXM_IRQ_ENC_EOS) { X sc->encoding_eos = 1; X wakeup(&sc->encoding_eos); X } X X cxm_set_irq_status(sc, status); X} X X X/* X * the child detached routine. X */ Xstatic void Xcxm_child_detached( device_t dev, device_t child ) X{ X struct cxm_softc *sc; X X /* Get the device data */ X sc = device_get_softc(dev); X X if (child == sc->cxm_iic) X sc->cxm_iic = NULL; X} X X Xstatic int Xcxm_read_ivar( device_t dev, device_t child, int index, uintptr_t* val) X{ X struct cxm_softc *sc; X X /* Get the device data */ X sc = device_get_softc(dev); X X switch (index) { X case CXM_IVAR_BHANDLE: X *val = sc->bhandle; X break; X X case CXM_IVAR_BTAG: X *val = sc->btag; X break; X X case CXM_IVAR_IICBUS: X *val = (uintptr_t)sc->iicbus; X break; X X default: X return ENOENT; X } X X return 0; X} X X Xstatic int Xcxm_write_ivar( device_t dev, device_t child, int index, uintptr_t val) X{ X struct cxm_softc *sc; X X /* Get the device data */ X sc = device_get_softc(dev); X X switch (index) { X case CXM_IVAR_BHANDLE: X return EINVAL; X X case CXM_IVAR_BTAG: X return EINVAL; X X case CXM_IVAR_IICBUS: X if (sc->iicbus) X return EINVAL; X sc->iicbus = (device_t)val; X break; X X default: X return ENOENT; X } X X return 0; X} X X X/*--------------------------------------------------------- X** X** Conexant iTVC15 / iTVC16 character device driver routines X** X**--------------------------------------------------------- X*/ X X#define UNIT(x) ((x) & 0x0f) X#define FUNCTION(x) (x >> 4) X X/* X * X */ Xint Xcxm_open( dev_t dev, int flags, int fmt, d_thread_t *td ) X{ X int unit; X struct cxm_softc *sc; X X unit = UNIT( minor(dev) ); X X /* Get the device data */ X sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit); X if (sc == NULL) { X /* the device is no longer valid/functioning */ X return ENXIO; X } X X if (sc->is_opened) X return EBUSY; X X sc->is_opened = 1; X sc->mpeg = 1; X X /* Record that the device is now busy */ X device_busy(devclass_get_device(cxm_devclass, unit)); X X return 0; X} X X X/* X * X */ Xint Xcxm_close( dev_t dev, int flags, int fmt, d_thread_t *td ) X{ X int unit; X struct cxm_softc *sc; X X unit = UNIT( minor(dev) ); X X /* Get the device data */ X sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit); X if (sc == NULL) { X /* the device is no longer valid/functioning */ X return ENXIO; X } X X if (cxm_stop_encoder(sc) < 0) X return ENXIO; X X sc->enc_pool.offset = 0; X sc->enc_pool.read = 0; X sc->enc_pool.write = 0; X X sc->enc_proc = NULL; X sc->enc_signal = 0; X X device_unbusy(devclass_get_device(cxm_devclass, unit)); X X sc->is_opened = 0; X X return 0; X} X X X/* X * X */ Xint Xcxm_read( dev_t dev, struct uio *uio, int flag ) X{ X int buffers_available; X int buffers_read; X int error; X int unit; X unsigned int current; X unsigned int i; X size_t nbytes; X size_t offset; X struct cxm_softc *sc; X intrmask_t s; X X unit = UNIT( minor(dev) ); X X /* Get the device data */ X sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit); X if (sc == NULL) { X /* the device is no longer valid/functioning */ X return ENXIO; X } X X /* Only trigger the encoder if the ring buffer is empty */ X if (! sc->encoding && sc->enc_pool.read == sc->enc_pool.write) { X if (cxm_start_encoder(sc) < 0) X return ENXIO; X if (flag & IO_NDELAY) X return EWOULDBLOCK; X } X X buffers_available = 0; X X s = spltty(); X while (sc->enc_pool.read == sc->enc_pool.write) { X error = tsleep(&sc->enc_pool.read, PZERO | PCATCH, "cmxrd", 0); X if (error) { X splx(s); X return error; X } X } X X /* X * Determine the number of buffers available at this * instant * X * taking in consideration that the ring buffer wraps. X */ X buffers_available = sc->enc_pool.write - sc->enc_pool.read; X if (buffers_available < 0) X buffers_available += CXM_SG_BUFFERS; X splx(s); X X offset = sc->enc_pool.offset; X X for (buffers_read = 0, i = sc->enc_pool.read; X buffers_read != buffers_available && uio->uio_resid; X buffers_read++, i = (i + 1) % CXM_SG_BUFFERS) { X X current = cxm_encoder_fixup_byte_order (sc, i, offset); X X nbytes = sc->enc_pool.bufs[current].size - offset; X X /* Don't transfer more than requested */ X if (nbytes > uio->uio_resid) X nbytes = uio->uio_resid; X X error = uiomove(sc->enc_pool.bufs[current].vaddr + offset, X nbytes, uio); X if (error) X return error; X X offset += nbytes; X X /* Handle a partial read of a buffer */ X if (! uio->uio_resid && offset != sc->enc_pool.bufs[i].size) X break; X X offset = 0; X } X X sc->enc_pool.offset = offset; X X /* Update the books (spl is used since mutex is not available) */ X s = spltty(); X sc->enc_pool.read = (sc->enc_pool.read + buffers_read) X % CXM_SG_BUFFERS; X splx(s); X X return 0; X} X X X/* X * X */ Xint Xcxm_ioctl( dev_t dev, unsigned long cmd, caddr_t arg, X int flag, d_thread_t *td ) X{ X int brightness; X int chroma_saturation; X int contrast; X int fps; X int hue; X int result; X int status; X int unit; X unsigned int i; X unsigned int sig; X unsigned long freq; X struct cxm_softc *sc; X enum cxm_source source; X struct bktr_capture_area *cap; X struct bktr_remote *remote; X intrmask_t s; X X unit = UNIT( minor(dev) ); X X /* Get the device data */ X sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit); X if (sc == NULL) { X /* the device is no longer valid/functioning */ X return ENXIO; X } X X switch (cmd) { X case BT848_GAUDIO: X switch (cxm_msp_selected_source(sc)) { X case cxm_tuner_source: X *(int *) arg = AUDIO_TUNER; X break; X X case cxm_line_in_source_composite: X case cxm_line_in_source_svideo: X *(int *) arg = AUDIO_EXTERN; X break; X X case cxm_fm_source: X *(int *) arg = AUDIO_INTERN; X break; X X default: X return ENXIO; X } X X if (cxm_msp_is_muted(sc) == 1) X *(int *) arg |= AUDIO_MUTE; X break; X X case BT848_SAUDIO: X source = cxm_unknown_source; X X switch (*(int *) arg) { X case AUDIO_TUNER: X source = cxm_tuner_source; X break; X X case AUDIO_EXTERN: X source = cxm_line_in_source_composite; X break; X X case AUDIO_INTERN: X source = cxm_fm_source; X break; X X case AUDIO_MUTE: X if (cxm_msp_mute(sc) < 0) X return ENXIO; X return 0; X X case AUDIO_UNMUTE: X if (cxm_msp_unmute(sc) < 0) X return ENXIO; X return 0; X X default: X return EINVAL; X } X X if (sc->encoding) { X X /* X * Switching between audio + video and audio only X * subtypes isn't supported while encoding. X */ X X if (source != sc->source X && (source == cxm_fm_source X || sc->source == cxm_fm_source)) X return EBUSY; X } X X if (cxm_pause_encoder(sc) < 0) X return ENXIO; X X if (cxm_msp_select_source(sc, source) < 0) X return ENXIO; X X if (source == cxm_fm_source) X sc->source = source; X X result = cxm_encoder_wait_for_lock(sc); X if (result < 0) X return ENXIO; X else if (result == 0) X return EINVAL; X X if (cxm_unpause_encoder(sc) < 0) X return ENXIO; X break; X X case BT848_GBRIG: X brightness = cxm_saa7115_get_brightness(sc); X X if (brightness < 0) X return ENXIO; X X /* X * Brooktree brightness: X * 0x80 = -50.0%, 0x00 = +0.0%, 0x7f = +49.6% X */ X *(int *)arg = (int)(unsigned char)brightness - 128; X break; X X case BT848_SBRIG: X X /* X * Brooktree brightness: X * 0x80 = -50.0%, 0x00 = +0.0%, 0x7f = +49.6% X */ X brightness = *(int *)arg + 128; X X if (cxm_saa7115_set_brightness(sc, brightness) < 0) X return ENXIO; X break; X X case METEORGBRIG: X brightness = cxm_saa7115_get_brightness(sc); X X if (brightness < 0) X return ENXIO; X X *(unsigned char *)arg = (unsigned char)brightness; X break; X X case METEORSBRIG: X brightness = *(unsigned char *)arg; X X if (cxm_saa7115_set_brightness(sc, brightness) < 0) X return ENXIO; X break; X X case BT848_GCSAT: X chroma_saturation = cxm_saa7115_get_chroma_saturation(sc); X X if (chroma_saturation < 0) X return ENXIO; X X /* X * Brooktree chroma saturation: X * 0x000 = 0%, 0x0fe = 100%, 0x1ff = 201.18% X */ X *(int *)arg = ((signed char)chroma_saturation > 0) X ? (chroma_saturation * 4 - 2) : 0; X break; X X case BT848_SCSAT: X X /* X * Brooktree chroma saturation: X * 0x000 = 0%, 0x0fe = 100%, 0x1ff = 201.18% X */ X chroma_saturation = (*(int *)arg & 0x1ff) < 510 X ? ((*(int *)arg & 0x1ff) + 2) / 4 : 127; X X if (cxm_saa7115_set_chroma_saturation(sc, chroma_saturation) X < 0) X return ENXIO; X X break; X X case METEORGCSAT: X chroma_saturation = cxm_saa7115_get_chroma_saturation(sc); X X if (chroma_saturation < 0) X return ENXIO; X X *(unsigned char *)arg = (unsigned char)chroma_saturation; X break; X X case METEORSCSAT: X chroma_saturation = *(unsigned char *)arg; X X if (cxm_saa7115_set_chroma_saturation(sc, chroma_saturation) X < 0) X return ENXIO; X break; X X case METEORGCONT: X contrast = cxm_saa7115_get_contrast(sc); X X if (contrast < 0) X return ENXIO; X X *(unsigned char *)arg = (unsigned char)contrast; X break; X X case METEORSCONT: X contrast = *(unsigned char *)arg; X X if (cxm_saa7115_set_contrast(sc, contrast) < 0) X return ENXIO; X break; X X case BT848_GHUE: X hue = cxm_saa7115_get_hue(sc); X X if (hue < 0) X return ENXIO; X X *(int *)arg = (signed char)hue; X break; X X case BT848_SHUE: X hue = *(int *)arg; X X if (cxm_saa7115_set_hue(sc, hue) < 0) X return ENXIO; X break; X X case METEORGHUE: X hue = cxm_saa7115_get_hue(sc); X X if (hue < 0) X return ENXIO; X X *(signed char *)arg = (signed char)hue; X break; X X case METEORSHUE: X hue = *(signed char *)arg; X X if (cxm_saa7115_set_hue(sc, hue) < 0) X return ENXIO; X break; X X case METEORCAPTUR: X switch (*(int *) arg) { X case METEOR_CAP_CONTINOUS: X if (cxm_start_encoder(sc) < 0) X return ENXIO; X break; X X case METEOR_CAP_STOP_CONT: X if (cxm_stop_encoder(sc) < 0) X return ENXIO; X break; X X default: X return EINVAL; X } X break; X X case BT848_GCAPAREA: X cap = (struct bktr_capture_area *)arg; X memset (cap, 0, sizeof (*cap)); X cap->x_offset = 0; X cap->y_offset = 0; X cap->x_size = sc->profile->width; X cap->y_size = sc->profile->height; X break; X X case BT848_SCAPAREA: X if (sc->encoding) X return EBUSY; X X cap = (struct bktr_capture_area *)arg; X if (cap->x_offset || cap->y_offset X || (cap->x_size % CXM_MACROBLOCK_WIDTH) X || (cap->y_size % CXM_MACROBLOCK_HEIGHT)) X return EINVAL; X X /* X * Setting the width and height has the side effect of X * chosing between the VCD, SVCD, and DVD profiles. X */ X X for (i = 0; i < NUM_ELEMENTS(codec_profiles); i++) X if (codec_profiles[i]->width == cap->x_size X && codec_profiles[i]->height == cap->y_size) X break; X X if (i >= NUM_ELEMENTS(codec_profiles)) X return EINVAL; X X sc->profile = codec_profiles[i]; X break; X X case BT848GFMT: X switch (cxm_saa7115_detected_format(sc)) { X case cxm_ntsc_60hz_source_format: X *(unsigned long *)arg = BT848_IFORM_F_NTSCM; X break; X X case cxm_pal_50hz_source_format: X *(unsigned long *)arg = BT848_IFORM_F_PALBDGHI; X break; X X case cxm_secam_50hz_source_format: X *(unsigned long *)arg = BT848_IFORM_F_SECAM; X break; X X case cxm_pal_60hz_source_format: X *(unsigned long *)arg = BT848_IFORM_F_PALM; X break; X X case cxm_bw_50hz_source_format: X case cxm_bw_60hz_source_format: X case cxm_ntsc_50hz_source_format: X *(unsigned long *)arg = BT848_IFORM_F_AUTO; X break; X X default: X return ENXIO; X } X break; X X case METEORGFMT: X switch (cxm_saa7115_detected_format(sc)) { X case cxm_ntsc_60hz_source_format: X *(unsigned long *)arg = METEOR_FMT_NTSC; X break; X X case cxm_pal_50hz_source_format: X *(unsigned long *)arg = METEOR_FMT_PAL; X break; X X case cxm_secam_50hz_source_format: X *(unsigned long *)arg = METEOR_FMT_SECAM; X break; X X case cxm_bw_50hz_source_format: X case cxm_bw_60hz_source_format: X case cxm_ntsc_50hz_source_format: X case cxm_pal_60hz_source_format: X *(unsigned long *)arg = METEOR_FMT_AUTOMODE; X break; X X default: X return ENXIO; X } X break; X X case METEORGFPS: X fps = cxm_saa7115_detected_fps(sc); X X if (fps < 0) X return ENXIO; X X *(unsigned short *)arg = fps; X break; X X case METEORGINPUT: X switch (sc->source) { X case cxm_tuner_source: X *(unsigned long *)arg = METEOR_INPUT_DEV1; X break; X X case cxm_line_in_source_composite: X *(unsigned long *)arg = METEOR_INPUT_DEV2; X break; X X case cxm_line_in_source_svideo: X *(unsigned long *)arg = METEOR_INPUT_DEV_SVIDEO; X break; X X default: X return ENXIO; X } X break; X X case METEORSINPUT: X source = cxm_unknown_source; X X switch (*(unsigned long *)arg & 0xf000) { X case METEOR_INPUT_DEV1: X source = cxm_tuner_source; X break; X X case METEOR_INPUT_DEV2: X source = cxm_line_in_source_composite; X break; X X case METEOR_INPUT_DEV_SVIDEO: X source = cxm_line_in_source_svideo; X break; X X default: X return EINVAL; X } X X if (sc->encoding) { X X /* X * Switching between audio + video and audio only X * subtypes isn't supported while encoding. X */ X X if (source != sc->source X && (source == cxm_fm_source X || sc->source == cxm_fm_source)) X return EBUSY; X } X X if (cxm_pause_encoder(sc) < 0) X return ENXIO; X X if (cxm_saa7115_select_source(sc, source) < 0) X return ENXIO; X if (cxm_msp_select_source(sc, source) < 0) X return ENXIO; X X sc->source = source; X X result = cxm_encoder_wait_for_lock(sc); X if (result < 0) X return ENXIO; X else if (result == 0) X return EINVAL; X X if (cxm_unpause_encoder(sc) < 0) X return ENXIO; X break; X X case METEORGSIGNAL: X *(unsigned int *)arg = sc->enc_signal; X break; X X case METEORSSIGNAL: X sig = *(unsigned int *)arg; X X if (! _SIG_VALID(sig) ) X return EINVAL; X X /* X * Historically, applications used METEOR_SIG_MODE_MASK X * to reset signal delivery. X */ X if (sig == METEOR_SIG_MODE_MASK) X sig = 0; X X s = spltty(); X#if __FreeBSD_version < 500000 X sc->enc_proc = sig ? td : NULL; X#else X sc->enc_proc = sig ? td->td_proc : NULL; X#endif X sc->enc_signal = sig; X splx (s); X break; X X case RADIO_GETFREQ: X /* Convert from kHz to MHz * 100 */ X freq = sc->tuner_freq / 10; X X *(unsigned int *)arg = freq; X break; X X case RADIO_SETFREQ: X if (sc->source == cxm_fm_source) X if (cxm_pause_encoder(sc) < 0) X return ENXIO; X X /* Convert from MHz * 100 to kHz */ X freq = *(unsigned int *)arg * 10; X X if (cxm_tuner_select_frequency(sc, cxm_tuner_fm_freq_type, X freq) < 0) X return ENXIO; X X /* X * Explicitly wait for the tuner lock so we X * can indicate if there's a station present. X */ X if (cxm_tuner_wait_for_lock(sc) < 0) X return EINVAL; X X result = cxm_encoder_wait_for_lock(sc); X if (result < 0) X return ENXIO; X else if (result == 0) X return EINVAL; X X if (sc->source == cxm_fm_source) X if (cxm_unpause_encoder(sc) < 0) X return ENXIO; X break; X X case TVTUNER_GETAFC: X *(int *)arg = sc->tuner_afc; X break; X X case TVTUNER_SETAFC: X sc->tuner_afc = (*(int *)arg != 0); X break; X X case TVTUNER_SETCHNL: X if (sc->source == cxm_tuner_source) X if (cxm_pause_encoder(sc) < 0) X return ENXIO; X X if (cxm_tuner_select_channel(sc, *(unsigned int *)arg) < 0) X return ENXIO; X X if (sc->tuner_afc) X if (cxm_tuner_apply_afc(sc) < 0) X return EINVAL; X X /* X * Explicitly wait for the tuner lock so we X * can indicate if there's a station present. X */ X if (cxm_tuner_wait_for_lock(sc) < 0) X return EINVAL; X X result = cxm_encoder_wait_for_lock(sc); X if (result < 0) X return ENXIO; X else if (result == 0) X return EINVAL; X X if (sc->source == cxm_tuner_source) X if (cxm_unpause_encoder(sc) < 0) X return ENXIO; X break; X X case TVTUNER_GETFREQ: X /* Convert from kHz to MHz * 16 */ X freq = (sc->tuner_freq * 16) / 1000; X X *(unsigned int *)arg = freq; X break; X X case TVTUNER_SETFREQ: X if (sc->source == cxm_tuner_source) X if (cxm_pause_encoder(sc) < 0) X return ENXIO; X X /* Convert from MHz * 16 to kHz */ X freq = (*(unsigned int *)arg * 1000) / 16; X X if (cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type, X freq) < 0) X return ENXIO; X X /* X * Explicitly wait for the tuner lock so we X * can indicate if there's a station present. X */ X if (cxm_tuner_wait_for_lock(sc) < 0) X return EINVAL; X X result = cxm_encoder_wait_for_lock(sc); X if (result < 0) X return ENXIO; X else if (result == 0) X return EINVAL; X X if (sc->source == cxm_tuner_source) X if (cxm_unpause_encoder(sc) < 0) X return ENXIO; X break; X X case TVTUNER_GETSTATUS: X status = cxm_tuner_status(sc); X if (status < 0) X return ENXIO; X *(unsigned long *)arg = status & 0xff; X break; X X case REMOTE_GETKEY: X remote = (struct bktr_remote *)arg; X if (cxm_ir_key(sc, (char *)remote, sizeof(*remote)) < 0) X return ENXIO; X break; X X default: X return ENOTTY; X } X X return 0; X} X X Xint cxm_poll( dev_t dev, int events, d_thread_t *td) X{ X int revents; X int unit; X struct cxm_softc *sc; X intrmask_t s; X X unit = UNIT( minor(dev) ); X X /* Get the device data */ X sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit); X if (sc == NULL) { X /* the device is no longer valid/functioning */ X return POLLHUP; X } X X revents = 0; X X s = spltty(); X if (events & (POLLIN | POLLRDNORM)) { X if (sc->enc_pool.read == sc->enc_pool.write) X selrecord(td, &sc->enc_sel); X else X revents = events & (POLLIN | POLLRDNORM); X } X splx(s); X X return revents; X} END-of-dev/cxm/cxm.c echo x - dev/cxm/cxm.h sed 's/^X//' >dev/cxm/cxm.h << 'END-of-dev/cxm/cxm.h' X/* X * Copyright (c) 2003, 2004 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * Header file for the Conexant MPEG-2 Codec driver. X */ X X#define bswap32(X) ntohl(X) X X#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(*array)) X X/* X * For simplicity several large buffers allocate during X * driver attachment which normally occurs early on X * (when large areas of memory are available) are used X * to move data to / from the card. It's not unusual X * for the memory allocation to fail due to fragmentation X * if the driver is loaded after the system has been X * running for a while. One solution is to allocate X * several PAGE_SIZE buffers instead, however it doesn't X * seem worth the trouble. X */ Xenum cxm_byte_order { cxm_unknown_byte_order, X cxm_device_mpeg_byte_order, cxm_device_yuv12_byte_order, X cxm_host_byte_order }; X Xstruct cxm_buffer { X char *vaddr; X bus_addr_t baddr; X bus_dmamap_t dmamap; X size_t size; X enum cxm_byte_order byte_order; X}; X X#define CXM_SG_BUFFERS 50 X Xstruct cxm_buffer_pool { X bus_dma_tag_t dmat; X size_t offset; X volatile unsigned int read; X volatile unsigned int write; X struct cxm_buffer bufs[CXM_SG_BUFFERS]; X}; X Xstruct cxm_codec_profile { X const char *name; X u_int32_t stream_type; X u_int32_t fps; X u_int32_t width; X u_int32_t height; X u_int32_t source_height; X struct { X u_int32_t start; X u_int32_t nlines; X u_int32_t cc; X } vbi; X u_int32_t aspect; X u_int32_t pulldown; X struct { X u_int32_t mode; X u_int32_t average; X u_int32_t peak; X } bitrate; X struct { X u_int32_t closure; X u_int32_t frames; X u_int32_t bframes; X } gop; X struct { X u_int32_t mode; X u_int32_t type; X u_int32_t spatial; X u_int32_t temporal; X } dnr; X X /* X * Audio format encoding X * X * 7 6 5 4 3 2 1 0 X * X * 0 0 44.1 kHz X * 0 1 48 kHz X * 1 0 32 kHz X * X * 0 1 Layer 1 X * 1 0 Layer 2 X * 1 1 Layer 3 X * X * L1 / L2 X * 0 0 0 0 Free fmt X * 0 0 0 1 32k / 32k X * 0 0 1 0 64k / 48k X * 0 0 1 1 96k / 56k X * 0 1 0 0 128k / 64k X * 0 1 0 1 160k / 80k X * 0 1 1 0 192k / 96k X * 0 1 1 1 224k / 112k X * 1 0 0 0 256k / 128k X * 1 0 0 1 288k / 160k X * 1 0 1 0 320k / 192k X * 1 0 1 1 352k / 224k X * 1 1 0 0 384k / 256k X * 1 1 0 1 416k / 320k X * 1 1 1 0 448k / 384k X */ X X u_int32_t audio; X}; X X#define CXM_VENDORID_CONEXANT 0x4444 X#define CXM_DEVICEID_CONEXANT_iTVC15 0x0803 X#define CXM_DEVICEID_CONEXANT_iTVC16 0x0016 X X#define CXM_VENDORID_HAUPPAUGE 0x0070 X Xstruct cxm_dev { X u_int16_t vid; X u_int16_t did; X char *name; X}; X X#define CXM_MBX_FW_CMD_MAILBOX 0 X#define CXM_MBX_FW_CMD_MAILBOXES 6 X X#define CXM_MBX_FW_DMA_MAILBOX 9 X X#define CXM_MBX_MAX_PARAMETERS 16 X X/* Mailbox flags bit definitions */ X#define CXM_MBX_FLAG_DRV_DONE 0x00000002 X#define CXM_MBX_FLAG_FW_DONE 0x00000004 X#define CXM_MBX_FLAG_IN_USE 0x00000001 X Xstruct cxm_mailbox { X u_int32_t flags; X u_int32_t command; X u_int32_t result; X u_int32_t timeout; X u_int32_t parameters[CXM_MBX_MAX_PARAMETERS]; X} __attribute__ ((packed)); X Xenum cxm_mailbox_name { cxm_unknown_mailbox, X cxm_dec_mailbox, cxm_enc_mailbox }; X X/* X * Scatter / gather is supported with the restriction X * that the size of each piece must be a multiple of X * 256 and less than 64k. X */ X#define CXM_SG_SEGMENT (0xff00 & ~(PAGE_SIZE - 1)) X Xstruct cxm_sg_entry { X u_int32_t src; X u_int32_t dst; X u_int32_t size; X} __attribute__ ((packed)); X Xstruct cxm_sg_list { X bus_dma_tag_t dmat; X struct cxm_sg_entry *vaddr; X bus_addr_t baddr; X bus_dmamap_t dmamap; X X}; X Xenum cxm_source { cxm_unknown_source, cxm_fm_source, cxm_tuner_source, X cxm_line_in_source_composite, cxm_line_in_source_svideo }; X Xenum cxm_source_format { cxm_unknown_source_format, X cxm_bw_50hz_source_format, X cxm_bw_60hz_source_format, X cxm_ntsc_50hz_source_format, X cxm_ntsc_60hz_source_format, X cxm_pal_50hz_source_format, X cxm_pal_60hz_source_format, X cxm_secam_50hz_source_format }; X Xextern const struct cxm_tuner cxm_tuners[]; X Xenum cxm_type { cxm_unknown_type, cxm_iTVC15_type, cxm_iTVC16_type }; X X/* X * Conexant iTVC15 / iTVC16 info structure, one per card installed. X */ Xstruct cxm_softc { X enum cxm_type type; X char name[10]; /* Device name and unit number */ X X struct resource *mem_res; /* Resource descriptor for registers */ X bus_space_tag_t btag; /* Bus space access functions */ X bus_space_handle_t bhandle; /* Bus space access functions */ X X struct resource *irq_res; /* Resource descriptor for interrupt */ X void *ih_cookie; /* Newbus interrupt handler cookie */ X X u_int32_t irq_mask; X X bus_dma_tag_t parent_dmat; X X struct cxm_buffer_pool enc_pool; X struct cxm_sg_list enc_sg; X X struct selinfo enc_sel; X X struct proc *enc_proc; X int enc_signal; X X unsigned int dec_mbx; X unsigned int enc_mbx; X X device_t cxm_iic; X device_t iicbus; X X const struct cxm_tuner *tuner; X const struct cxm_tuner_channels *tuner_channels; X int tuner_afc; X unsigned long tuner_freq; X X char msp_name[10]; X X const struct cxm_codec_profile *profile; X X enum cxm_source source; X X dev_t cxm_dev; /* Device entry for /dev/cxmN */ X X int is_opened; X int mpeg; X X int encoding; X int encoding_dma; X volatile int encoding_eos; X}; X X/* X * Conexant iTVC15 / iTVC16 I2C info structure, one per card installed. X */ Xstruct cxm_iic_softc { X char name[10]; /* Device name and unit number */ X bus_space_tag_t btag; /* Bus space access functions */ X bus_space_handle_t bhandle; /* Bus space access functions */ X X device_t iicbb; X X}; X X/* X * List of IVARS available to the I2C device driver X */ X#define CXM_IVAR_BHANDLE 0 X#define CXM_IVAR_BTAG 1 X#define CXM_IVAR_IICBUS 2 X X/* X * Bus resource id X */ X#define CXM_RID PCIR_MAPS X X/* X * Access macros X */ X#define CSR_WRITE_4(sc, reg, val) \ X bus_space_write_4((sc)->btag, (sc)->bhandle, (reg), (val)) X#define CSR_WRITE_2(sc, reg, val) \ X bus_space_write_2((sc)->btag, (sc)->bhandle, (reg), val)) X#define CSR_WRITE_1(sc, reg, val) \ X bus_space_write_1((sc)->btag, (sc)->bhandle, (reg), val)) X#define CSR_READ_4(sc, reg) \ X bus_space_read_4((sc)->btag, (sc)->bhandle, (reg)) X#define CSR_READ_2(sc, reg) \ X bus_space_read_2((sc)->btag, (sc)->bhandle, (reg)) X#define CSR_READ_1(sc, reg) \ X bus_space_read_1((sc)->btag, (sc)->bhandle, (reg)) X X/* X * Decoder / encoder firmware X */ Xextern const char cxm_dec_fw[]; Xextern const char cxm_enc_fw[]; X X#define CXM_FW_SIZE (256 * 1024) X X/* X * Decoder / encoder memory offsets X */ X#define CXM_MEM_DEC 0x01000000 X#define CXM_MEM_ENC 0x00000000 X X#define CXM_MEM_DEC_SIZE 0x01000000 X#define CXM_MEM_ENC_SIZE 0x01000000 X X/* X * Register offsets X */ X#define CXM_REG_AO 0x2002d00 X#define CXM_REG_APU 0x200a064 X#define CXM_REG_DEC_SDRAM_PRECHARGE 0x20008fc X#define CXM_REG_DEC_SDRAM_REFRESH 0x20008f8 X#define CXM_REG_DMA_STATUS 0x2000004 X#define CXM_REG_ENC_SDRAM_PRECHARGE 0x20007fc X#define CXM_REG_ENC_SDRAM_REFRESH 0x20007f8 X#define CXM_REG_HW_BLOCKS 0x2009054 X#define CXM_REG_I2C_GETSCL 0x2007008 X#define CXM_REG_I2C_GETSDA 0x200700c X#define CXM_REG_I2C_SETSCL 0x2007000 X#define CXM_REG_I2C_SETSDA 0x2007004 X#define CXM_REG_IRQ_MASK 0x2000048 X#define CXM_REG_IRQ_STATUS 0x2000040 X#define CXM_REG_SPU 0x2009050 X#define CXM_REG_VDM 0x2002800 X#define CXM_REG_VPU 0x2009058 X X/* X * Register values X */ X#define CXM_CMD_AO_STOP 0x00000005 X#define CXM_CMD_APU_PING 0x00000000 X#define CXM_CMD_HW_BLOCKS_RST 0xffffffff X#define CXM_CMD_SDRAM_PRECHARGE_INIT 0x0000001a X#define CXM_CMD_SDRAM_REFRESH_INIT 0x80000640 X#define CXM_CMD_SPU_STOP 0x00000001 X#define CXM_CMD_VDM_STOP 0x00000000 X#define CXM_CMD_VPU_STOP15 0xfffffffe X#define CXM_CMD_VPU_STOP16 0xffffffee X X#define CXM_DMA_ERROR_LIST 0x00000008 X#define CXM_DMA_ERROR_READ 0x00000002 X#define CXM_DMA_ERROR_WRITE 0x00000004 X#define CXM_DMA_SUCCESS 0x00000001 X X#define CXM_IRQ_DEC_DMA_DONE (1 << 20) X#define CXM_IRQ_DEC_DMA_REQUEST (1 << 22) X#define CXM_IRQ_DEC_VSYNC (1 << 10) X#define CXM_IRQ_ENC_DMA_DONE (1 << 27) X#define CXM_IRQ_ENC_DMA_REQUEST (1 << 31) X#define CXM_IRQ_ENC_EOS (1 << 30) X#define CXM_IRQ_ENC_EVENT (1 << 28) X X#define CXM_IRQ_ENC (CXM_IRQ_ENC_DMA_REQUEST | CXM_IRQ_ENC_DMA_DONE \ X | CXM_IRQ_ENC_EOS | CXM_IRQ_ENC_EVENT) X X/* X * Register masks X */ X#define CXM_MASK_SPU_ENABLE 0xfffffffe X#define CXM_MASK_VPU_ENABLE15 0xfffffff6 X#define CXM_MASK_VPU_ENABLE16 0xfffffffb X X/* X * Firmware commands X */ X#define CXM_FW_CMD_ASSIGN_3_2_PULLDOWN 0x000000b1 X#define CXM_FW_CMD_ASSIGN_ASPECT_RATIO 0x00000099 X#define CXM_FW_CMD_ASSIGN_AUDIO_PROPERTIES 0x000000bd X#define CXM_FW_CMD_ASSIGN_BITRATES 0x00000095 X#define CXM_FW_CMD_ASSIGN_CORING_LEVELS 0x0000009f X#define CXM_FW_CMD_ASSIGN_DMA_BLOCKLEN 0x000000c9 X#define CXM_FW_CMD_ASSIGN_DNR_FILTER_MODE 0x0000009b X#define CXM_FW_CMD_ASSIGN_DNR_FILTER_PROPERTIES 0x0000009d X#define CXM_FW_CMD_ASSIGN_FRAME_DROP_RATE 0x000000d0 X#define CXM_FW_CMD_ASSIGN_FRAME_RATE 0x0000008f X#define CXM_FW_CMD_ASSIGN_FRAME_SIZE 0x00000091 X#define CXM_FW_CMD_ASSIGN_GOP_CLOSURE 0x000000c5 X#define CXM_FW_CMD_ASSIGN_GOP_PROPERTIES 0x00000097 X#define CXM_FW_CMD_ASSIGN_NUM_VSYNC_LINES 0x000000d6 X#define CXM_FW_CMD_ASSIGN_OUTPUT_PORT 0x000000bb X#define CXM_FW_CMD_ASSIGN_PGM_INDEX_INFO 0x000000c7 X#define CXM_FW_CMD_ASSIGN_PLACEHOLDER 0x000000d8 X#define CXM_FW_CMD_ASSIGN_SPATIAL_FILTER_TYPE 0x000000a1 X#define CXM_FW_CMD_ASSIGN_STREAM_TYPE 0x000000b9 X#define CXM_FW_CMD_ASSIGN_VBI_LINE 0x000000b7 X#define CXM_FW_CMD_ASSIGN_VBI_PROPERTIES 0x000000c8 X#define CXM_FW_CMD_BEGIN_CAPTURE 0x00000081 X#define CXM_FW_CMD_DEC_EVENT_NOTIFICATION 0x00000017 X#define CXM_FW_CMD_DEC_GET_FW_VER 0x00000011 X#define CXM_FW_CMD_DEC_HALT_FW 0x0000000e X#define CXM_FW_CMD_ENC_EVENT_NOTIFICATION 0x000000d5 X#define CXM_FW_CMD_ENC_GET_FW_VER 0x000000c4 X#define CXM_FW_CMD_ENC_HALT_FW 0x000000c3 X#define CXM_FW_CMD_END_CAPTURE 0x00000082 X#define CXM_FW_CMD_INITIALIZE_VIDEO_INPUT 0x000000cd X#define CXM_FW_CMD_PAUSE_ENCODER 0x000000d2 X#define CXM_FW_CMD_SCHED_DMA_TO_HOST 0x000000cc X X#define CXM_FW_STD_TIMEOUT 0x00010000 X X#define CXM_FW_CAPTURE_STREAM_TYPE_MPEG 0x00000000 X#define CXM_FW_CAPTURE_STREAM_TYPE_RAW 0x00000001 X#define CXM_FW_CAPTURE_STREAM_TYPE_RAW_PASSTHROUGH 0x00000002 X#define CXM_FW_CAPTURE_STREAM_TYPE_VBI 0x00000003 X X#define CXM_FW_CAPTURE_STREAM_YUV 0x00000001 X#define CXM_FW_CAPTURE_STREAM_PCM_AUDIO 0x00000002 X#define CXM_FW_CAPTURE_STREAM_VBI 0x00000004 X X#define CXM_FW_STREAM_TYPE_DVD 0x0000000a X#define CXM_FW_STREAM_TYPE_MPEG1 0x00000002 X#define CXM_FW_STREAM_TYPE_MPEG2_PROGRAM 0x00000000 X#define CXM_FW_STREAM_TYPE_SVCD 0x0000000c X#define CXM_FW_STREAM_TYPE_VCD 0x0000000b X X#define CXM_MACROBLOCK_HEIGHT 16 X#define CXM_MACROBLOCK_WIDTH 16 X#define CXM_MACROBLOCK_SIZE (CXM_MACROBLOCK_HEIGHT * CXM_MACROBLOCK_WIDTH) X X/* X * I2C addresses X */ X#define CXM_I2C_EEPROM 0xa0 X#define CXM_I2C_IR 0x30 X#define CXM_I2C_MSP3400 0x80 X#define CXM_I2C_SAA7115 0x42 X#define CXM_I2C_TUNER 0xc2 X X/* The maximum wait time of the MSP X is 1 ms during normal operations. */ X#define CXM_I2C_TIMEOUT 1000 X X/* X * EEPROM X */ Xint cxm_eeprom_init( struct cxm_softc *sc ); Xint cxm_eeprom_tuner_type( struct cxm_softc *sc ); X X/* X * Infrared remote X */ Xint cxm_ir_init( struct cxm_softc *sc ); Xint cxm_ir_key( struct cxm_softc *sc, char *buf, int len ); X X/* X * Audio decoder X */ X#define CXM_MSP3400C_DEM 0x10 X#define CXM_MSP3400C_DFP 0x12 X Xstruct cxm_msp_setting { X unsigned char dev; X unsigned int addr; X char value[2]; X}; X Xstruct cxm_msp_command { X unsigned int nsettings; X struct cxm_msp_setting settings[4]; X}; X Xint cxm_msp_init( struct cxm_softc *sc ); Xint cxm_msp_mute( struct cxm_softc *sc ); Xint cxm_msp_unmute( struct cxm_softc *sc ); Xint cxm_msp_is_muted( struct cxm_softc *sc ); Xint cxm_msp_select_source( struct cxm_softc *sc, enum cxm_source source ); Xenum cxm_source cxm_msp_selected_source( struct cxm_softc *sc ); Xint cxm_msp_autodetect_standard( struct cxm_softc *sc ); Xint cxm_msp_is_locked( struct cxm_softc *sc ); Xint cxm_msp_wait_for_lock( struct cxm_softc *sc ); X X/* X * Tuner X */ X#define CXM_TUNER_PHILIPS_FI1216_MK2 0 X#define CXM_TUNER_PHILIPS_FM1216 1 X#define CXM_TUNER_PHILIPS_FI1236_MK2 2 X#define CXM_TUNER_PHILIPS_FM1236 3 X#define CXM_TUNER_PHILIPS_FI1246_MK2 4 X#define CXM_TUNER_PHILIPS_FM1246 5 X#define CXM_TUNER_TEMIC_4006_FH5 6 X#define CXM_TUNER_TEMIC_4009_FR5 7 X#define CXM_TUNER_TEMIC_4036_FY5 8 X#define CXM_TUNER_TEMIC_4039_FR5 9 X#define CXM_TUNER_TEMIC_4066_FY5 10 X#define CXM_TUNER_LG_TP18PSB11D 11 X#define CXM_TUNER_LG_TP18PSB01D 12 X X#define CXM_TUNER_TYPES 13 X X#define CXM_TUNER_AFC_MASK 0x07 X X#define CXM_TUNER_AFC_FREQ_MINUS_125 0x00 X#define CXM_TUNER_AFC_FREQ_MINUS_62 0x01 X#define CXM_TUNER_AFC_FREQ_CENTERED 0x02 X#define CXM_TUNER_AFC_FREQ_PLUS_62 0x03 X#define CXM_TUNER_AFC_FREQ_PLUS_125 0x04 X X#define CXM_TUNER_PHASE_LOCKED 0x40 X Xstruct cxm_tuner_band_code { X unsigned long freq; X unsigned char codes[2]; X}; X Xstruct cxm_tuner_channel_assignment { X unsigned int channel; X unsigned long freq; X unsigned long step; X}; X Xstruct cxm_tuner_channels { X const char *name; X unsigned int min_channel; X unsigned int max_channel; X unsigned long if_freq; X struct cxm_tuner_channel_assignment assignments[17]; X}; X Xstruct cxm_tuner { X const char *name; X unsigned long min_freq; X unsigned long max_freq; X struct cxm_tuner_band_code band_codes[3]; X unsigned long fm_min_freq; X unsigned long fm_max_freq; X struct cxm_tuner_band_code fm_band_code; X struct { X const struct cxm_tuner_channels *air; X const struct cxm_tuner_channels *cable; X } channels; X}; X Xenum cxm_tuner_freq_type { cxm_tuner_unknown_freq_type, cxm_tuner_fm_freq_type, X cxm_tuner_tv_freq_type }; X Xint cxm_tuner_init( struct cxm_softc *sc ); Xint cxm_tuner_select_frequency( struct cxm_softc *sc, X enum cxm_tuner_freq_type type, X unsigned long freq ); Xint cxm_tuner_select_channel( struct cxm_softc *sc, unsigned int channel ); Xint cxm_tuner_apply_afc( struct cxm_softc *sc ); Xint cxm_tuner_is_locked( struct cxm_softc *sc ); Xint cxm_tuner_wait_for_lock( struct cxm_softc *sc ); Xint cxm_tuner_status( struct cxm_softc *sc ); X X/* X * Video decoder X */ Xstruct cxm_saa7115_setting { X unsigned char addr; X unsigned int nvalues; X char values[32]; X}; X Xstruct cxm_saa7115_command { X unsigned int nsettings; X struct cxm_saa7115_setting settings[20]; X}; X Xstruct cxm_saa7115_scaling { X unsigned int width; X unsigned int height; X const struct cxm_saa7115_command *scaling; X}; X Xint cxm_saa7115_init( struct cxm_softc *sc ); Xint cxm_saa7115_mute( struct cxm_softc *sc ); Xint cxm_saa7115_unmute( struct cxm_softc *sc ); Xint cxm_saa7115_select_source( struct cxm_softc *sc, enum cxm_source source ); Xint cxm_saa7115_configure_scaler( struct cxm_softc *sc, X unsigned int width, unsigned int height ); Xenum cxm_source_format cxm_saa7115_detected_format( struct cxm_softc *sc ); Xint cxm_saa7115_detected_fps( struct cxm_softc *sc ); Xint cxm_saa7115_get_brightness( struct cxm_softc *sc ); Xint cxm_saa7115_set_brightness( struct cxm_softc *sc, X unsigned char brightness ); Xint cxm_saa7115_get_chroma_saturation( struct cxm_softc *sc ); Xint cxm_saa7115_set_chroma_saturation( struct cxm_softc *sc, X unsigned char chroma_saturation); Xint cxm_saa7115_get_contrast( struct cxm_softc *sc ); Xint cxm_saa7115_set_contrast( struct cxm_softc *sc, unsigned char contrast ); Xint cxm_saa7115_get_hue( struct cxm_softc *sc ); Xint cxm_saa7115_set_hue( struct cxm_softc *sc, unsigned char hue ); Xint cxm_saa7115_is_locked( struct cxm_softc *sc ); Xint cxm_saa7115_wait_for_lock( struct cxm_softc *sc ); END-of-dev/cxm/cxm.h echo x - dev/cxm/cxm_audio.c sed 's/^X//' >dev/cxm/cxm_audio.c << 'END-of-dev/cxm/cxm_audio.c' X/* X * Copyright (c) 2003, 2004 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * Audio decoder routines for the Conexant MPEG-2 Codec driver. X * X * Ideally these routines should be implemented as a separate X * driver which has a generic audio decoder interface so that X * it's not necessary for each multimedia driver to re-invent X * the wheel. X */ X X#include X#include X#include X#include X#include X#include X X#if __FreeBSD_version >= 500014 X# include X#else X# include X#endif X X#include X#include X#include X#include X X#include X#include X X#include X X#include X#include X X#include "iicbb_if.h" X X Xstatic const struct cxm_msp_command Xmsp343xG_init = { X 4, X { X /* Enable Automatic Sound Select */ X { CXM_MSP3400C_DEM, 0x0030, { 0x20, 0x03 } }, X /* SCART prescale = 0 dB */ X { CXM_MSP3400C_DFP, 0x000d, { 0x19, 0x00 } }, X /* FM / AM Prescale = 100 Khz and FM Matrix = Sound A Mono */ X { CXM_MSP3400C_DFP, 0x000e, { 0x24, 0x03 } }, X /* Enable Automatic Standard Select */ X { CXM_MSP3400C_DEM, 0x0020, { 0x00, 0x01 } }, X } X}; X Xstatic const struct cxm_msp_command Xmsp34xxx_mute = { X 2, X { X /* Loudspeaker volume = mute */ X { CXM_MSP3400C_DFP, 0x0000, { 0x00, 0x00 } }, X /* SC1_OUT_L/R volume = mute */ X { CXM_MSP3400C_DFP, 0x0007, { 0x00, 0x01 } } X } X}; X Xstatic const struct cxm_msp_command Xmsp34xxx_unmute = { X 2, X { X /* Loudspeaker volume = 0 db */ X { CXM_MSP3400C_DFP, 0x0000, { 0x73, 0x00 } }, X /* SC1_OUT_L/R volume = 0 db */ X { CXM_MSP3400C_DFP, 0x0007, { 0x73, 0x01 } } X } X}; X Xstatic const struct cxm_msp_command Xmsp34xxx_select_fm = { X 3, X { X /* Loudspeaker Source = SCART, Matrix = STEREO */ X { CXM_MSP3400C_DFP, 0x0008, { 0x02, 0x20 } }, X /* SCART1_L/R Source = SCART, Matrix = STEREO */ X { CXM_MSP3400C_DFP, 0x000a, { 0x02, 0x20 } }, X /* DSP In = SC2_IN_L/R, SC1_OUT_L/R Source = SCART1_L/R */ X { CXM_MSP3400C_DFP, 0x0013, { 0x0e, 0x00 } } X } X}; X Xstatic const struct cxm_msp_command Xmsp34xxx_select_line_in = { X 3, X { X /* Loudspeaker Source = SCART, Matrix = STEREO */ X { CXM_MSP3400C_DFP, 0x0008, { 0x02, 0x20 } }, X /* SCART1_L/R Source = SCART, Matrix = STEREO */ X { CXM_MSP3400C_DFP, 0x000a, { 0x02, 0x20 } }, X /* DSP In = SC1_IN_L/R, SC1_OUT_L/R Source = SCART1_L/R */ X { CXM_MSP3400C_DFP, 0x0013, { 0x0c, 0x00 } } X } X}; X Xstatic const struct cxm_msp_command Xmsp34xxx_select_tuner = { X 3, X { X /* Loudspeaker Source = demodulator (St or A), Matrix = St */ X { CXM_MSP3400C_DFP, 0x0008, { 0x03, 0x20 } }, X /* SCART1_L/R Source = demodulator (St or A), Matrix = St */ X { CXM_MSP3400C_DFP, 0x000a, { 0x03, 0x20 } }, X /* DSP In = mute, SC1_OUT_L/R Source = SCART1_L/R */ X { CXM_MSP3400C_DFP, 0x0013, { 0x0f, 0x20 } } X } X}; X X X/* Reset the MSP or DPL chip */ Xstatic int Xcxm_msp_dpl_reset( device_t iicbus, int i2c_addr ) X{ X unsigned char msg[3]; X int sent; X X /* put into reset mode */ X msg[0] = 0x00; X msg[1] = 0x80; X msg[2] = 0x00; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 X || sent != sizeof(msg)) X goto fail; X X iicbus_stop(iicbus); X X /* put back to operational mode */ X msg[0] = 0x00; X msg[1] = 0x00; X msg[2] = 0x00; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 X || sent != sizeof(msg)) X goto fail; X X iicbus_stop(iicbus); X X return 0; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X X/* Read from the MSP or DPL registers */ Xstatic int Xcxm_msp_dpl_read( device_t iicbus, int i2c_addr, X unsigned char dev, unsigned int addr, X char *buf, int len ) X{ X unsigned char msg[3]; X int received; X int sent; X X msg[0] = (unsigned char)(dev + 1); X msg[1] = (unsigned char)(addr >> 8); X msg[2] = (unsigned char)addr; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 X || sent != sizeof(msg)) X goto fail; X X if (iicbus_repeated_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0) X goto fail; X X if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0) X goto fail; X X iicbus_stop(iicbus); X X return received; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X X/* Write to the MSP or DPL registers */ Xstatic int Xcxm_msp_dpl_write( device_t iicbus, int i2c_addr, X unsigned char dev, unsigned int addr, X const char *buf, int len ) X{ X unsigned char msg[3]; X int sent; X X msg[0] = (unsigned char)dev; X msg[1] = (unsigned char)(addr >> 8); X msg[2] = (unsigned char)addr; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 X || sent != sizeof(msg)) X goto fail; X X if (iicbus_write(iicbus, buf, len, &sent, CXM_I2C_TIMEOUT) != 0) X goto fail; X X iicbus_stop(iicbus); X X return sent; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X Xint Xcxm_msp_init( struct cxm_softc *sc ) X{ X unsigned char rev1[2]; X unsigned char rev2[2]; X unsigned int i; X unsigned int nsettings; X const struct cxm_msp_setting *settings; X X if (cxm_msp_dpl_reset (sc->iicbus, CXM_I2C_MSP3400) < 0) X return -1; X X if (cxm_msp_dpl_read(sc->iicbus, CXM_I2C_MSP3400, CXM_MSP3400C_DFP, X 0x001e, rev1, sizeof(rev1)) != sizeof(rev1)) X return -1; X X if (cxm_msp_dpl_read(sc->iicbus, CXM_I2C_MSP3400, CXM_MSP3400C_DFP, X 0x001f, rev2, sizeof(rev2)) != sizeof(rev2)) X return -1; X X snprintf(sc->msp_name, sizeof(sc->msp_name), "%c4%02d%c-%c%d", X ((rev1[1] >> 4) & 0x0f) + '3', rev2[0], X (rev1[1] & 0x0f) + '@', rev1[0] + '@', rev2[1] & 0x1f); X X /* X * MSP 34x5G and MSP 44x8G are the only X * audio decoders currently supported. X */ X X nsettings = 0; X settings = NULL; X X if (strncmp(&sc->msp_name[0], "34", 2) == 0 X && strncmp(&sc->msp_name[3], "5G", 2) == 0) { X nsettings = msp343xG_init.nsettings; X settings = msp343xG_init.settings; X } X else if (strncmp(&sc->msp_name[0], "44", 2) == 0 X && strncmp(&sc->msp_name[3], "8G", 2) == 0) { X nsettings = msp343xG_init.nsettings; X settings = msp343xG_init.settings; X } X else { X printf("%s: unknown audio decoder MSP%s\n", X sc->name, sc->msp_name); X return -1; X } X X for (i = 0; i < nsettings; i++) X if (cxm_msp_dpl_write(sc->iicbus, CXM_I2C_MSP3400, X settings[i].dev, settings[i].addr, X settings[i].value, X sizeof(settings[i].value)) X != sizeof(settings[i].value)) X return -1; X X if (cxm_msp_select_source(sc, cxm_tuner_source) < 0) X return -1; X X printf("%s: MSP%s audio decoder\n", sc->name, sc->msp_name); X X return 0; X} X X Xint Xcxm_msp_mute( struct cxm_softc *sc ) X{ X unsigned int i; X unsigned int nsettings; X const struct cxm_msp_setting *settings; X X nsettings = msp34xxx_mute.nsettings; X settings = msp34xxx_mute.settings; X X for (i = 0; i < nsettings; i++) X if (cxm_msp_dpl_write(sc->iicbus, CXM_I2C_MSP3400, X settings[i].dev, settings[i].addr, X settings[i].value, X sizeof(settings[i].value)) X != sizeof(settings[i].value)) X return -1; X X return 0; X} X X Xint Xcxm_msp_unmute( struct cxm_softc *sc ) X{ X unsigned int i; X unsigned int nsettings; X const struct cxm_msp_setting *settings; X X nsettings = msp34xxx_unmute.nsettings; X settings = msp34xxx_unmute.settings; X X for (i = 0; i < nsettings; i++) X if (cxm_msp_dpl_write(sc->iicbus, CXM_I2C_MSP3400, X settings[i].dev, settings[i].addr, X settings[i].value, X sizeof(settings[i].value)) X != sizeof(settings[i].value)) X return -1; X X return 0; X} X X Xint Xcxm_msp_is_muted( struct cxm_softc *sc ) X{ X unsigned char volume[2]; X X if (cxm_msp_dpl_read(sc->iicbus, CXM_I2C_MSP3400, CXM_MSP3400C_DFP, X 0x0000, volume, sizeof(volume)) != sizeof(volume)) X return -1; X X return volume[0] == 0x00 || volume[0] == 0xff ? 1 : 0; X} X X Xint Xcxm_msp_select_source( struct cxm_softc *sc, enum cxm_source source ) X{ X unsigned int i; X unsigned int nsettings; X const struct cxm_msp_setting *settings; X X switch (source) { X case cxm_fm_source: X nsettings = msp34xxx_select_fm.nsettings; X settings = msp34xxx_select_fm.settings; X break; X X case cxm_line_in_source_composite: X case cxm_line_in_source_svideo: X nsettings = msp34xxx_select_line_in.nsettings; X settings = msp34xxx_select_line_in.settings; X break; X X case cxm_tuner_source: X nsettings = msp34xxx_select_tuner.nsettings; X settings = msp34xxx_select_tuner.settings; X break; X X default: X return -1; X } X X for (i = 0; i < nsettings; i++) X if (cxm_msp_dpl_write(sc->iicbus, CXM_I2C_MSP3400, X settings[i].dev, settings[i].addr, X settings[i].value, X sizeof(settings[i].value)) X != sizeof(settings[i].value)) X return -1; X X return 0; X} X X Xenum cxm_source Xcxm_msp_selected_source( struct cxm_softc *sc ) X{ X unsigned char dsp[2]; X unsigned char source[2]; X X if (cxm_msp_dpl_read(sc->iicbus, CXM_I2C_MSP3400, CXM_MSP3400C_DFP, X 0x0008, source, sizeof(source)) != sizeof(source)) X return cxm_unknown_source; X X switch (source[0]) { X case 0: /* FM / AM mono signal */ X case 1: /* Stereo or A / B */ X case 3: /* Stereo or A */ X case 4: /* Stereo or B */ X return cxm_tuner_source; X X case 2: /* SCART */ X break; X X default: X return cxm_unknown_source; X } X X if (cxm_msp_dpl_read(sc->iicbus, CXM_I2C_MSP3400, CXM_MSP3400C_DFP, X 0x0013, dsp, sizeof(dsp)) != sizeof(dsp)) X return cxm_unknown_source; X X if (dsp[1] & 0x20) X return cxm_unknown_source; X X switch (dsp[0] & 0x03) { X case 0: X return cxm_line_in_source_composite; X X case 2: X return cxm_fm_source; X X default: X return cxm_unknown_source; X } X} X X Xint Xcxm_msp_autodetect_standard( struct cxm_softc *sc ) X{ X unsigned int i; X unsigned int nsettings; X const struct cxm_msp_setting *settings; X X switch (cxm_msp_selected_source(sc)) { X case cxm_tuner_source: X break; X X case cxm_fm_source: X case cxm_line_in_source_composite: X case cxm_line_in_source_svideo: X return 0; X X default: X return -1; X } X X /* X * Section 3.3.2.2 of the data sheet states: X * X * A general refresh of the STANDARD SELECT X * register is not allowed. X */ X X if (cxm_msp_dpl_reset (sc->iicbus, CXM_I2C_MSP3400) < 0) X return -1; X X nsettings = msp343xG_init.nsettings; X settings = msp343xG_init.settings; X X for (i = 0; i < nsettings; i++) X if (cxm_msp_dpl_write(sc->iicbus, CXM_I2C_MSP3400, X settings[i].dev, settings[i].addr, X settings[i].value, X sizeof(settings[i].value)) X != sizeof(settings[i].value)) X return -1; X X if (cxm_msp_select_source(sc, cxm_tuner_source) < 0) X return -1; X X return 0; X} X X Xint Xcxm_msp_is_locked( struct cxm_softc *sc ) X{ X unsigned char source[2]; X unsigned char standard[2]; X unsigned char status[2]; X X if (cxm_msp_dpl_read(sc->iicbus, CXM_I2C_MSP3400, CXM_MSP3400C_DFP, X 0x0008, source, sizeof(source)) != sizeof(source)) X return -1; X X switch (source[0]) { X case 0: /* FM / AM mono signal */ X case 1: /* Stereo or A / B */ X case 3: /* Stereo or A */ X case 4: /* Stereo or B */ X break; X X default: X return 1; X } X X if (cxm_msp_dpl_read(sc->iicbus, CXM_I2C_MSP3400, CXM_MSP3400C_DEM, X 0x007e, standard, sizeof(standard)) X != sizeof(standard)) X return -1; X X if (standard[0] >= 8 || (standard[0] == 0 && standard[1] == 0)) X return 0; X X if (cxm_msp_dpl_read(sc->iicbus, CXM_I2C_MSP3400, CXM_MSP3400C_DEM, X 0x0200, status, sizeof(status)) != sizeof(status)) X return -1; X X return (status[1] & 0x06) == 0x06 ? 0 : 1; X} X X Xint Xcxm_msp_wait_for_lock( struct cxm_softc *sc ) X{ X unsigned int i; X X /* X * Section 3.3.2.1 of the data sheet states: X * X * Within 0.5 s the detection and setup of the actual X * TV sound standard is performed. The detected result X * can be read out of the STANDARD RESULT register by X * the control processor. X */ X X for (i = 0; i < 10; i++) { X X /* X * The input may have just change (prior to X * cxm_msp_wait_for_lock) so start with the X * delay to give the audio decoder a chance X * to update it's status. X */ X X tsleep(&sc->iicbus, PZERO, "audio", hz / 20 ); X X switch (cxm_msp_is_locked(sc)) { X case 1: X return 1; X X case 0: X break; X X default: X return -1; X } X } X X printf("%s: audio decoder failed to lock\n", sc->name); X X return 0; X} END-of-dev/cxm/cxm_audio.c echo x - dev/cxm/cxm_eeprom.c sed 's/^X//' >dev/cxm/cxm_eeprom.c << 'END-of-dev/cxm/cxm_eeprom.c' X/* X * Copyright (c) 2003, 2004 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * EEPROM routines for the Conexant MPEG-2 Codec driver. X * X * Ideally these routines should be implemented as a separate X * driver which has a generic EEPROM interface so that it's X * not necessary for each multimedia driver to re-invent the X * wheel. X */ X X X#include X#include X#include X#include X#include X#include X X#if __FreeBSD_version >= 500014 X# include X#else X# include X#endif X X#include X#include X#include X#include X X#include X#include X X#include X X#include X#include X X#include "iicbb_if.h" X X Xstatic int Xcxm_eeprom_read( device_t iicbus, int i2c_addr, X char *buf, int len, unsigned int offset ) X{ X char msg[1]; X int received; X int sent; X X msg[0] = (unsigned char)offset; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 X || sent != sizeof(msg)) X goto fail; X X if (iicbus_repeated_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0) X goto fail; X X if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0) X goto fail; X X iicbus_stop(iicbus); X X return received; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X Xint Xcxm_eeprom_init( struct cxm_softc *sc ) X{ X unsigned char eeprom[1]; X X if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM, X eeprom, sizeof(eeprom), 0) != sizeof(eeprom)) X return -1; X X return 0; X} X X Xint Xcxm_eeprom_tuner_type( struct cxm_softc *sc ) X{ X unsigned char eeprom[256]; X unsigned int i; X unsigned int len; X unsigned int subsystem_vendor_id; X unsigned int tuner_code; X int tuner_type; X X if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM, X eeprom, sizeof(eeprom), 0) != sizeof(eeprom)) X return -1; X X subsystem_vendor_id = (unsigned int)eeprom[254] << 8 | eeprom[255]; X tuner_type = -1; X X switch (subsystem_vendor_id) { X case CXM_VENDORID_HAUPPAUGE: X X /* X * The Hauppauge eeprom format is tagged. X */ X X if (eeprom[0] != 0x84) { X printf("%s: unknown Hauppauge eeprom format %#x\n", X sc->name, (unsigned int)eeprom[0]); X break; X } X X tuner_code = -1; X X for (i = 0; i < sizeof(eeprom); i += len) { X len = 0; X if (eeprom[i] == 0x84) { X len = (unsigned int)eeprom[i + 2] << 8 X | eeprom[i + 1]; X i += 3; X } X else if ((eeprom[i] & 0xf0) == 0x70) { X if (eeprom[i] & 0x08) X break; X len = eeprom[i] & 0x07; X i++; X } X else { X printf( X "%s: unknown Hauppauge eeprom packet %#x\n", X sc->name, (unsigned int)eeprom[i]); X return -1; X } X X if (i >= sizeof(eeprom) X || (i + len) > sizeof(eeprom)) { X printf("%s: corrupt Hauppauge eeprom packet\n", X sc->name); X return -1; X } X X switch (eeprom[i]) { X case 0x00: X tuner_code = eeprom[i + 6]; X break; X X case 0x0a: X tuner_code = eeprom[i + 2]; X break; X X default: X break; X } X } X X switch (tuner_code) { X case 0x03: /* Philips FI1216 */ X case 0x08: /* Philips FI1216 MK2 */ X tuner_type = CXM_TUNER_PHILIPS_FI1216_MK2; X break; X X case 0x1d: /* Temic 4006FH5 */ X tuner_type = CXM_TUNER_TEMIC_4006_FH5; X break; X X case 0x30: /* LG Innotek TP18PSB11D */ X tuner_type = CXM_TUNER_LG_TP18PSB11D; X break; X X case 0x05: /* Philips FI1236 */ X case 0x0a: /* Philips FI1236 MK2 */ X tuner_type = CXM_TUNER_PHILIPS_FI1236_MK2; X break; X X case 0x1a: /* Temic 4036FY5 */ X tuner_type = CXM_TUNER_TEMIC_4036_FY5; X break; X X case 0x06: /* Philips FI1246 */ X case 0x0b: /* Philips FI1246 MK2 */ X tuner_type = CXM_TUNER_PHILIPS_FI1246_MK2; X break; X X case 0x23: /* Temic 4066FY5 */ X tuner_type = CXM_TUNER_TEMIC_4066_FY5; X break; X X case 0x10: /* Philips FR1216 MK2 */ X case 0x15: /* Philips FM1216 */ X tuner_type = CXM_TUNER_PHILIPS_FM1216; X break; X X case 0x2a: /* Temic 4009FR5 */ X tuner_type = CXM_TUNER_TEMIC_4009_FR5; X break; X X case 0x2f: /* LG Innotek TP18PSB01D */ X tuner_type = CXM_TUNER_LG_TP18PSB01D; X break; X X case 0x12: /* Philips FR1236 MK2 */ X case 0x17: /* Philips FM1236 */ X tuner_type = CXM_TUNER_PHILIPS_FM1236; X break; X X case 0x21: /* Temic 4039FR5 */ X tuner_type = CXM_TUNER_TEMIC_4039_FR5; X break; X X case 0x13: /* Philips FR1246 MK2 */ X case 0x18: /* Philips FM1246 */ X tuner_type = CXM_TUNER_PHILIPS_FM1246; X break; X X default: X printf("%s: unknown tuner code %#x\n", X sc->name, tuner_code); X break; X } X break; X X default: X printf("%s: unknown subsystem vendor id %#x\n", X sc->name, subsystem_vendor_id); X break; X } X X return tuner_type; X} END-of-dev/cxm/cxm_eeprom.c echo x - dev/cxm/cxm_i2c.c sed 's/^X//' >dev/cxm/cxm_i2c.c << 'END-of-dev/cxm/cxm_i2c.c' X/* X * Copyright (c) 2003, 2004 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * I2c routines for the Conexant MPEG-2 Codec driver. X */ X X#include X#include X#include X#include X#include X#include X#include X X#if __FreeBSD_version >= 500014 X# include X#else X# include X#endif X X#include X#include X#include X#include X X#include X#include X X#if __FreeBSD_version < 500000 X# include X# include X#else X# include X# include X#endif X X#include X X#include X#include X X#include "iicbb_if.h" X X Xstatic int cxm_iic_probe( device_t dev ); Xstatic int cxm_iic_attach( device_t dev ); Xstatic int cxm_iic_detach( device_t dev ); Xstatic void cxm_iic_child_detached( device_t dev, device_t child ); X Xstatic int cxm_iic_callback( device_t, int, caddr_t * ); Xstatic int cxm_iic_reset( device_t, u_char, u_char, u_char * ); Xstatic int cxm_iic_getscl( device_t ); Xstatic int cxm_iic_getsda( device_t ); Xstatic void cxm_iic_setscl( device_t, int ); Xstatic void cxm_iic_setsda( device_t, int ); Xstatic void cxm_iic_setlines( device_t, int, int ); X Xstatic device_method_t cxm_iic_methods[] = { X /* Device interface */ X DEVMETHOD(device_probe, cxm_iic_probe), X DEVMETHOD(device_attach, cxm_iic_attach), X DEVMETHOD(device_detach, cxm_iic_detach), X X /* bus interface */ X DEVMETHOD(bus_child_detached, cxm_iic_child_detached), X DEVMETHOD(bus_print_child, bus_generic_print_child), X DEVMETHOD(bus_driver_added, bus_generic_driver_added), X X /* iicbb interface */ X DEVMETHOD(iicbb_callback, cxm_iic_callback), X DEVMETHOD(iicbb_reset, cxm_iic_reset), X X#if __FreeBSD_version < 500000 X DEVMETHOD(iicbb_getdataline, cxm_iic_getsda), X DEVMETHOD(iicbb_setlines, cxm_iic_setlines), X#else X DEVMETHOD(iicbb_getscl, cxm_iic_getscl), X DEVMETHOD(iicbb_getsda, cxm_iic_getsda), X DEVMETHOD(iicbb_setscl, cxm_iic_setscl), X DEVMETHOD(iicbb_setsda, cxm_iic_setsda), X#endif X X { 0, 0 } X}; X Xstatic driver_t cxm_iic_driver = { X "cxm_iic", X cxm_iic_methods, X sizeof(struct cxm_iic_softc), X}; X Xstatic devclass_t cxm_iic_devclass; X XMODULE_VERSION(cxm_iic, 1); XDRIVER_MODULE(cxm_iic, cxm, cxm_iic_driver, cxm_iic_devclass, 0, 0); X X X/* X * the boot time probe routine. X * X * The cxm_iic device is only probed after it has X * been established that the cxm device is present X * which means that the cxm_iic device * must * X * be present since it's built into the cxm hardware. X */ Xstatic int Xcxm_iic_probe( device_t dev ) X{ X device_set_desc(dev, "Conexant iTVC15 / iTVC16 I2C controller"); X X return 0; X} X X X/* X * the attach routine. X */ Xstatic int Xcxm_iic_attach( device_t dev ) X{ X device_t *kids; X device_t iicbus; X int error; X int numkids; X int i; X int unit; X unsigned int bhandle; X unsigned int btag; X struct cxm_iic_softc *sc; X X /* Get the device data */ X sc = device_get_softc(dev); X unit = device_get_unit(dev); X X /* build the device name */ X snprintf(sc->name, sizeof(sc->name), "cxm_iic%d",unit); X X /* retrieve the cxm btag and bhandle */ X if (BUS_READ_IVAR(device_get_parent(dev), dev, CXM_IVAR_BTAG, &btag) X || BUS_READ_IVAR(device_get_parent(dev), dev, X CXM_IVAR_BHANDLE, &bhandle)) { X device_printf(dev, X "could not retrieve bus space information\n"); X return ENXIO; X } X X sc->btag = btag; X sc->bhandle = bhandle; X X /* add bit-banging generic code onto cxm_iic interface */ X sc->iicbb = device_add_child(dev, "iicbb", -1); X X if (! sc->iicbb) { X device_printf(dev, "could not add iicbb\n"); X return ENXIO; X } X X /* probed and attached the bit-banging code */ X error = device_probe_and_attach(sc->iicbb); X X if (error) { X device_printf(dev, "could not attach iicbb\n"); X goto fail; X } X X /* locate iicbus which was attached by the bit-banging code */ X iicbus = NULL; X device_get_children(sc->iicbb, &kids, &numkids); X for (i = 0; i < numkids; i++) X if (strcmp(device_get_name(kids[i]), "iicbus") == 0) { X iicbus = kids[i]; X break; X } X free(kids, M_TEMP); X X if (! iicbus) { X device_printf(dev, "could not find iicbus\n"); X error = ENXIO; X goto fail; X } X X if (BUS_WRITE_IVAR(device_get_parent(dev), dev, X CXM_IVAR_IICBUS, (uintptr_t)iicbus)) { X device_printf(dev, "could not store iicbus information\n"); X error = ENXIO; X goto fail; X } X X return 0; X Xfail: X /* X * Detach the children before recursively deleting X * in case a child has a pointer to a grandchild X * which is used by the child's detach routine. X */ X bus_generic_detach(dev); X if (sc->iicbb) X device_delete_child(dev, sc->iicbb); X X return error; X} X X X/* X * the detach routine. X */ Xstatic int Xcxm_iic_detach( device_t dev ) X{ X struct cxm_iic_softc *sc; X device_t child; X X /* Get the device data */ X sc = device_get_softc(dev); X X (void)BUS_WRITE_IVAR(device_get_parent(dev), dev, CXM_IVAR_IICBUS, 0); X X /* X * Detach the children before recursively deleting X * in case a child has a pointer to a grandchild X * which is used by the child's detach routine. X * X * Remember the child before detaching so we can X * delete it (bus_generic_detach indirectly zeroes X * sc->child_dev). X */ X child = sc->iicbb; X bus_generic_detach(dev); X if (child) X device_delete_child(dev, child); X X return 0; X} X X X/* X * the child detached routine. X */ Xstatic void Xcxm_iic_child_detached( device_t dev, device_t child ) X{ X struct cxm_iic_softc *sc; X X /* Get the device data */ X sc = device_get_softc(dev); X X if (child == sc->iicbb) X sc->iicbb = NULL; X} X X Xstatic int Xcxm_iic_callback( device_t dev, int index, caddr_t *data ) X{ X return 0; X} X X Xstatic int Xcxm_iic_reset( device_t dev, u_char speed, u_char addr, u_char * oldaddr ) X{ X struct cxm_iic_softc *sc; X X /* Get the device data */ X sc = (struct cxm_iic_softc *)device_get_softc(dev); X X /* Set scl to 1 */ X CSR_WRITE_4(sc, CXM_REG_I2C_SETSCL, ~(int)1); X X /* Set sda to 1 */ X CSR_WRITE_4(sc, CXM_REG_I2C_SETSDA, ~(int)1); X X /* X * PCI writes may be buffered so force the X * write to complete by reading the last X * location written. X */ X X (void)CSR_READ_4(sc, CXM_REG_I2C_SETSDA); X X /* Wait for 10 usec */ X DELAY(10); X X return IIC_ENOADDR; X} X X Xstatic int Xcxm_iic_getscl( device_t dev ) X{ X struct cxm_iic_softc *sc; X X /* Get the device data */ X sc = (struct cxm_iic_softc *)device_get_softc(dev); X X /* Get sda */ X return CSR_READ_1(sc, CXM_REG_I2C_GETSCL); X} X X Xstatic int Xcxm_iic_getsda( device_t dev ) X{ X struct cxm_iic_softc *sc; X X /* Get the device data */ X sc = (struct cxm_iic_softc *)device_get_softc(dev); X X /* Get sda */ X return CSR_READ_1(sc, CXM_REG_I2C_GETSDA); X} X X Xstatic void Xcxm_iic_setscl( device_t dev, int val ) X{ X struct cxm_iic_softc *sc; X X /* Get the device data */ X sc = (struct cxm_iic_softc *)device_get_softc(dev); X X /* Set scl to the requested value */ X CSR_WRITE_4(sc, CXM_REG_I2C_SETSCL, ~(int)(val ? 1 : 0)); X X /* X * PCI writes may be buffered so force the X * write to complete by reading the last X * location written. X */ X X (void)CSR_READ_4(sc, CXM_REG_I2C_SETSCL); X} X X Xstatic void Xcxm_iic_setsda( device_t dev, int val ) X{ X struct cxm_iic_softc *sc; X X /* Get the device data */ X sc = (struct cxm_iic_softc *)device_get_softc(dev); X X /* Set sda to the requested value */ X CSR_WRITE_4(sc, CXM_REG_I2C_SETSDA, ~(int)(val ? 1 : 0)); X X /* X * PCI writes may be buffered so force the X * write to complete by reading the last X * location written. X */ X X (void)CSR_READ_4(sc, CXM_REG_I2C_SETSDA); X} X X Xstatic void Xcxm_iic_setlines( device_t dev, int ctrl, int data ) X{ X X cxm_iic_setscl(dev, ctrl); X cxm_iic_setsda(dev, data); X X /* Wait for 10 usec */ X DELAY(10); X} END-of-dev/cxm/cxm_i2c.c echo x - dev/cxm/cxm_ir.c sed 's/^X//' >dev/cxm/cxm_ir.c << 'END-of-dev/cxm/cxm_ir.c' X/* X * Copyright (c) 2003, 2004 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * Infrared remote routines for the Conexant MPEG-2 Codec driver. X * X * Ideally these routines should be implemented as a separate X * driver which has a generic infrared remote interface so that X * it's not necessary for each multimedia driver to re-invent X * the wheel. X */ X X X#include X#include X#include X#include X#include X#include X X#if __FreeBSD_version >= 500014 X# include X#else X# include X#endif X X#include X#include X#include X#include X X#include X#include X X#include X X#include X#include X X#include "iicbb_if.h" X X Xstatic int Xcxm_ir_read( device_t iicbus, int i2c_addr, char *buf, int len ) X{ X int received; X X if (iicbus_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0) X goto fail; X X iicbus_stop(iicbus); X X return received; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X Xint Xcxm_ir_init( struct cxm_softc *sc ) X{ X unsigned char key[1]; X X if (cxm_ir_read(sc->iicbus, CXM_I2C_IR, X key, sizeof(key)) != sizeof(key)) X return -1; X X printf("%s: IR Remote\n", sc->name); X X return 0; X} X X Xint Xcxm_ir_key( struct cxm_softc *sc, char *buf, int len ) X{ X int result; X X result = cxm_ir_read(sc->iicbus, CXM_I2C_IR, buf, len); X X if (result >= 0) X return result; X X /* X * If the IR receiver didn't respond, X * then wait 50 ms and try again. X */ X X tsleep(&sc->iicbus, PZERO, "IR", hz / 20 ); X X return cxm_ir_read(sc->iicbus, CXM_I2C_IR, buf, len); X} END-of-dev/cxm/cxm_ir.c echo x - dev/cxm/cxm_tuner.c sed 's/^X//' >dev/cxm/cxm_tuner.c << 'END-of-dev/cxm/cxm_tuner.c' X/* X * Copyright (c) 2003, 2004 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * Tuner routines for the Conexant MPEG-2 Codec driver. X * X * Ideally these routines should be implemented as a separate X * driver which has a generic tuner interface so that it's X * not necessary for each multimedia driver to re-invent the X * wheel. X */ X X#include X#include X#include X#include X#include X#include X X#if __FreeBSD_version >= 500014 X# include X#else X# include X#endif X X#include X#include X#include X#include X X#include X#include X X#include X X#include X#include X X#include "iicbb_if.h" X X X/* X * Channel mappings derived from X * http://developer.apple.com/technotes/tn/tn1012.html X */ X Xstatic const struct cxm_tuner_channels Xus_air_channels = { X "US Broadcast", X 2, X 69, X 45750, X { { 14, 471250, 6000 }, X { 7, 175250, 6000 }, X { 5, 77250, 6000 }, X { 2, 55250, 6000 } } X}; X Xstatic const struct cxm_tuner_channels Xus_cable_channels = { X "US Cable", X 2, X 125, X 45750, X { { 100, 649250, 6000 }, X { 95, 91250, 6000 }, X { 23, 217250, 6000 }, X { 14, 121250, 6000 }, X { 7, 175250, 6000 }, X { 5, 77250, 6000 }, X { 2, 55250, 6000 } } X}; X Xstatic const struct cxm_tuner_channels Xbg_air_channels = { X "B/G Broadcast", X 2, X 89, X 38900, X { { 82, 175250, 7000 }, X { 80, 55250, 7000 }, X { 79, 217250, 7000 }, X { 77, 209250, 7000 }, X { 76, 138250, 9000 }, X { 75, 102250, 9000 }, X { 73, 86250, 9000 }, X { 72, 64250, 7500 }, X { 70, 49750, 7500 }, X { 21, 471250, 8000 }, X { 20, 210250, 8500 }, X { 18, 192750, 8500 }, X { 16, 175250, 8000 }, X { 15, 82250, 8500 }, X { 13, 53750, 8500 }, X { 5, 175250, 7000 }, X { 2, 48250, 7000 } } X}; X Xstatic const struct cxm_tuner_channels Xbg_australia_channels = { X "B/G Australia", X 1, X 83, X 38900, X { { 28, 527250, 7000 }, X { 10, 209250, 7000 }, X { 6, 175250, 7000 }, X { 4, 95250, 7000 }, X { 3, 86250, 7000 }, X { 1, 57250, 7000 } } X}; X Xstatic const struct cxm_tuner_channels Xi_air_channels = { X "I Broadcast", X 1, X 83, X 38900, X { { 75, 179750, 5000 }, X { 71, 51750, 5000 }, X { 70, 45000, 5000 }, X { 21, 471250, 8000 }, X { 20, 0, 0 }, X { 19, 0, 0 }, X { 18, 0, 0 }, X { 17, 0, 0 }, X { 16, 0, 0 }, X { 15, 0, 0 }, X { 14, 0, 0 }, X { 13, 247250, 8000 }, X { 12, 0, 0 }, X { 4, 175250, 8000 }, X { 1, 45750, 8000 } } X}; X X Xconst struct cxm_tuner Xcxm_tuners[CXM_TUNER_TYPES] = { X { "Philips FI1216 MK2", 48250, 855250, X { { 450000, { 0x8e, 0x30 } }, X { 170000, { 0x8e, 0x90 } }, X { 48250, { 0x8e, 0xa0 } } }, X 0, 0, X { 0, { 0x00, 0x00 } }, X { &bg_air_channels, NULL } }, X { "Philips FM1216", 48250, 855250, X { { 450000, { 0xce, 0x30 } }, X { 170000, { 0xce, 0x90 } }, X { 48250, { 0xce, 0xa0 } } }, X 87500, 108000, X { 87500, { 0x88, 0xa5 } }, X { &bg_air_channels, NULL } }, X { "Philips FI1236 MK2", 55250, 801250, X { { 454000, { 0x8e, 0x30 } }, X { 160000, { 0x8e, 0x90 } }, X { 55250, { 0x8e, 0xa0 } } }, X 0, 0, X { 0, { 0x00, 0x00 } }, X { &us_air_channels, &us_cable_channels } }, X { "Philips FM1236", 55250, 801250, X { { 454000, { 0xce, 0x30 } }, X { 160000, { 0xce, 0x90 } }, X { 55250, { 0xce, 0xa0 } } }, X 76000, 108000, X { 76000, { 0x88, 0xa5 } }, X { &us_air_channels, &us_cable_channels } }, X { "Philips FI1246 MK2", 45750, 855250, X { { 450000, { 0x8e, 0x30 } }, X { 170000, { 0x8e, 0x90 } }, X { 45750, { 0x8e, 0xa0 } } }, X 0, 0, X { 0, { 0x00, 0x00 } }, X { &i_air_channels, NULL } }, X { "Philips FM1246", 45750, 855250, X { { 450000, { 0xce, 0x30 } }, X { 170000, { 0xce, 0x90 } }, X { 45750, { 0xce, 0xa0 } } }, X 87500, 108000, X { 87500, { 0x88, 0xa5 } }, X { &i_air_channels, NULL } }, X { "Temic 4006 FH5", 48250, 855250, X { { 454000, { 0x8e, 0x30 } }, X { 169000, { 0x8e, 0x90 } }, X { 48250, { 0x8e, 0xa0 } } }, X 0, 0, X { 0, { 0x00, 0x00 } }, X { &bg_air_channels, NULL } }, X { "Temic 4009 FR5", 48250, 855250, X { { 464000, { 0x8e, 0x30 } }, X { 141000, { 0x8e, 0x90 } }, X { 48250, { 0x8e, 0xa0 } } }, X 87500, 108100, X { 87500, { 0x88, 0xa5 } }, X { &bg_air_channels, NULL } }, X { "Temic 4036 FY5", 55250, 801250, X { { 453000, { 0x8e, 0x30 } }, X { 158000, { 0x8e, 0x90 } }, X { 55250, { 0x8e, 0xa0 } } }, X 0, 0, X { 0, { 0x00, 0x00 } }, X { &us_air_channels, &us_cable_channels } }, X { "Temic 4039 FR5", 55250, 801250, X { { 453000, { 0x8e, 0x30 } }, X { 158000, { 0x8e, 0x90 } }, X { 55250, { 0x8e, 0xa0 } } }, X 75900, 108100, X { 75900, { 0x88, 0xa5 } }, X { &us_air_channels, &us_cable_channels } }, X { "Temic 4066 FY5", 45750, 855250, X { { 454000, { 0x8e, 0x30 } }, X { 169000, { 0x8e, 0x90 } }, X { 45750, { 0x8e, 0xa0 } } }, X 0, 0, X { 0, { 0x00, 0x00 } }, X { &i_air_channels, NULL } }, X { "LG Innotek TPI8PSB11D", 48250, 855250, X { { 450000, { 0x8e, 0x30 } }, X { 170000, { 0x8e, 0x90 } }, X { 48250, { 0x8e, 0xa0 } } }, X 0, 0, X { 0, { 0x00, 0x00 } }, X { &bg_air_channels, NULL } }, X { "LG Innotek TPI8PSB01D", 48250, 855250, X { { 450000, { 0x8e, 0x30 } }, X { 170000, { 0x8e, 0x90 } }, X { 48250, { 0x8e, 0xa0 } } }, X 87500, 108100, X { 87500, { 0x88, 0xa5 } }, X { &bg_air_channels, NULL } } X}; X X X/* Read from the tuner registers */ Xstatic int Xcxm_tuner_read( device_t iicbus, int i2c_addr, char *buf, int len ) X{ X int received; X X if (iicbus_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0) X goto fail; X X iicbus_stop(iicbus); X X return received; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X X/* Write to the tuner registers */ Xstatic int Xcxm_tuner_write( device_t iicbus, int i2c_addr, const char *buf, int len ) X{ X int sent; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, buf, len, &sent, CXM_I2C_TIMEOUT) != 0) X goto fail; X X iicbus_stop(iicbus); X X return sent; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X Xint Xcxm_tuner_init( struct cxm_softc *sc ) X{ X unsigned char status; X int tuner_type; X X if (cxm_eeprom_init(sc) < 0) X return -1; X X tuner_type = cxm_eeprom_tuner_type(sc); X X if (tuner_type < 0 || tuner_type >= NUM_ELEMENTS(cxm_tuners)) X return -1; X X sc->tuner = &cxm_tuners[tuner_type]; X sc->tuner_channels = sc->tuner->channels.cable X ? sc->tuner->channels.cable X : sc->tuner->channels.air; X sc->tuner_freq = 0; X X if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER, &status, sizeof(status)) X != sizeof(status)) X return -1; X X if (cxm_tuner_select_channel(sc, 4) < 0) X return -1; X X printf("%s: %s tuner\n", sc->name, sc->tuner->name); X X return 0; X} X X Xint Xcxm_tuner_select_frequency( struct cxm_softc *sc, X enum cxm_tuner_freq_type freq_type, X unsigned long freq ) X{ X unsigned char msg[4]; X unsigned long N; X unsigned long osc_freq; X const struct cxm_tuner_band_code *band_codes; X X N = 0; X X switch (freq_type) { X case cxm_tuner_fm_freq_type: X X if (freq < sc->tuner->fm_min_freq X || freq > sc->tuner->fm_max_freq X || ! sc->tuner->fm_band_code.freq) X return -1; X X /* X * N = { fRF(pc) + fIF(pc) } / step_size X * X * fRF = RF frequency in MHz X * fIF = Intermediate frequency in MHz (FM = 10.70 MHz) X * step_size = Step size in MHz (FM = 50 kHz) X */ X X osc_freq = freq + 10700; X X N = (20 * osc_freq) / 1000; X X msg[0] = (unsigned char)(N >> 8); X msg[1] = (unsigned char)N; X msg[2] = sc->tuner->fm_band_code.codes[0]; X msg[3] = sc->tuner->fm_band_code.codes[1]; X break; X X case cxm_tuner_tv_freq_type: X X if (freq < sc->tuner->min_freq X || freq > sc->tuner->max_freq) X return -1; X X /* X * N = 16 * { fRF(pc) + fIF(pc) } X * X * fRF = RF frequency in MHz X * fIF = Intermediate frequency in MHz X * X * The data sheet doesn't state it, however X * this is probably the same equation as X * FM simply with 62.5 kHz as the step size. X */ X X osc_freq = freq + sc->tuner_channels->if_freq; X X N = (16 * osc_freq) / 1000; X X for (band_codes = sc->tuner->band_codes; X band_codes->freq > freq; band_codes++) X ; X X if (freq >= sc->tuner_freq) { X msg[0] = (unsigned char)(N >> 8); X msg[1] = (unsigned char)N; X msg[2] = band_codes->codes[0]; X msg[3] = band_codes->codes[1]; X } X else { X msg[0] = band_codes->codes[0]; X msg[1] = band_codes->codes[1]; X msg[2] = (unsigned char)(N >> 8); X msg[3] = (unsigned char)N; X } X break; X X default: X return -1; X } X X if (N > 32767) X return -1; X X if (cxm_tuner_write(sc->iicbus, CXM_I2C_TUNER, msg, sizeof(msg)) X != sizeof(msg)) X return -1; X X sc->tuner_freq = freq; X X return 0; X} X X Xint Xcxm_tuner_select_channel( struct cxm_softc *sc, unsigned int channel ) X{ X unsigned long freq; X const struct cxm_tuner_channel_assignment *assignments; X const struct cxm_tuner_channels *channels; X X channels = sc->tuner_channels; X X if (! channels X || channel < channels->min_channel X || channel > channels->max_channel) X return -1; X X for (assignments = channels->assignments; X assignments->channel > channel; assignments++) X ; X X if (! assignments->freq) X return -1; X X freq = assignments->freq X + (channel - assignments->channel) * assignments->step; X X return cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type, freq); X} X X Xint Xcxm_tuner_apply_afc( struct cxm_softc *sc ) X{ X unsigned char status; X unsigned int i; X unsigned long freq; X unsigned long max_offset; X unsigned long original_freq; X unsigned long prev_freq; X unsigned long step_size; X X if (cxm_tuner_wait_for_lock(sc) != 1) X return -1; X X original_freq = sc->tuner_freq; X X freq = sc->tuner_freq; X prev_freq = 0; X max_offset = 2000; X step_size = 63; X X for (i = 0; i < (max_offset / step_size); i++) { X if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER, X &status, sizeof(status)) != sizeof(status)) X break; X X if (! (status & CXM_TUNER_PHASE_LOCKED) ) X break; X X switch (status & CXM_TUNER_AFC_MASK) { X case CXM_TUNER_AFC_FREQ_CENTERED: X return 0; X X case CXM_TUNER_AFC_FREQ_MINUS_125: X case CXM_TUNER_AFC_FREQ_MINUS_62: X freq -= step_size; X break; X X case CXM_TUNER_AFC_FREQ_PLUS_62: X case CXM_TUNER_AFC_FREQ_PLUS_125: X freq += step_size; X break; X X default: X goto fail; X } X X if (freq == prev_freq) X return 0; X prev_freq = sc->tuner_freq; X X if (cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type, X freq) < 0) X break; X X /* X * Delay long enough for the tuner to update it's status. X */ X X tsleep(&sc->iicbus, PZERO, "afc", hz / 10 ); X } X Xfail: X (void)cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type, X original_freq); X return -1; X} X X Xint Xcxm_tuner_is_locked( struct cxm_softc *sc ) X{ X unsigned char status; X X if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER, &status, sizeof(status)) X != sizeof(status)) X return -1; X X return (status & CXM_TUNER_PHASE_LOCKED) ? 1 : 0; X} X X Xint Xcxm_tuner_wait_for_lock( struct cxm_softc *sc ) X{ X unsigned int i; X X /* X * The data sheet states the maximum lock-in time X * is 150 ms using fast tuning ... unfortunately X * it doesn't state the maximum lock-in time using X * moderate tuning. Hopefully 300 ms is enough. X */ X X for (i = 0; i < 3; i++) { X X /* X * The frequency may have just change (prior to X * cxm_tuner_wait_for_lock) so start with the delay X * to give the tuner a chance to update it's status. X */ X X tsleep(&sc->iicbus, PZERO, "tuner", hz / 10); X X switch (cxm_tuner_is_locked(sc)) { X case 1: X return 1; X X case 0: X break; X X default: X return -1; X } X } X X printf("%s: tuner failed to lock\n", sc->name); X X return 0; X} X X Xint Xcxm_tuner_status( struct cxm_softc *sc ) X{ X unsigned char status; X X if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER, &status, sizeof(status)) X != sizeof(status)) X return -1; X X return status; X} END-of-dev/cxm/cxm_tuner.c echo x - dev/cxm/cxm_video.c sed 's/^X//' >dev/cxm/cxm_video.c << 'END-of-dev/cxm/cxm_video.c' X/* X * Copyright (c) 2003, 2004 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * Video decoder routines for the Conexant MPEG-2 Codec driver. X * X * Ideally these routines should be implemented as a separate X * driver which has a generic video decoder interface so that X * it's not necessary for each multimedia driver to re-invent X * the wheel. X */ X X#include X#include X#include X#include X#include X#include X X#if __FreeBSD_version >= 500014 X# include X#else X# include X#endif X X#include X#include X#include X#include X X#include X#include X X#include X X#include X#include X X#include "iicbb_if.h" X X Xstatic const struct cxm_saa7115_command Xsaa7115_init = { X 19, X { X /* Full auto mode for CVBS */ X { 0x01, 1, { 0x08 } }, X { 0x03, 18, { 0x20, 0x90, 0x90, 0xeb, 0xe0, 0xb0, 0x40, 0x80, X 0x44, 0x40, 0x00, 0x03, 0x2a, 0x06, 0x00, 0x9d, X 0x80, 0x01 } }, X { 0x17, 7, { 0x99, 0x40, 0x80, 0x77, 0x42, 0xa9, 0x01 } }, X X /* X * VBI data slicer X * X * NTSC raw VBI data on lines 10 through 21 X * PAL raw VBI data on lines 6 through 22 X * X * Actually lines 21 and 22 are set by the X * NTSC and PAL specific configurations. X */ X { 0x40, 20, { 0x40, 0x00, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd, X 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, X 0xdd, 0xdd, 0xdd, 0xdd } }, X { 0x56, 4, { 0x00, 0x00, 0x00, 0x47 } }, X { 0x5c, 3, { 0x00, 0x1f, 0x35 } }, X X /* I-port and X-port configuration */ X { 0x80, 2, { 0x00, 0x01 } }, X { 0x83, 5, { 0x00, 0x20, 0x21, 0xc5, 0x01 } }, X X /* Scaler input configuration and output format settings */ X { 0xc0, 4, { 0x00, 0x08, 0x00, 0x80 } }, X X /* VBI scaler configuration */ X { 0x90, 4, { 0x80, 0x48, 0x00, 0x84 } }, X { 0xa0, 3, { 0x01, 0x00, 0x00 } }, X { 0xa4, 3, { 0x80, 0x40, 0x40 } }, X { 0xa8, 3, { 0x00, 0x02, 0x00 } }, X { 0xac, 3, { 0x00, 0x01, 0x00 } }, X { 0xb0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } }, X { 0xb8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, X X /* Audio Master Clock to Audio Serial Clock ratio */ X { 0x38, 3, { 0x03, 0x10, 0x00 } }, X X /* PLL2 target clock 27 MHz (using a 32.11 MHz crystal) */ X { 0xf1, 4, { 0x05, 0xd0, 0x35, 0x00 } }, X X /* Pulse generator */ X { 0xf6, 10, { 0x61, 0x0e, 0x60, 0x0e, 0x60, 0x0e, 0x00, X 0x00, 0x00, 0x88 } } X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_mute = { X 1, X { X /* Disable I-port */ X { 0x87, 1, { 0x00 } }, X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_unmute = { X 1, X { X /* Enable I-port */ X { 0x87, 1, { 0x01 } }, X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_select_fm = { X 1, X { X /* Enable audio clock */ X { 0x88, 1, { 0x33 } } X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_select_line_in_composite = { X 3, X { X /* Amp plus anti-alias filter, CVBS from AI11 */ X { 0x02, 1, { 0xc0 } }, X /* Adaptive luminance comb filter */ X { 0x09, 1, { 0x40 } }, X X /* Enable AD1, audio clock, scaler, decoder */ X { 0x88, 1, { 0x70 } } X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_select_line_in_svideo = { X 3, X { X /* Amp plus anti-alias filter, Y / C from AI11 / AI21 */ X { 0x02, 1, { 0xc8 } }, X /* Bypass chrominance trap / comb filter */ X { 0x09, 1, { 0x80 } }, X X /* Enable AD1 & 2, audio clock, scaler, decoder */ X { 0x88, 1, { 0xf0 } } X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_select_tuner = { X 3, X { X /* Amp plus anti-alias filter, CVBS (auto gain) from AI23 */ X { 0x02, 1, { 0xc4 } }, X /* Adaptive luminance comb filter */ X { 0x09, 1, { 0x40 } }, X X /* Enable AD2, audio clock, scaler, decoder */ X { 0x88, 1, { 0xb0 } } X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_scaler_vcd_ntsc_double_lines = { X 15, X { X /* X * Input window = 720 x 240, output window = 352 x 240 with X * YS extended by 2 as per section 17.4 of the data sheet X * and YO accounting for scaler processing triggering at X * line 5 and active video starting at line 23 (see section X * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet). X * NTSC active video should actually start at line 22, however X * not all channels / programs do. X */ X { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x12, 0x00, 0xf2, 0x00, X 0x60, 0x01, 0xf0, 0x00 } }, X X /* Prefiltering and prescaling */ X { 0xd0, 3, { 0x02, 0x02, 0xaa } }, X X /* Brightness, contrast, and saturation */ X { 0xd4, 3, { 0x80, 0x40, 0x40 } }, X X /* Horizontal phase scaling */ X { 0xd8, 3, { 0x18, 0x04, 0x00 } }, X { 0xdc, 3, { 0x0c, 0x02, 0x00 } }, X X /* Vertical scaling */ X { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } }, X X /* Vertical phase offsets */ X { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, X X /* X * VBI input window = 720 x 12, output window = 1440 x 12. X */ X { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x05, 0x00, 0x0c, 0x00, X 0xa0, 0x05, 0x0c, 0x00 } }, X X /* Inverted VGATE start at line 23, stop after line 263 */ X { 0x15, 2, { 0x02, 0x12 } }, X X /* VBI data slicer 525 lines, line 21 is closed caption */ X { 0x54, 2, { 0x4d, 0x00 } }, X { 0x5a, 2, { 0x06, 0x83 } }, X X /* PLL2 525 lines, 27 Mhz target clock */ X { 0xf0, 1, { 0xad } }, X X /* Pulse generator 525 lines, 27 Mhz target clock */ X { 0xf5, 1, { 0xad } }, X X /* Audio clock 44.1 kHz NTSC (using a 32.11 MHz crystal) */ X { 0x30, 3, { 0xbc, 0xdf, 0x02 } }, X { 0x34, 3, { 0xf2, 0x00, 0x2d } }, X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_scaler_vcd_pal_double_lines = { X 15, X { X /* X * Input window = 720 x 288, output window = 352 x 288 with X * YS extended by 2 as per section 17.4 of the data sheet X * and YO accounting for scaler processing triggering at X * line 2 and active video starting at line 25 (see section X * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet). X * PAL active video should actually start at line 24, however X * not all channels / programs do. X */ X { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x17, 0x00, 0x22, 0x01, X 0x60, 0x01, 0x20, 0x01 } }, X X /* Prefiltering and prescaling */ X { 0xd0, 3, { 0x02, 0x02, 0xaa } }, X X /* Brightness, contrast, and saturation */ X { 0xd4, 3, { 0x80, 0x40, 0x40 } }, X X /* Horizontal phase scaling */ X { 0xd8, 3, { 0x18, 0x04, 0x00 } }, X { 0xdc, 3, { 0x0c, 0x02, 0x00 } }, X X /* Vertical scaling */ X { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } }, X X /* Vertical phase offsets */ X { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, X X /* X * VBI input window = 720 x 17, output window = 1440 x 17. X */ X { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x04, 0x00, 0x11, 0x00, X 0xa0, 0x05, 0x11, 0x00 } }, X X /* Inverted VGATE start at line 25, stop after line 313 */ X { 0x15, 2, { 0x37, 0x17 } }, X X /* VBI data slicer 625 lines, line 22 is closed caption */ X { 0x54, 2, { 0xdd, 0x4d } }, X { 0x5a, 2, { 0x03, 0x03 } }, X X /* PLL2 625 lines, 27 Mhz target clock */ X { 0xf0, 1, { 0xb0 } }, X X /* Pulse generator 625 lines, 27 Mhz target clock */ X { 0xf5, 1, { 0xb0 } }, X X /* Audio clock 44.1 kHz PAL (using a 32.11 MHz crystal) */ X { 0x30, 3, { 0x00, 0x72, 0x03 } }, X { 0x34, 3, { 0xf2, 0x00, 0x2d } }, X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_scaler_svcd_ntsc = { X 15, X { X /* X * Input window = 720 x 240, output window = 480 x 240 with X * YS extended by 2 as per section 17.4 of the data sheet X * and YO accounting for scaler processing triggering at X * line 5 and active video starting at line 23 (see section X * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet). X * NTSC active video should actually start at line 22, however X * not all channels / programs do. X */ X { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x12, 0x00, 0xf2, 0x00, X 0xe0, 0x01, 0xf0, 0x00 } }, X X /* Prefiltering and prescaling */ X { 0xd0, 3, { 0x01, 0x00, 0x00 } }, X X /* Brightness, contrast, and saturation */ X { 0xd4, 3, { 0x80, 0x40, 0x40 } }, X X /* Horizontal phase scaling */ X { 0xd8, 3, { 0x00, 0x06, 0x00 } }, X { 0xdc, 3, { 0x00, 0x03, 0x00 } }, X X /* Vertical scaling */ X { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } }, X X /* Vertical phase offsets */ X { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, X X /* X * VBI input window = 720 x 12, output window = 1440 x 12. X */ X { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x05, 0x00, 0x0c, 0x00, X 0xa0, 0x05, 0x0c, 0x00 } }, X X /* Inverted VGATE start at line 23, stop after line 263 */ X { 0x15, 2, { 0x02, 0x12 } }, X X /* VBI data slicer 525 lines, line 21 is closed caption */ X { 0x54, 2, { 0x4d, 0x00 } }, X { 0x5a, 2, { 0x06, 0x83 } }, X X /* PLL2 525 lines, 27 Mhz target clock */ X { 0xf0, 1, { 0xad } }, X X /* Pulse generator 525 lines, 27 Mhz target clock */ X { 0xf5, 1, { 0xad } }, X X /* Audio clock 44.1 kHz NTSC (using a 32.11 MHz crystal) */ X { 0x30, 3, { 0xbc, 0xdf, 0x02 } }, X { 0x34, 3, { 0xf2, 0x00, 0x2d } }, X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_scaler_svcd_pal = { X 15, X { X /* X * Input window = 720 x 288, output window = 480 x 288 with X * YS extended by 2 as per section 17.4 of the data sheet X * and YO accounting for scaler processing triggering at X * line 2 and active video starting at line 25 (see section X * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet). X * PAL active video should actually start at line 24, however X * not all channels / programs do. X */ X { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x17, 0x00, 0x22, 0x01, X 0xe0, 0x01, 0x20, 0x01 } }, X X /* Prefiltering and prescaling */ X { 0xd0, 3, { 0x01, 0x00, 0x00 } }, X X /* Brightness, contrast, and saturation */ X { 0xd4, 3, { 0x80, 0x40, 0x40 } }, X X /* Horizontal phase scaling */ X { 0xd8, 3, { 0x00, 0x06, 0x00 } }, X { 0xdc, 3, { 0x00, 0x03, 0x00 } }, X X /* Vertical scaling */ X { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } }, X X /* Vertical phase offsets */ X { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, X X /* X * VBI input window = 720 x 17, output window = 1440 x 17. X */ X { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x04, 0x00, 0x11, 0x00, X 0xa0, 0x05, 0x11, 0x00 } }, X X /* Inverted VGATE start at line 25, stop after line 313 */ X { 0x15, 2, { 0x37, 0x17 } }, X X /* VBI data slicer 625 lines, line 22 is closed caption */ X { 0x54, 2, { 0xdd, 0x4d } }, X { 0x5a, 2, { 0x03, 0x03 } }, X X /* PLL2 625 lines, 27 Mhz target clock */ X { 0xf0, 1, { 0xb0 } }, X X /* Pulse generator 625 lines, 27 Mhz target clock */ X { 0xf5, 1, { 0xb0 } }, X X /* Audio clock 44.1 kHz PAL (using a 32.11 MHz crystal) */ X { 0x30, 3, { 0x00, 0x72, 0x03 } }, X { 0x34, 3, { 0xf2, 0x00, 0x2d } }, X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_scaler_dvd_ntsc = { X 15, X { X /* X * Input window = 720 x 240, output window = 720 x 240 with X * YS extended by 2 as per section 17.4 of the data sheet X * and YO accounting for scaler processing triggering at X * line 5 and active video starting at line 23 (see section X * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet). X * NTSC active video should actually start at line 22, however X * not all channels / programs do. X */ X { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x12, 0x00, 0xf2, 0x00, X 0xd0, 0x02, 0xf0, 0x00 } }, X X /* Prefiltering and prescaling */ X { 0xd0, 3, { 0x01, 0x00, 0x00 } }, X X /* Brightness, contrast, and saturation */ X { 0xd4, 3, { 0x80, 0x40, 0x40 } }, X X /* Horizontal phase scaling */ X { 0xd8, 3, { 0x00, 0x04, 0x00 } }, X { 0xdc, 3, { 0x00, 0x02, 0x00 } }, X X /* Vertical scaling */ X { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } }, X X /* Vertical phase offsets */ X { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, X X /* X * VBI input window = 720 x 12, output window = 1440 x 12. X */ X { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x05, 0x00, 0x0c, 0x00, X 0xa0, 0x05, 0x0c, 0x00 } }, X X /* Inverted VGATE start at line 23, stop after line 263 */ X { 0x15, 2, { 0x02, 0x12 } }, X X /* VBI data slicer 525 lines, line 21 is closed caption */ X { 0x54, 2, { 0x4d, 0x00 } }, X { 0x5a, 2, { 0x06, 0x83 } }, X X /* PLL2 525 lines, 27 Mhz target clock */ X { 0xf0, 1, { 0xad } }, X X /* Pulse generator 525 lines, 27 Mhz target clock */ X { 0xf5, 1, { 0xad } }, X X /* Audio clock 48 kHz NTSC (using a 32.11 MHz crystal) */ X { 0x30, 3, { 0xcd, 0x20, 0x03 } }, X { 0x34, 3, { 0xce, 0xfb, 0x30 } }, X } X}; X Xstatic const struct cxm_saa7115_command Xsaa7115_scaler_dvd_pal = { X 15, X { X /* X * Input window = 720 x 288, output window = 720 x 288 with X * YS extended by 2 as per section 17.4 of the data sheet X * and YO accounting for scaler processing triggering at X * line 2 and active video starting at line 25 (see section X * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet). X * PAL active video should actually start at line 24, however X * not all channels / programs do. X */ X { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x17, 0x00, 0x22, 0x01, X 0xd0, 0x02, 0x20, 0x01 } }, X X /* Prefiltering and prescaling */ X { 0xd0, 3, { 0x01, 0x00, 0x00 } }, X X /* Brightness, contrast, and saturation */ X { 0xd4, 3, { 0x80, 0x40, 0x40 } }, X X /* Horizontal phase scaling */ X { 0xd8, 3, { 0x00, 0x04, 0x00 } }, X { 0xdc, 3, { 0x00, 0x02, 0x00 } }, X X /* Vertical scaling */ X { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } }, X X /* Vertical phase offsets */ X { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, X X /* X * VBI input window = 720 x 17, output window = 1440 x 17. X */ X { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x04, 0x00, 0x11, 0x00, X 0xa0, 0x05, 0x11, 0x00 } }, X X /* Inverted VGATE start at line 25, stop after line 313 */ X { 0x15, 2, { 0x37, 0x17 } }, X X /* VBI data slicer 625 lines, line 22 is closed caption */ X { 0x54, 2, { 0xdd, 0x4d } }, X { 0x5a, 2, { 0x03, 0x03 } }, X X /* PLL2 625 lines, 27 Mhz target clock */ X { 0xf0, 1, { 0xb0 } }, X X /* Pulse generator 625 lines, 27 Mhz target clock */ X { 0xf5, 1, { 0xb0 } }, X X /* Audio clock 48 kHz PAL (using a 32.11 MHz crystal) */ X { 0x30, 3, { 0x00, 0xc0, 0x03 } }, X { 0x34, 3, { 0xce, 0xfb, 0x30 } }, X } X}; X Xstatic const struct cxm_saa7115_scaling Xsaa7115_scalings[] = { X { 352, 480, &saa7115_scaler_vcd_ntsc_double_lines }, X { 352, 576, &saa7115_scaler_vcd_pal_double_lines }, X { 480, 480, &saa7115_scaler_svcd_ntsc }, X { 480, 576, &saa7115_scaler_svcd_pal }, X { 720, 480, &saa7115_scaler_dvd_ntsc }, X { 720, 576, &saa7115_scaler_dvd_pal } X}; X X/* Reset the SAA7115 chip */ Xstatic int Xcxm_saa7115_reset( device_t iicbus, int i2c_addr ) X{ X unsigned char msg[2]; X int sent; X X /* put into reset mode */ X msg[0] = 0x88; X msg[1] = 0x0b; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 X || sent != sizeof(msg)) X goto fail; X X iicbus_stop(iicbus); X X /* put back to operational mode */ X msg[0] = 0x88; X msg[1] = 0x2b; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 X || sent != sizeof(msg)) X goto fail; X X iicbus_stop(iicbus); X X return 0; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X X/* Read from the SAA7115 registers */ Xstatic int Xcxm_saa7115_read( device_t iicbus, int i2c_addr, X unsigned char addr, char *buf, int len ) X{ X unsigned char msg[1]; X int received; X int sent; X X msg[0] = addr; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 X || sent != sizeof(msg)) X goto fail; X X if (iicbus_repeated_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0) X goto fail; X X if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0) X goto fail; X X iicbus_stop(iicbus); X X return received; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X X/* Write to the SAA7115 registers */ Xstatic int Xcxm_saa7115_write( device_t iicbus, int i2c_addr, X unsigned char addr, const char *buf, int len ) X{ X unsigned char msg[1]; X int sent; X X msg[0] = addr; X X if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0) X return -1; X X if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0 X || sent != sizeof(msg)) X goto fail; X X if (iicbus_write(iicbus, buf, len, &sent, CXM_I2C_TIMEOUT) != 0) X goto fail; X X iicbus_stop(iicbus); X X return sent; X Xfail: X iicbus_stop(iicbus); X return -1; X} X X Xint Xcxm_saa7115_init( struct cxm_softc *sc ) X{ X char name[5]; X unsigned char id[1]; X unsigned char rev; X unsigned int i; X unsigned int nsettings; X const struct cxm_saa7115_setting *settings; X X if (cxm_saa7115_reset (sc->iicbus, CXM_I2C_SAA7115) < 0) X return -1; X X name[4] = '\0'; X for (i = 0; i < 4; i++) { X id[0] = 2 + i; X X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x00, X id, sizeof(id)) != sizeof(id)) X return -1; X X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x00, X id, sizeof(id)) != sizeof(id)) X return -1; X X name[i] = '0' + (id[0] & 0x0f); X rev = id[0] >> 4; X } X X /* X * SAA 7115 is the only video decoder currently supported. X */ X X nsettings = 0; X settings = NULL; X X if (strcmp(name, "7115") == 0) { X nsettings = saa7115_init.nsettings; X settings = saa7115_init.settings; X } X else { X printf("%s: unknown video decoder SAA%s\n", X sc->name, name); X return -1; X } X X for (i = 0; i < nsettings; i++) X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, X settings[i].addr, X settings[i].values, settings[i].nvalues) X != settings[i].nvalues) X return -1; X X if (cxm_saa7115_select_source(sc, cxm_tuner_source) < 0) X return -1; X X printf("%s: SAA%s rev %u video decoder\n", X sc->name, name, (unsigned int)rev); X X return 0; X} X X Xint Xcxm_saa7115_mute( struct cxm_softc *sc ) X{ X unsigned int i; X unsigned int nsettings; X const struct cxm_saa7115_setting *settings; X X nsettings = saa7115_mute.nsettings; X settings = saa7115_mute.settings; X X for (i = 0; i < nsettings; i++) X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, X settings[i].addr, X settings[i].values, settings[i].nvalues) X != settings[i].nvalues) X return -1; X X return 0; X} X X Xint Xcxm_saa7115_unmute( struct cxm_softc *sc ) X{ X unsigned int i; X unsigned int nsettings; X const struct cxm_saa7115_setting *settings; X X nsettings = saa7115_unmute.nsettings; X settings = saa7115_unmute.settings; X X for (i = 0; i < nsettings; i++) X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, X settings[i].addr, X settings[i].values, settings[i].nvalues) X != settings[i].nvalues) X return -1; X X return 0; X} X X Xint Xcxm_saa7115_select_source( struct cxm_softc *sc, enum cxm_source source ) X{ X unsigned int i; X unsigned int nsettings; X const struct cxm_saa7115_setting *settings; X X switch (source) { X case cxm_fm_source: X nsettings = saa7115_select_fm.nsettings; X settings = saa7115_select_fm.settings; X break; X X case cxm_line_in_source_composite: X nsettings = saa7115_select_line_in_composite.nsettings; X settings = saa7115_select_line_in_composite.settings; X break; X X case cxm_line_in_source_svideo: X nsettings = saa7115_select_line_in_svideo.nsettings; X settings = saa7115_select_line_in_svideo.settings; X break; X X case cxm_tuner_source: X nsettings = saa7115_select_tuner.nsettings; X settings = saa7115_select_tuner.settings; X break; X X default: X return -1; X } X X for (i = 0; i < nsettings; i++) X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, X settings[i].addr, X settings[i].values, settings[i].nvalues) X != settings[i].nvalues) X return -1; X X return 0; X} X X Xint Xcxm_saa7115_configure_scaler( struct cxm_softc *sc, X unsigned int width, unsigned int height ) X{ X unsigned char power[1]; X unsigned char task[1]; X unsigned int i; X unsigned int nsettings; X const struct cxm_saa7115_setting *settings; X X for (i = 0; NUM_ELEMENTS(saa7115_scalings); i++) X if (saa7115_scalings[i].width == width X && saa7115_scalings[i].height == height) X break; X X if (i >= NUM_ELEMENTS(saa7115_scalings)) X return -1; X X nsettings = saa7115_scalings[i].scaling->nsettings; X settings = saa7115_scalings[i].scaling->settings; X X /* X * Reset scaler. X */ X X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x88, X power, sizeof(power)) != sizeof(power)) X return -1; X X power[0] &= ~0x20; X X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x88, X power, sizeof(power)) != sizeof(power)) X return -1; X X /* X * Configure scaler. X */ X X for (i = 0; i < nsettings; i++) X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, X settings[i].addr, X settings[i].values, settings[i].nvalues) X != settings[i].nvalues) X return -1; X X /* X * Enable task register set A and B. X */ X X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x80, X task, sizeof(task)) != sizeof(task)) X return -1; X X task[0] |= 0x30; X X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x80, X task, sizeof(task)) != sizeof(task)) X return -1; X X /* X * Enable scaler. X */ X X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x88, X power, sizeof(power)) != sizeof(power)) X return -1; X X power[0] |= 0x20; X X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x88, X power, sizeof(power)) != sizeof(power)) X return -1; X X return 0; X} X X Xenum cxm_source_format Xcxm_saa7115_detected_format( struct cxm_softc *sc ) X{ X unsigned char status[2]; X enum cxm_source_format source_format; X X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x1e, X status, sizeof(status)) != sizeof(status)) X return cxm_unknown_source_format; X X if (! (status[1] & 0x01) ) { X printf("%s: video decoder isn't locked\n", sc->name); X return cxm_unknown_source_format; X } X X source_format = cxm_unknown_source_format; X X if (! (status[1] & 0x20) ) X switch (status[0] & 0x03) { X case 0: X source_format = cxm_bw_50hz_source_format; X break; X X case 1: X source_format = cxm_ntsc_50hz_source_format; X break; X X case 2: X source_format = cxm_pal_50hz_source_format; X break; X X case 3: X source_format = cxm_secam_50hz_source_format; X break; X X default: X break; X } X else X switch (status[0] & 0x03) { X case 0: X source_format = cxm_bw_60hz_source_format; X break; X X case 1: X source_format = cxm_ntsc_60hz_source_format; X break; X X case 2: X source_format = cxm_pal_60hz_source_format; X break; X X default: X break; X } X X return source_format; X} X X Xint Xcxm_saa7115_detected_fps( struct cxm_softc *sc ) X{ X unsigned char status[1]; X X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x1f, X status, sizeof(status)) != sizeof(status)) X return -1; X X if (! (status[0] & 0x01) ) { X printf("%s: video decoder isn't locked\n", sc->name); X return -1; X } X X return (status[0] & 0x20) ? 30 : 25; X} X X Xint Xcxm_saa7115_get_brightness( struct cxm_softc *sc ) X{ X unsigned char brightness; X X /* X * Brightness is treated as an unsigned value by the decoder. X * 0 = dark, 128 = ITU level, 255 = bright X */ X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0a, X &brightness, sizeof(brightness)) X != sizeof(brightness)) X return -1; X X return brightness; X} X X Xint Xcxm_saa7115_set_brightness( struct cxm_softc *sc, unsigned char brightness ) X{ X X /* X * Brightness is treated as an unsigned value by the decoder. X * 0 = dark, 128 = ITU level, 255 = bright X */ X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0a, X &brightness, sizeof(brightness)) X != sizeof(brightness)) X return -1; X X return 0; X} X X Xint Xcxm_saa7115_get_chroma_saturation( struct cxm_softc *sc ) X{ X unsigned char chroma_saturation; X X /* X * Chroma saturation is treated as a signed value by the decoder. X * -128 = -2.0 (inverse chrominance), -64 = 1.0 (inverse chrominance), X * 0 = 0 (color off), 64 = 1.0 (ITU level), 127 = 1.984 (maximum) X */ X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0c, X &chroma_saturation, sizeof(chroma_saturation)) X != sizeof(chroma_saturation)) X return -1; X X return chroma_saturation; X} X X Xint Xcxm_saa7115_set_chroma_saturation( struct cxm_softc *sc, X unsigned char chroma_saturation ) X{ X X /* X * Chroma saturation is treated as a signed value by the decoder. X * -128 = -2.0 (inverse chrominance), -64 = 1.0 (inverse chrominance), X * 0 = 0 (color off), 64 = 1.0 (ITU level), 127 = 1.984 (maximum) X */ X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0c, X &chroma_saturation, sizeof(chroma_saturation)) X != sizeof(chroma_saturation)) X return -1; X X return 0; X} X X Xint Xcxm_saa7115_get_contrast( struct cxm_softc *sc ) X{ X unsigned char contrast; X X /* X * Contrast is treated as a signed value by the decoder. X * -128 = -2.0 (inverse luminance), -64 = 1.0 (inverse luminance), X * 0 = 0 (luminance off), 64 = 1.0, 68 = 1.063 (ITU level), X * 127 = 1.984 (maximum) X */ X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0b, X &contrast, sizeof(contrast)) != sizeof(contrast)) X return -1; X X return contrast; X} X X Xint Xcxm_saa7115_set_contrast( struct cxm_softc *sc, unsigned char contrast ) X{ X X /* X * Contrast is treated as a signed value by the decoder. X * -128 = -2.0 (inverse luminance), -64 = 1.0 (inverse luminance), X * 0 = 0 (luminance off), 64 = 1.0, 68 = 1.063 (ITU level), X * 127 = 1.984 (maximum) X */ X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0b, X &contrast, sizeof(contrast)) != sizeof(contrast)) X return -1; X X return 0; X} X X Xint Xcxm_saa7115_get_hue( struct cxm_softc *sc ) X{ X unsigned char hue; X X /* X * Hue is treated as a signed value by the decoder. X * -128 = -180.0, 0 = 0.0, 127 = +178.6 X */ X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0d, X &hue, sizeof(hue)) X != sizeof(hue)) X return -1; X X return hue; X} X X Xint Xcxm_saa7115_set_hue( struct cxm_softc *sc, unsigned char hue ) X{ X X /* X * Hue is treated as a signed value by the decoder. X * -128 = -180.0, 0 = 0.0, 127 = +178.6 X */ X if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0d, X &hue, sizeof(hue)) X != sizeof(hue)) X return -1; X X return 0; X} X X Xint Xcxm_saa7115_is_locked( struct cxm_softc *sc ) X{ X unsigned char status[1]; X X if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x1f, X status, sizeof(status)) != sizeof(status)) X return -1; X X return (status[0] & 0x01) ? 1 : 0; X} X X Xint Xcxm_saa7115_wait_for_lock( struct cxm_softc *sc ) X{ X unsigned int i; X X /* X * Section 2.7 of the data sheet states: X * X * Ultra-fast frame lock (almost 1 field) X * X * so hopefully 500 ms is enough (the lock X * sometimes takes a long time to occur ... X * possibly due to the time it takes to X * autodetect the format). X */ X X for (i = 0; i < 10; i++) { X X /* X * The input may have just change (prior to X * cxm_saa7115_wait_for_lock) so start with X * the delay to give the video decoder a X * chance to update it's status. X */ X X tsleep(&sc->iicbus, PZERO, "video", hz / 20 ); X X switch (cxm_saa7115_is_locked(sc)) { X case 1: X return 1; X X case 0: X break; X X default: X return -1; X } X } X X printf("%s: video decoder failed to lock\n", sc->name); X X return 0; X} END-of-dev/cxm/cxm_video.c echo x - dev/cxm/cxm_extract_fw.c sed 's/^X//' >dev/cxm/cxm_extract_fw.c << 'END-of-dev/cxm/cxm_extract_fw.c' X/* X * Copyright (c) 2003 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * Conexant MPEG-2 Codec firmware extraction program. X * X * Generates cxm_dec_fw.c and cxm_enc_fw.c from the X * Hauppauge PVR-250 / PVR-350 Microsoft Windows driver X * (i.e. hcwpvrp2.sys). X * X * This was written using the invaluable information X * compiled by The IvyTV Project (ivtv.sourceforge.net). X */ X X#include X#include X#include X#include X#include X#include X#include X#include X X Xconst char *MyName = "cxm_extract_fw"; X Xconst u_int8_t decoder_magic[] = { X 0xa7, 0x03, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa }; Xconst u_int8_t encoder_magic[] = { X 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa }; X X Xstatic int Xsave_firmware (const char *name, const u_int8_t *buf, size_t nbytes) X { X FILE *ofp; X char outfile[MAXPATHLEN]; X size_t i; X X if (nbytes < (256 * 1024)) { X fprintf (stderr, "%s: save_firmware -- firmware image isn't long enough\n", X MyName); X return -1; X } X X if (snprintf (outfile, sizeof (outfile), "%s.c", name) >= sizeof (outfile)) { X fprintf (stderr, "%s: save_firmware -- firmware name is too long\n", X MyName); X return -1; X } X X if (! (ofp = fopen (outfile, "w")) ) { X fprintf (stderr, "%s: save_firmware -- can't open output file <%s>\n", X MyName, outfile); X perror (MyName); X return -1; X } X X fprintf (ofp, "#include \n" X "\n" X "const u_int8_t %s[] __attribute__ ((aligned(4))) = {", X name); X X for (i = 0; i < (256 * 1024); i++) { X if (i) X fputc (',', ofp); X if ((i % 8) == 0) X fputs ("\n\t", ofp); X else X fputc (' ', ofp); X fprintf (ofp, "0x%.2x", buf[i]); X } X X fprintf (ofp, "\n};\n"); X X if (ferror (ofp)) { X fclose (ofp); X return -1; X } X X fclose (ofp); X return 0; X } X X Xint Xmain (int argc, char **argv) X { X const char *infile; X const u_int8_t *end; X const u_int8_t *ptr; X const u_int8_t *start; X int decoder_fw_saved; X int encoder_fw_saved; X int fd; X struct stat statbuf; X X if (argc != 2) { X fprintf (stderr, "Usage: %s \n", MyName); X exit (1); X } X X infile = argv[1]; X X /* X * Open the file. X */ X X if ((fd = open (infile, O_RDONLY)) < 0) { X fprintf (stderr, "%s: can't open %s for reading\n", MyName, infile); X perror (MyName); X exit (1); X } X X /* X * Determine how big it is. X */ X X if (fstat (fd, &statbuf) < 0) { X fprintf (stderr, "%s: can't fstat %s\n", MyName, infile); X perror (MyName); X close (fd); X exit (1); X } X X /* X * Map it into memory. X */ X X if ( !(start = (u_int8_t *)mmap (NULL, (size_t)statbuf.st_size, X PROT_READ, MAP_SHARED, fd, (off_t)0)) ) { X fprintf (stderr, "%s: can't mmap %s\n", MyName, infile); X perror (MyName); X close (fd); X exit (1); X } X X end = start + statbuf.st_size; X X close (fd); X X decoder_fw_saved = 0; X encoder_fw_saved = 0; X X for (ptr = start; ptr != end; ptr++) { X if ((end - ptr) >= sizeof (decoder_magic) X && memcmp (ptr, decoder_magic, sizeof (decoder_magic)) == 0) X if (! decoder_fw_saved) { X if (save_firmware ("cxm_dec_fw", ptr, end - ptr) < 0) { X fprintf (stderr, "%s: save_firmware failed\n", MyName); X exit (1); X } X decoder_fw_saved = 1; X } X else { X fprintf (stderr, "%s: multiple decoder images present\n", MyName); X exit (1); X } X X if ((end - ptr) >= sizeof (encoder_magic) X && memcmp (ptr, encoder_magic, sizeof (encoder_magic)) == 0) X if (! encoder_fw_saved) { X if (save_firmware ("cxm_enc_fw", ptr, end - ptr) < 0) { X fprintf (stderr, "%s: save_firmware failed\n", MyName); X exit (1); X } X encoder_fw_saved = 1; X } X else { X fprintf (stderr, "%s: multiple encoder images present\n", MyName); X exit (1); X } X } X X munmap ((caddr_t)start, (size_t)statbuf.st_size); X X if (! decoder_fw_saved) X fprintf (stderr, "%s: decoder image not present\n", MyName); X X if (! encoder_fw_saved) X fprintf (stderr, "%s: encoder image not present\n", MyName); X X if (! decoder_fw_saved || ! encoder_fw_saved) X exit (1); X X exit (0); X } END-of-dev/cxm/cxm_extract_fw.c echo c - modules/cxm mkdir -p modules/cxm > /dev/null 2>&1 echo x - modules/cxm/Makefile sed 's/^X//' >modules/cxm/Makefile << 'END-of-modules/cxm/Makefile' XSUBDIR = XSUBDIR += cxm XSUBDIR += cxm_iic X X.include END-of-modules/cxm/Makefile echo c - modules/cxm/cxm mkdir -p modules/cxm/cxm > /dev/null 2>&1 echo x - modules/cxm/cxm/Makefile sed 's/^X//' >modules/cxm/cxm/Makefile << 'END-of-modules/cxm/cxm/Makefile' X.PATH: ${.CURDIR}/../../../dev/cxm XKMOD = cxm XSRCS = cxm.c cxm.h cxm_dec_fw.c cxm_enc_fw.c cxm_audio.c cxm_eeprom.c \ X cxm_ir.c cxm_tuner.c cxm_video.c opt_cxm.h \ X bus_if.h device_if.h iicbb_if.h pci_if.h vnode_if.h X X.include END-of-modules/cxm/cxm/Makefile echo c - modules/cxm/cxm_iic mkdir -p modules/cxm/cxm_iic > /dev/null 2>&1 echo x - modules/cxm/cxm_iic/Makefile sed 's/^X//' >modules/cxm/cxm_iic/Makefile << 'END-of-modules/cxm/cxm_iic/Makefile' X.PATH: ${.CURDIR}/../../../dev/cxm XKMOD = cxm_iic XSRCS = cxm_i2c.c cxm.h \ X opt_cxm.h bus_if.h device_if.h iicbb_if.h pci_if.h X X.include END-of-modules/cxm/cxm_iic/Makefile exit ------------------------------------------------------------------------- | Feith Systems | Voice: 1-215-646-8000 | Email: john@feith.com | | John Wehle | Fax: 1-215-540-5495 | | -------------------------------------------------------------------------