Index: linux-2.6.11/Documentation/scsi-changer.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/Documentation/scsi-changer.txt 2005-03-07 18:13:01.000000000 +0100 @@ -0,0 +1,180 @@ + +README for the SCSI media changer driver +======================================== + +This is a driver for SCSI Medium Changer devices, which are listed +with "Type: Medium Changer" in /proc/scsi/scsi. + +This is for *real* Jukeboxes. It is *not* supported to work with +common small CD-ROM changers, neither one-lun-per-slot SCSI changers +nor IDE drives. + +Userland tools available from here: + http://linux.bytesex.org/misc/changer.html + + +General Information +------------------- + +First some words about how changers work: A changer has 2 (possibly +more) SCSI ID's. One for the changer device which controls the robot, +and one for the device which actually reads and writes the data. The +later may be anything, a MOD, a CD-ROM, a tape or whatever. For the +changer device this is a "don't care", he *only* shuffles around the +media, nothing else. + + +The SCSI changer model is complex, compared to - for example - IDE-CD +changers. But it allows to handle nearly all possible cases. It knows +4 different types of changer elements: + + media transport - this one shuffles around the media, i.e. the + transport arm. Also known as "picker". + storage - a slot which can hold a media. + import/export - the same as above, but is accessable from outside, + i.e. there the operator (you !) can use this to + fill in and remove media from the changer. + Sometimes named "mailslot". + data transfer - this is the device which reads/writes, i.e. the + CD-ROM / Tape / whatever drive. + +None of these is limited to one: A huge Jukebox could have slots for +123 CD-ROM's, 5 CD-ROM readers (and therefore 6 SCSI ID's: the changer +and each CD-ROM) and 2 transport arms. No problem to handle. + + +How it is implemented +--------------------- + +I implemented the driver as character device driver with a NetBSD-like +ioctl interface. Just grabbed NetBSD's header file and one of the +other linux SCSI device drivers as starting point. The interface +should be source code compatible with NetBSD. So if there is any +software (anybody knows ???) which supports a BSDish changer driver, +it should work with this driver too. + +Over time a few more ioctls where added, volume tag support for example +wasn't covered by the NetBSD ioctl API. + + +Current State +------------- + +Support for more than one transport arm is not implemented yet (and +nobody asked for it so far...). + +I test and use the driver myself with a 35 slot cdrom jukebox from +Grundig. I got some reports telling it works ok with tape autoloaders +(Exabyte, HP and DEC). Some People use this driver with amanda. It +works fine with small (11 slots) and a huge (4 MOs, 88 slots) +magneto-optical Jukebox. Probably with lots of other changers too, most +(but not all :-) people mail me only if it does *not* work... + +I don't have any device lists, neither black-list nor white-list. Thus +it is quite useless to ask me whenever a specific device is supported or +not. In theory every changer device which supports the SCSI-2 media +changer command set should work out-of-the-box with this driver. If it +doesn't, it is a bug. Either within the driver or within the firmware +of the changer device. + + +Using it +-------- + +This is a character device with major number is 86, so use +"mknod /dev/sch0 c 86 0" to create the special file for the driver. + +If the module finds the changer, it prints some messages about the +device [ try "dmesg" if you don't see anything ] and should show up in +/proc/devices. If not.... some changers use ID ? / LUN 0 for the +device and ID ? / LUN 1 for the robot mechanism. But Linux does *not* +look for LUN's other than 0 as default, becauce there are to many +broken devices. So you can try: + + 1) echo "scsi add-single-device 0 0 ID 1" > /proc/scsi/scsi + (replace ID with the SCSI-ID of the device) + 2) boot the kernel with "max_scsi_luns=1" on the command line + (append="max_scsi_luns=1" in lilo.conf should do the trick) + + +Trouble? +-------- + +If you insmod the driver with "insmod debug=1", it will be verbose and +prints a lot of stuff to the syslog. Compiling the kernel with +CONFIG_SCSI_CONSTANTS=y improves the quality of the error messages alot +because the kernel will translate the error codes into human-readable +strings then. + +You can display these messages with the dmesg command (or check the +logfiles). If you email me some question becauce of a problem with the +driver, please include these messages. + + +Insmod options +-------------- + +debug=0/1 + Enable debug messages (see above, default: 0). + +verbose=0/1 + Be verbose (default: 1). + +init=0/1 + Send INITIALIZE ELEMENT STATUS command to the changer + at insmod time (default: 1). + +timeout_init= + timeout for the INITIALIZE ELEMENT STATUS command + (default: 3600). + +timeout_move= + timeout for all other commands (default: 120). + +dt_id=,,... +dt_lun=,,... + These two allow to specify the SCSI ID and LUN for the data + transfer elements. You likely don't need this as the jukebox + should provide this information. But some devices don't ... + +vendor_firsts= +vendor_counts= +vendor_labels= + These insmod options can be used to tell the driver that there + are some vendor-specific element types. Grundig for example + does this. Some jukeboxes have a printer to label fresh burned + CDs, which is addressed as element 0xc000 (type 5). To tell the + driver about this vendor-specific element, use this: + $ insmod ch \ + vendor_firsts=0xc000 \ + vendor_counts=1 \ + vendor_labels=printer + All three insmod options accept up to four comma-separated + values, this way you can configure the element types 5-8. + You likely need the SCSI specs for the device in question to + find the correct values as they are not covered by the SCSI-2 + standard. + + +Credits +------- + +I wrote this driver using the famous mailing-patches-around-the-world +method. With (more or less) help from: + + Daniel Moehwald + Dane Jasper + R. Scott Bailey + Jonathan Corbet + +Special thanks go to + Martin Kuehne +for a old, second-hand (but full functional) cdrom jukebox which I use +to develop/test driver and tools now. + +Have fun, + + Gerd + +-- +Gerd Knorr Index: linux-2.6.11/Documentation/video4linux/CARDLIST.saa7134 =================================================================== --- linux-2.6.11.orig/Documentation/video4linux/CARDLIST.saa7134 2005-03-07 10:12:23.000000000 +0100 +++ linux-2.6.11/Documentation/video4linux/CARDLIST.saa7134 2005-03-08 10:33:01.000000000 +0100 @@ -6,29 +6,30 @@ 5 -> SKNet Monster TV [1131:4e85] 6 -> Tevion MD 9717 7 -> KNC One TV-Station RDS / Typhoon TV Tuner RDS [1131:fe01,1894:fe01] - 8 -> KNC One TV-Station DVR [1894:a006] - 9 -> Terratec Cinergy 400 TV [153B:1142] - 10 -> Medion 5044 - 11 -> Kworld/KuroutoShikou SAA7130-TVPCI - 12 -> Terratec Cinergy 600 TV [153B:1143] - 13 -> Medion 7134 [16be:0003] - 14 -> Typhoon TV+Radio 90031 - 15 -> ELSA EX-VISION 300TV [1048:226b] - 16 -> ELSA EX-VISION 500TV [1048:226b] - 17 -> ASUS TV-FM 7134 [1043:4842,1043:4830,1043:4840] - 18 -> AOPEN VA1000 POWER [1131:7133] - 19 -> 10MOONS PCI TV CAPTURE CARD [1131:2001] - 20 -> BMK MPEX No Tuner - 21 -> Compro VideoMate TV [185b:c100] - 22 -> Matrox CronosPlus [102B:48d0] - 23 -> Medion 2819/ AverMedia M156 [1461:a70b,1461:2115] - 24 -> BMK MPEX Tuner + 8 -> Terratec Cinergy 400 TV [153B:1142] + 9 -> Medion 5044 + 10 -> Kworld/KuroutoShikou SAA7130-TVPCI + 11 -> Terratec Cinergy 600 TV [153B:1143] + 12 -> Medion 7134 [16be:0003] + 13 -> Typhoon TV+Radio 90031 + 14 -> ELSA EX-VISION 300TV [1048:226b] + 15 -> ELSA EX-VISION 500TV [1048:226b] + 16 -> ASUS TV-FM 7134 [1043:4842,1043:4830,1043:4840] + 17 -> AOPEN VA1000 POWER [1131:7133] + 18 -> BMK MPEX No Tuner + 19 -> Compro VideoMate TV [185b:c100] + 20 -> Matrox CronosPlus [102B:48d0] + 21 -> 10MOONS PCI TV CAPTURE CARD [1131:2001] + 22 -> Medion 2819/ AverMedia M156 [1461:a70b,1461:2115] + 23 -> BMK MPEX Tuner + 24 -> KNC One TV-Station DVR [1894:a006] 25 -> ASUS TV-FM 7133 [1043:4843] 26 -> Pinnacle PCTV Stereo (saa7134) [11bd:002b] - 27 -> Manli MuchTV M-TV002 - 28 -> Manli MuchTV M-TV001 + 27 -> Manli MuchTV M-TV002 + 28 -> Manli MuchTV M-TV001 29 -> Nagase Sangyo TransGear 3000TV [1461:050c] 30 -> Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) [1019:4cb4] 31 -> Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM) [1019:4cb5] - 32 -> AVACS SmartTV + 32 -> AVACS SmartTV 33 -> AVerMedia DVD EZMaker [1461:10ff] + 34 -> LifeView FlyTV Platinum33 mini [5168:0212] Index: linux-2.6.11/Documentation/video4linux/README.cx88 =================================================================== --- linux-2.6.11.orig/Documentation/video4linux/README.cx88 2005-03-07 10:13:25.000000000 +0100 +++ linux-2.6.11/Documentation/video4linux/README.cx88 2005-03-08 10:33:01.000000000 +0100 @@ -11,9 +11,6 @@ current status video - Basically works. - Some minor image quality glitches. - - Red and blue are swapped sometimes for not-yet known - reasons (seems to depend on the image size, try to resize - your tv app window as workaround ...). - For now only capture, overlay support isn't completed yet. audio Index: linux-2.6.11/Documentation/video4linux/bttv/Cards =================================================================== --- linux-2.6.11.orig/Documentation/video4linux/bttv/Cards 2005-03-07 10:13:04.000000000 +0100 +++ linux-2.6.11/Documentation/video4linux/bttv/Cards 2005-03-08 10:33:01.000000000 +0100 @@ -1,9 +1,9 @@ Gunther Mayer's bttv card gallery (graphical version of this text file :-) -is available at: http://mayerg.gmxhome.de/bttv/bttv-gallery.html +is available at: http://www.bttv-gallery.de/ -Suppported cards: +Supported cards: Bt848/Bt848a/Bt849/Bt878/Bt879 cards ------------------------------------ @@ -166,6 +166,9 @@ Lifeview Flyvideo Series: or Flyvideo 3000 (SAA7134) w/Stereo TV These exist in variations w/FM and w/Remote sometimes denoted by suffixes "FM" and "R". + 3) You have a laptop (miniPCI card): + Product = FlyTV Platinum Mini + Model/Chip = LR212/saa7135 Lifeview.com.tw states (Feb. 2002): "The FlyVideo2000 and FlyVideo2000s product name have renamed to FlyVideo98." Index: linux-2.6.11/Documentation/video4linux/bttv/README =================================================================== --- linux-2.6.11.orig/Documentation/video4linux/bttv/README 2005-03-07 10:12:37.000000000 +0100 +++ linux-2.6.11/Documentation/video4linux/bttv/README 2005-03-08 10:33:01.000000000 +0100 @@ -22,7 +22,7 @@ very likely specified the wrong (or no) cards is in CARDLIST.bttv If bttv takes very long to load (happens sometimes with the cheap -cards which have no tuner), try adding this to your modprobe.conf: +cards which have no tuner), try adding this to your modules.conf: options i2c-algo-bit bit_test=1 For the WinTV/PVR you need one firmware file from the driver CD: Index: linux-2.6.11/MAINTAINERS =================================================================== --- linux-2.6.11.orig/MAINTAINERS 2005-03-07 10:14:21.000000000 +0100 +++ linux-2.6.11/MAINTAINERS 2005-03-08 10:33:27.000000000 +0100 @@ -501,7 +501,7 @@ P: Gerd Knorr M: kraxel@bytesex.org L: video4linux-list@redhat.com W: http://bytesex.org/bttv/ -S: Maintained +S: Orphan BUSLOGIC SCSI DRIVER P: Leonard N. Zubkoff @@ -2534,7 +2534,8 @@ S: Maintained VIDEO FOR LINUX P: Gerd Knorr M: kraxel@bytesex.org -S: Maintained +L: video4linux-list@redhat.com +S: Orphan W1 DALLAS'S 1-WIRE BUS P: Evgeniy Polyakov Index: linux-2.6.11/arch/x86_64/ia32/ia32_ioctl.c =================================================================== --- linux-2.6.11.orig/arch/x86_64/ia32/ia32_ioctl.c 2005-03-07 10:14:05.000000000 +0100 +++ linux-2.6.11/arch/x86_64/ia32/ia32_ioctl.c 2005-03-08 10:33:27.000000000 +0100 @@ -18,25 +18,6 @@ #define CODE #include "compat_ioctl.c" -#ifndef TIOCGDEV -#define TIOCGDEV _IOR('T',0x32, unsigned int) -#endif -static int tiocgdev(unsigned fd, unsigned cmd, unsigned int __user *ptr) -{ - - struct file *file = fget(fd); - struct tty_struct *real_tty; - - if (!file) - return -EBADF; - if (file->f_op->ioctl != tty_ioctl) - return -EINVAL; - real_tty = (struct tty_struct *)file->private_data; - if (!real_tty) - return -EINVAL; - return put_user(new_encode_dev(tty_devnum(real_tty)), ptr); -} - #define RTC_IRQP_READ32 _IOR('p', 0x0b, unsigned int) /* Read IRQ rate */ #define RTC_IRQP_SET32 _IOW('p', 0x0c, unsigned int) /* Set IRQ rate */ #define RTC_EPOCH_READ32 _IOR('p', 0x0d, unsigned) /* Read epoch */ @@ -176,7 +157,6 @@ COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - COMPATIBLE_IOCTL(FIOQSIZE) /* And these ioctls need translation */ -HANDLE_IOCTL(TIOCGDEV, tiocgdev) /* realtime device */ HANDLE_IOCTL(RTC_IRQP_READ, rtc32_ioctl) HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl) Index: linux-2.6.11/drivers/char/tty_io.c =================================================================== --- linux-2.6.11.orig/drivers/char/tty_io.c 2005-03-07 10:14:19.000000000 +0100 +++ linux-2.6.11/drivers/char/tty_io.c 2005-03-08 10:33:27.000000000 +0100 @@ -2369,6 +2369,21 @@ int tty_ioctl(struct inode * inode, stru case TIOCMBIC: case TIOCMBIS: return tty_tiocmset(tty, file, cmd, p); + /* + * Without the real device to which /dev/console is connected, + * blogd can not work. + * blogd spawns a pty/tty pair, + * set /dev/console to the tty of that pair (ioctl TIOCCONS), + * then reads in all input from the current /dev/console, + * buffer or write the readed data to /var/log/boot.msg + * _and_ to the original real device. + */ + case TIOCGDEV: + { + unsigned int ret = new_encode_dev(tty_devnum(real_tty)); + return put_user(ret, (unsigned int __user *)p); + } + } if (tty->driver->ioctl) { retval = (tty->driver->ioctl)(tty, file, cmd, arg); Index: linux-2.6.11/drivers/media/common/ir-common.c =================================================================== --- linux-2.6.11.orig/drivers/media/common/ir-common.c 2005-03-07 10:14:43.000000000 +0100 +++ linux-2.6.11/drivers/media/common/ir-common.c 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: ir-common.c,v 1.6 2004/12/10 12:33:39 kraxel Exp $ + * $Id: ir-common.c,v 1.8 2005/02/22 12:28:40 kraxel Exp $ * * some common structs and functions to handle infrared remotes via * input layer ... @@ -23,7 +23,6 @@ #include #include - #include /* -------------------------------------------------------------------------- */ @@ -45,6 +44,7 @@ module_param(debug, int, 0644); /* generic RC5 keytable */ /* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */ +/* used by old (black) Hauppauge remotes */ IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = { [ 0x00 ] = KEY_KP0, // 0 [ 0x01 ] = KEY_KP1, // 1 @@ -117,12 +117,102 @@ IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB }; EXPORT_SYMBOL_GPL(ir_codes_rc5_tv); +/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */ +IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { + [ 5 ] = KEY_KP1, + [ 6 ] = KEY_KP2, + [ 7 ] = KEY_KP3, + [ 9 ] = KEY_KP4, + [ 10 ] = KEY_KP5, + [ 11 ] = KEY_KP6, + [ 13 ] = KEY_KP7, + [ 14 ] = KEY_KP8, + [ 15 ] = KEY_KP9, + [ 18 ] = KEY_KP0, + + [ 0 ] = KEY_POWER, +// [ 27 ] = MTS button + [ 2 ] = KEY_TUNER, // TV/FM + [ 30 ] = KEY_VIDEO, +// [ 22 ] = display button + [ 4 ] = KEY_VOLUMEUP, + [ 8 ] = KEY_VOLUMEDOWN, + [ 12 ] = KEY_CHANNELUP, + [ 16 ] = KEY_CHANNELDOWN, + [ 3 ] = KEY_ZOOM, // fullscreen + [ 31 ] = KEY_SUBTITLE, // closed caption/teletext + [ 32 ] = KEY_SLEEP, +// [ 41 ] = boss key + [ 20 ] = KEY_MUTE, + [ 43 ] = KEY_RED, + [ 44 ] = KEY_GREEN, + [ 45 ] = KEY_YELLOW, + [ 46 ] = KEY_BLUE, + [ 24 ] = KEY_KPPLUS, //fine tune + + [ 25 ] = KEY_KPMINUS, //fine tune - +// [ 42 ] = picture in picture + [ 33 ] = KEY_KPDOT, + [ 19 ] = KEY_KPENTER, +// [ 17 ] = recall + [ 34 ] = KEY_BACK, + [ 35 ] = KEY_PLAYPAUSE, + [ 36 ] = KEY_NEXT, +// [ 37 ] = time shifting + [ 38 ] = KEY_STOP, + [ 39 ] = KEY_RECORD +// [ 40 ] = snapshot +}; +EXPORT_SYMBOL_GPL(ir_codes_winfast); + /* empty keytable, can be used as placeholder for not-yet created keytables */ IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = { [ 42 ] = KEY_COFFEE, }; EXPORT_SYMBOL_GPL(ir_codes_empty); +/* Hauppauge: the newer, gray remotes (seems there are multiple + * slightly different versions), shipped with cx88+ivtv cards. + * almost rc5 coding, but some non-standard keys */ +IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = { + [ 0x00 ] = KEY_KP0, // 0 + [ 0x01 ] = KEY_KP1, // 1 + [ 0x02 ] = KEY_KP2, // 2 + [ 0x03 ] = KEY_KP3, // 3 + [ 0x04 ] = KEY_KP4, // 4 + [ 0x05 ] = KEY_KP5, // 5 + [ 0x06 ] = KEY_KP6, // 6 + [ 0x07 ] = KEY_KP7, // 7 + [ 0x08 ] = KEY_KP8, // 8 + [ 0x09 ] = KEY_KP9, // 9 + [ 0x0b ] = KEY_RED, // red button + [ 0x0c ] = KEY_OPTION, // black key without text + [ 0x0d ] = KEY_MENU, // menu + [ 0x0f ] = KEY_MUTE, // mute + [ 0x10 ] = KEY_VOLUMEUP, // volume + + [ 0x11 ] = KEY_VOLUMEDOWN, // volume - + [ 0x1e ] = KEY_NEXT, // skip >| + [ 0x1f ] = KEY_EXIT, // back/exit + [ 0x20 ] = KEY_CHANNELUP, // channel / program + + [ 0x21 ] = KEY_CHANNELDOWN, // channel / program - + [ 0x22 ] = KEY_CHANNEL, // source (old black remote) + [ 0x24 ] = KEY_PREVIOUS, // replay |< + [ 0x25 ] = KEY_ENTER, // OK + [ 0x26 ] = KEY_SLEEP, // minimize (old black remote) + [ 0x29 ] = KEY_BLUE, // blue key + [ 0x2e ] = KEY_GREEN, // green button + [ 0x30 ] = KEY_PAUSE, // pause + [ 0x32 ] = KEY_REWIND, // backward << + [ 0x34 ] = KEY_FASTFORWARD, // forward >> + [ 0x35 ] = KEY_PLAY, // play + [ 0x36 ] = KEY_STOP, // stop + [ 0x37 ] = KEY_RECORD, // recording + [ 0x38 ] = KEY_YELLOW, // yellow key + [ 0x3b ] = KEY_SELECT, // top right button + [ 0x3c ] = KEY_ZOOM, // full + [ 0x3d ] = KEY_POWER, // system power (green button) +}; +EXPORT_SYMBOL(ir_codes_hauppauge_new); + /* -------------------------------------------------------------------------- */ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) @@ -192,6 +282,8 @@ void ir_input_keydown(struct input_dev * #endif } +/* -------------------------------------------------------------------------- */ + u32 ir_extract_bits(u32 data, u32 mask) { int mbit, vbit; @@ -209,10 +301,78 @@ u32 ir_extract_bits(u32 data, u32 mask) return value; } +static int inline getbit(u32 *samples, int bit) +{ + return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0; +} + +/* sump raw samples for visual debugging ;) */ +int ir_dump_samples(u32 *samples, int count) +{ + int i, bit, start; + + printk(KERN_DEBUG "ir samples: "); + start = 0; + for (i = 0; i < count * 32; i++) { + bit = getbit(samples,i); + if (bit) + start = 1; + if (0 == start) + continue; + printk("%s", bit ? "#" : "_"); + } + printk("\n"); + return 0; +} + +/* decode raw samples, biphase coding, used by rc5 for example */ +int ir_decode_biphase(u32 *samples, int count, int low, int high) +{ + int i,last,bit,len,flips; + u32 value; + + /* find start bit (1) */ + for (i = 0; i < 32; i++) { + bit = getbit(samples,i); + if (bit) + break; + } + + /* go decoding */ + len = 0; + flips = 0; + value = 1; + for (; i < count * 32; i++) { + if (len > high) + break; + if (flips > 1) + break; + last = bit; + bit = getbit(samples,i); + if (last == bit) { + len++; + continue; + } + if (len < low) { + len++; + flips++; + continue; + } + value <<= 1; + value |= bit; + flips = 0; + len = 1; + } + return value; +} + EXPORT_SYMBOL_GPL(ir_input_init); EXPORT_SYMBOL_GPL(ir_input_nokey); EXPORT_SYMBOL_GPL(ir_input_keydown); + EXPORT_SYMBOL_GPL(ir_extract_bits); +EXPORT_SYMBOL_GPL(ir_dump_samples); +EXPORT_SYMBOL_GPL(ir_decode_biphase); /* * Local variables: Index: linux-2.6.11/drivers/media/dvb/dvb-core/dvb_frontend.c =================================================================== --- linux-2.6.11.orig/drivers/media/dvb/dvb-core/dvb_frontend.c 2005-03-07 10:13:08.000000000 +0100 +++ linux-2.6.11/drivers/media/dvb/dvb-core/dvb_frontend.c 2005-03-08 10:33:27.000000000 +0100 @@ -919,3 +919,24 @@ int dvb_unregister_frontend(struct dvb_f return 0; } EXPORT_SYMBOL(dvb_unregister_frontend); + +void dvb_suspend_frontend(struct dvb_frontend* fe) +{ + if (fe->ops->sleep) + fe->ops->sleep(fe); +} +EXPORT_SYMBOL(dvb_suspend_frontend); + +void dvb_resume_frontend(struct dvb_frontend* fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + if (fe->ops->init) + fe->ops->init(fe); + fepriv->state = FESTATE_RETUNE; + dvb_frontend_wakeup(fe); + dvb_frontend_add_event (fe, 0); + fepriv->status = 0; +} +EXPORT_SYMBOL(dvb_resume_frontend); + Index: linux-2.6.11/drivers/media/dvb/dvb-core/dvb_frontend.h =================================================================== --- linux-2.6.11.orig/drivers/media/dvb/dvb-core/dvb_frontend.h 2005-03-07 10:15:26.000000000 +0100 +++ linux-2.6.11/drivers/media/dvb/dvb-core/dvb_frontend.h 2005-03-08 10:33:27.000000000 +0100 @@ -122,5 +122,7 @@ extern int dvb_register_frontend(struct struct dvb_frontend* fe); extern int dvb_unregister_frontend(struct dvb_frontend* fe); +extern void dvb_suspend_frontend(struct dvb_frontend* fe); +extern void dvb_resume_frontend(struct dvb_frontend* fe); #endif Index: linux-2.6.11/drivers/media/dvb/frontends/Kconfig =================================================================== --- linux-2.6.11.orig/drivers/media/dvb/frontends/Kconfig 2005-03-07 10:12:55.000000000 +0100 +++ linux-2.6.11/drivers/media/dvb/frontends/Kconfig 2005-03-08 10:33:27.000000000 +0100 @@ -157,4 +157,8 @@ config DVB_NXT2002 help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. +config DVB_OR51132 + tristate "OR51132 based (pcHDTV)" + depends on DVB_CORE + endmenu Index: linux-2.6.11/drivers/media/dvb/frontends/Makefile =================================================================== --- linux-2.6.11.orig/drivers/media/dvb/frontends/Makefile 2005-03-07 10:12:27.000000000 +0100 +++ linux-2.6.11/drivers/media/dvb/frontends/Makefile 2005-03-08 10:33:27.000000000 +0100 @@ -4,6 +4,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ +obj-$(CONFIG_DVB_CORE) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o obj-$(CONFIG_DVB_SP8870) += sp8870.o obj-$(CONFIG_DVB_CX22700) += cx22700.o @@ -25,4 +26,4 @@ obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o obj-$(CONFIG_DVB_TDA10021) += tda10021.o obj-$(CONFIG_DVB_STV0297) += stv0297.o obj-$(CONFIG_DVB_NXT2002) += nxt2002.o - +obj-$(CONFIG_DVB_OR51132) += or51132.o Index: linux-2.6.11/drivers/media/dvb/frontends/cx22702.c =================================================================== --- linux-2.6.11.orig/drivers/media/dvb/frontends/cx22702.c 2005-03-07 10:14:54.000000000 +0100 +++ linux-2.6.11/drivers/media/dvb/frontends/cx22702.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,8 +1,8 @@ /* - Conexant 22702 DVB OFDM demodulator driver + Conexant 22702 DVB OFDM frontend driver based on: - Alps TDMB7 DVB OFDM demodulator driver + Alps TDMB7 DVB OFDM frontend driver Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler @@ -31,30 +31,35 @@ #include #include #include + #include "dvb_frontend.h" +#include "dvb-pll.h" #include "cx22702.h" +#define FRONTEND_NAME "dvbfe_cx22702" -struct cx22702_state { - - struct i2c_adapter* i2c; - - struct dvb_frontend_ops ops; +#define dprintk if (debug) printk - /* configuration settings */ - const struct cx22702_config* config; +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); - struct dvb_frontend frontend; +/* ------------------------------------------------------------------ */ - /* previous uncorrected block counter */ +struct cx22702_state { + const struct cx22702_config *config; + struct i2c_client demod; + struct i2c_client pll; + struct dvb_frontend fe; + struct dvb_frontend_ops ops; u8 prevUCBlocks; }; -static int debug = 0; -#define dprintk if (debug) printk +static struct i2c_client demod_template; +static struct i2c_client pll_template; /* Register values to initialise the demod */ -static u8 init_tab [] = { +static u8 init_tab[] = { 0x00, 0x00, /* Stop aquisition */ 0x0B, 0x06, 0x09, 0x01, @@ -83,73 +88,105 @@ static u8 init_tab [] = { 0xfd, 0x00, }; -static int cx22702_writereg (struct cx22702_state* state, u8 reg, u8 data) +/* ------------------------------------------------------------------ */ + +static int writereg(struct i2c_client *c, u8 reg, u8 data) { + u8 buf[] = { reg, data }; int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) + ret = i2c_master_send(c, buf, 2); + if (ret != 2) { printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", - __FUNCTION__, reg, data, ret); + __FUNCTION__, reg, data, ret); + return -1; + } + return 0; +} - return (ret != 1) ? -1 : 0; +static int readreg(struct i2c_client *c, u8 reg) +{ + u8 wr [] = { reg }; + u8 rd [] = { 0 }; + struct i2c_msg msg [] = { + { .addr = c->addr, .flags = 0, .buf = wr, .len = 1 }, + { .addr = c->addr, .flags = I2C_M_RD, .buf = rd, .len = 1 }, + }; + int ret; + + ret = i2c_transfer(c->adapter, msg, 2); + if (ret != 2) { + printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + return -1; + } + return rd[0]; } -static u8 cx22702_readreg (struct cx22702_state* state, u8 reg) +/* ------------------------------------------------------------------ */ + +#define PLL_ENABLE(cx) writereg(&cx->demod, 0x0D, readreg(&cx->demod, 0x0D) & 0xfe) +#define PLL_DISABLE(cx) writereg(&cx->demod, 0x0D, readreg(&cx->demod, 0x0D) | 0x01) + +static int pll_write4(struct i2c_client *c, u8 *data) { int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { - { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + ret = i2c_master_send(c, data, 4); + if (ret != 4) { + printk("%s: i/o error (addr == 0x%02x, ret == %i)\n", + __FUNCTION__, c->addr, ret); + return -EIO; + } + return 0; +} - ret = i2c_transfer(state->i2c, msg, 2); +/* ------------------------------------------------------------------ */ - if (ret != 2) - printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); +static int cx22702_reset(struct cx22702_state *state) +{ + int i; - return b1[0]; + dprintk("%s\n",__FUNCTION__); + writereg(&state->demod, 0x00, 0x02); + msleep(10); + + for (i=0; idemod, init_tab[i], init_tab[i+1]); + return 0; } -static int cx22702_set_inversion (struct cx22702_state *state, int inversion) +static int cx22702_set_inversion(struct cx22702_state *state, int inversion) { u8 val; switch (inversion) { + case INVERSION_AUTO: + return -EOPNOTSUPP; - case INVERSION_AUTO: - return -EOPNOTSUPP; - - case INVERSION_ON: - val = cx22702_readreg (state, 0x0C); - return cx22702_writereg (state, 0x0C, val | 0x01); - - case INVERSION_OFF: - val = cx22702_readreg (state, 0x0C); - return cx22702_writereg (state, 0x0C, val & 0xfe); + case INVERSION_ON: + val = readreg(&state->demod, 0x0C); + return writereg(&state->demod, 0x0C, val | 0x01); - default: - return -EINVAL; + case INVERSION_OFF: + val = readreg(&state->demod, 0x0C); + return writereg(&state->demod, 0x0C, val & 0xfe); + default: + return -EINVAL; } - } /* Retrieve the demod settings */ -static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p) +static int cx22702_get_tps(struct cx22702_state *state, + struct dvb_ofdm_parameters *p) { u8 val; /* Make sure the TPS regs are valid */ - if (!(cx22702_readreg(state, 0x0A) & 0x20)) + if (!(readreg(&state->demod, 0x0A) & 0x20)) return -EAGAIN; - val = cx22702_readreg (state, 0x01); + val = readreg(&state->demod, 0x01); switch( (val&0x18)>>3) { case 0: p->constellation = QPSK; break; case 1: p->constellation = QAM_16; break; @@ -162,8 +199,7 @@ static int cx22702_get_tps (struct cx227 case 3: p->hierarchy_information = HIERARCHY_4; break; } - - val = cx22702_readreg (state, 0x02); + val = readreg(&state->demod, 0x02); switch( (val&0x38)>>3 ) { case 0: p->code_rate_HP = FEC_1_2; break; case 1: p->code_rate_HP = FEC_2_3; break; @@ -179,14 +215,13 @@ static int cx22702_get_tps (struct cx227 case 4: p->code_rate_LP = FEC_7_8; break; } - - val = cx22702_readreg (state, 0x03); + val = readreg(&state->demod, 0x03); switch( (val&0x0c)>>2 ) { case 0: p->guard_interval = GUARD_INTERVAL_1_32; break; case 1: p->guard_interval = GUARD_INTERVAL_1_16; break; case 2: p->guard_interval = GUARD_INTERVAL_1_8; break; case 3: p->guard_interval = GUARD_INTERVAL_1_4; break; -} + } switch( val&0x03 ) { case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break; case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break; @@ -195,42 +230,36 @@ static int cx22702_get_tps (struct cx227 return 0; } - - - - - - - - - - - - /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx22702_set_tps(struct cx22702_state *state, + struct dvb_frontend_parameters *p) { u8 val; - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + u8 pllbuf[4]; + + dprintk("%s\n",__FUNCTION__); /* set PLL */ - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); - state->config->pll_set(fe, p); - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); + dvb_pll_configure(state->config->pll_desc, pllbuf, + p->frequency, + p->u.ofdm.bandwidth); + PLL_ENABLE(state); + pll_write4(&state->pll,pllbuf); + PLL_DISABLE(state); /* set inversion */ - cx22702_set_inversion (state, p->inversion); + cx22702_set_inversion(state, p->inversion); /* set bandwidth */ switch(p->u.ofdm.bandwidth) { case BANDWIDTH_6_MHZ: - cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20 ); + writereg(&state->demod, 0x0C, (readreg(&state->demod, 0x0C) & 0xcf) | 0x20 ); break; case BANDWIDTH_7_MHZ: - cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10 ); + writereg(&state->demod, 0x0C, (readreg(&state->demod, 0x0C) & 0xcf) | 0x10 ); break; case BANDWIDTH_8_MHZ: - cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf ); + writereg(&state->demod, 0x0C, readreg(&state->demod, 0x0C) &0xcf ); break; default: dprintk ("%s: invalid bandwidth\n",__FUNCTION__); @@ -249,13 +278,13 @@ static int cx22702_set_tps (struct dvb_f (p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) { /* TPS Source - use hardware driven values */ - cx22702_writereg(state, 0x06, 0x10); - cx22702_writereg(state, 0x07, 0x9); - cx22702_writereg(state, 0x08, 0xC1); - cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc ); - cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); - cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */ - printk("%s: Autodetecting\n",__FUNCTION__); + writereg(&state->demod, 0x06, 0x10); + writereg(&state->demod, 0x07, 0x9); + writereg(&state->demod, 0x08, 0xC1); + writereg(&state->demod, 0x0B, readreg(&state->demod, 0x0B) & 0xfc ); + writereg(&state->demod, 0x0C, (readreg(&state->demod, 0x0C) & 0xBF) | 0x40 ); + writereg(&state->demod, 0x00, 0x01); /* Begin aquisition */ + dprintk("%s: Autodetecting\n",__FUNCTION__); return 0; } @@ -278,7 +307,7 @@ static int cx22702_set_tps (struct dvb_f dprintk ("%s: invalid hierarchy\n",__FUNCTION__); return -EINVAL; } - cx22702_writereg (state, 0x06, val); + writereg(&state->demod, 0x06, val); val=0; switch(p->u.ofdm.code_rate_HP) { @@ -303,7 +332,7 @@ static int cx22702_set_tps (struct dvb_f dprintk ("%s: invalid code_rate_LP\n",__FUNCTION__); return -EINVAL; } - cx22702_writereg (state, 0x07, val); + writereg(&state->demod, 0x07, val); val=0; switch(p->u.ofdm.guard_interval) { @@ -322,211 +351,300 @@ static int cx22702_set_tps (struct dvb_f dprintk ("%s: invalid transmission_mode\n",__FUNCTION__); return -EINVAL; } - cx22702_writereg(state, 0x08, val); - cx22702_writereg(state, 0x0B, (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02 ); - cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); + writereg(&state->demod, 0x08, val); + writereg(&state->demod, 0x0B, (readreg(&state->demod, 0x0B) & 0xfc) | 0x02 ); + writereg(&state->demod, 0x0C, (readreg(&state->demod, 0x0C) & 0xBF) | 0x40 ); /* Begin channel aquisition */ - cx22702_writereg(state, 0x00, 0x01); + writereg(&state->demod, 0x00, 0x01); return 0; } +/* ------------------------------------------------------------------ */ -/* Reset the demod hardware and reset all of the configuration registers - to a default state. */ -static int cx22702_init (struct dvb_frontend* fe) +static int cx22702_init(struct dvb_frontend* fe) { - int i; - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - - cx22702_writereg (state, 0x00, 0x02); - - msleep(10); - - for (i=0; iconfig->pll_init) { - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); - state->config->pll_init(fe); - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); - } + struct cx22702_state *state = fe->demodulator_priv; + cx22702_reset(state); return 0; } static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - u8 reg0A; - u8 reg23; - - *status = 0; - - reg0A = cx22702_readreg (state, 0x0A); - reg23 = cx22702_readreg (state, 0x23); - - dprintk ("%s: status demod=0x%02x agc=0x%02x\n" - ,__FUNCTION__,reg0A,reg23); - - if(reg0A & 0x10) { - *status |= FE_HAS_LOCK; - *status |= FE_HAS_VITERBI; - *status |= FE_HAS_SYNC; - } - - if(reg0A & 0x20) - *status |= FE_HAS_CARRIER; + struct cx22702_state *state = fe->demodulator_priv; + u8 reg0A = readreg(&state->demod, 0x0A); + u8 reg23 = readreg(&state->demod, 0x23); - if(reg23 < 0xf0) - *status |= FE_HAS_SIGNAL; + *status = 0; + if (reg0A & 0x10) + *status |= FE_HAS_LOCK| FE_HAS_VITERBI | FE_HAS_SYNC; + if (reg0A & 0x20) + *status |= FE_HAS_CARRIER; + if (reg23 < 0xf0) + *status |= FE_HAS_SIGNAL; + dprintk ("%s: status demod=0x%02x agc=0x%02x status=0x%x\n", + __FUNCTION__,reg0A,reg23,*status); return 0; - } +} static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber) - { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - - if(cx22702_readreg (state, 0xE4) & 0x02) { - /* Realtime statistics */ - *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 - | (cx22702_readreg (state, 0xDF)&0x7F); - } else { - /* Averagtine statistics */ - *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 - | cx22702_readreg (state, 0xDF); - } +{ + struct cx22702_state *state = fe->demodulator_priv; + *ber = (readreg(&state->demod, 0xDE) & 0x7F) << 7; + *ber |= readreg(&state->demod, 0xDF) & 0x7F; return 0; - } - -static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) - { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; +} - *signal_strength = cx22702_readreg (state, 0x23); +static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct cx22702_state *state = fe->demodulator_priv; + u8 signal; + signal = readreg(&state->demod, 0x23); + *strength = ((signal<<8) | signal); return 0; } static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - - u16 rs_ber=0; - if(cx22702_readreg (state, 0xE4) & 0x02) { - /* Realtime statistics */ - rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 - | (cx22702_readreg (state, 0xDF)& 0x7F); - } else { - /* Averagine statistics */ - rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 8 - | cx22702_readreg (state, 0xDF); - } - *snr = ~rs_ber; + u32 ber; + /* We don't have an register for this */ + /* We'll take the inverse of the BER register */ + cx22702_read_ber(fe, &ber); + *snr = ~ber; return 0; } static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - - u8 _ucblocks; + struct cx22702_state *state = fe->demodulator_priv; + u8 ucb; /* RS Uncorrectable Packet Count then reset */ - _ucblocks = cx22702_readreg (state, 0xE3); - if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks); - else *ucblocks = state->prevUCBlocks - _ucblocks; - state->prevUCBlocks = _ucblocks; - + ucb = readreg(&state->demod, 0xE3); + if (state->prevUCBlocks <= ucb) + *ucblocks = (ucb - state->prevUCBlocks); + else + *ucblocks = 256 + ucb - state->prevUCBlocks; + state->prevUCBlocks = ucb; return 0; } -static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx22702_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; + u8 reg0C = readreg(&state->demod, 0x0C); + params->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22702_get_tps(state, ¶ms->u.ofdm); +} - u8 reg0C = cx22702_readreg (state, 0x0C); +static int cx22702_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params) +{ + struct cx22702_state *state = fe->demodulator_priv; + int ret; - p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22702_get_tps (state, &p->u.ofdm); + ret=cx22702_set_tps(state, params); + if (debug && ret < 0) + printk("%s: set_tps failed ret=%d\n",__FUNCTION__,ret); + return ret; } static void cx22702_release(struct dvb_frontend* fe) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - kfree(state); - } + struct cx22702_state *state = fe->demodulator_priv; -static struct dvb_frontend_ops cx22702_ops; + i2c_detach_client(&state->demod); + i2c_detach_client(&state->pll); + kfree(state); +} -struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, - struct i2c_adapter* i2c) +static int cx22702_sleep(struct dvb_frontend* fe) { - struct cx22702_state* state = NULL; - - /* allocate memory for the internal state */ - state = (struct cx22702_state*) kmalloc(sizeof(struct cx22702_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops)); - state->prevUCBlocks = 0; - - /* check if the demod is there */ - if (cx22702_readreg(state, 0x1f) != 0x3) goto error; + struct cx22702_state *state = fe->demodulator_priv; + u8 pllbuf[4]; - /* create dvb_frontend */ - state->frontend.ops = &state->ops; - state->frontend.demodulator_priv = state; - return &state->frontend; + dprintk("%s\n",__FUNCTION__); -error: - if (state) kfree(state); - return NULL; + dvb_pll_configure(state->config->pll_desc, pllbuf, 0, 0); + PLL_ENABLE(state); + pll_write4(&state->pll,pllbuf); + PLL_DISABLE(state); + return 0; } -static struct dvb_frontend_ops cx22702_ops = { - +static struct dvb_frontend_ops cx22702_fe_ops = { .info = { - .name = "Conexant CX22702 DVB-T", + .name = "cx22702 demod", .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER + .caps = + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_RECOVER, }, + .init = cx22702_init, + .sleep = cx22702_sleep, + .set_frontend = cx22702_set_frontend, + .get_frontend = cx22702_get_frontend, + .read_status = cx22702_read_status, + .read_ber = cx22702_read_ber, + .read_signal_strength = cx22702_read_signal_strength, + .read_snr = cx22702_read_snr, + .read_ucblocks = cx22702_read_ucblocks, + .release = cx22702_release, +}; - .release = cx22702_release, +/* ------------------------------------------------------------------ */ - .init = cx22702_init, +/* Validate the demod, make sure we understand the hardware */ +static int cx22702_validate_demod(struct i2c_client *c) +{ + int type = readreg(c, 0x1f); - .set_frontend = cx22702_set_tps, - .get_frontend = cx22702_get_frontend, + if (0x03 != type) { + printk ("%s i2c demod type 0x%02x not known\n", + __FUNCTION__, type); + return -ENODEV; + } + return 0; +} - .read_status = cx22702_read_status, - .read_ber = cx22702_read_ber, - .read_signal_strength = cx22702_read_signal_strength, - .read_snr = cx22702_read_snr, - .read_ucblocks = cx22702_read_ucblocks, +/* Validate the tuner PLL, make sure we understand the hardware */ +static int cx22702_validate_pll(struct cx22702_state *state) +{ + int result=0; + + PLL_ENABLE(state); + result = readreg(&state->pll,0xc2); + PLL_DISABLE(state); + return result; +} + +struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, + struct i2c_adapter* i2c) +{ + struct cx22702_state *state; + int ret; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (NULL == state) + return NULL; + memset(state, 0, sizeof(*state)); + + state->config = config; + state->ops = cx22702_fe_ops; + state->fe.demodulator_priv = state; + state->fe.ops = &state->ops; + + state->demod = demod_template; + state->demod.adapter = i2c; + state->demod.addr = config->demod_address; + state->pll = pll_template; + strlcpy(state->pll.name, config->pll_desc->name, sizeof(state->pll.name)); + state->pll.adapter = i2c; + state->pll.addr = config->pll_address; + i2c_set_clientdata(&state->demod, state); + i2c_set_clientdata(&state->pll, state); + + /* verify devices */ + ret=cx22702_validate_demod(&state->demod); + if (ret < 0) + goto fail_free; + ret=cx22702_validate_pll(state); + if(ret < 0) + goto fail_free; + + /* register i2c */ + ret = i2c_attach_client(&state->demod); + if (0 != ret) { + printk("cx22702: i2c demod register failed (%d)\n", ret); + goto fail_free; + } + ret = i2c_attach_client(&state->pll); + if (0 != ret) { + printk("cx22702: i2c pll register failed (%d)\n", ret); + goto fail_unreg1; + } + + /* all fine ;) */ + return &state->fe; + +fail_unreg1: + i2c_detach_client(&state->demod); +fail_free: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(cx22702_attach); + +/* ------------------------------------------------------------------ */ + +static struct i2c_driver demod_driver = { + .owner = THIS_MODULE, + .name = __stringify(KBUILD_MODNAME) " demod", + .id = I2C_DRIVERID_DVBFE_CX22702, +}; +static struct i2c_client demod_template = { + .name = "cx22702", + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &demod_driver, }; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable verbose debug messages"); +static struct i2c_driver pll_driver = { + .owner = THIS_MODULE, + .name = __stringify(KBUILD_MODNAME) " pll", + .id = I2C_DRIVERID_DVBFE_CX22702, +}; +static struct i2c_client pll_template = { + .name = "unset", + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &pll_driver, +}; -MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver"); +static int __init init_cx22702 (void) +{ + i2c_add_driver(&demod_driver); + i2c_add_driver(&pll_driver); + return 0; +} + +static void __exit exit_cx22702 (void) +{ + i2c_del_driver(&pll_driver); + i2c_del_driver(&demod_driver); +} + +module_init (init_cx22702); +module_exit (exit_cx22702); + +MODULE_DESCRIPTION("CX22702 DVB Frontend driver"); MODULE_AUTHOR("Steven Toth"); +MODULE_AUTHOR("Gerd Knorr"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(cx22702_attach); +/* + * Local variables: + * c-basic-offset: 8 + * compile-command: "make DVB=1" + * End: + */ Index: linux-2.6.11/drivers/media/dvb/frontends/cx22702.h =================================================================== --- linux-2.6.11.orig/drivers/media/dvb/frontends/cx22702.h 2005-03-07 10:14:50.000000000 +0100 +++ linux-2.6.11/drivers/media/dvb/frontends/cx22702.h 2005-03-08 10:33:27.000000000 +0100 @@ -36,8 +36,14 @@ struct cx22702_config u8 demod_address; /* PLL maintenance */ + u8 pll_address; + struct dvb_pll_desc *pll_desc; + +#if 0 /* disabled for now, but maybe we'll need it again for plls + * which don't fit into the dvb_pll_desc model ... */ int (*pll_init)(struct dvb_frontend* fe); int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +#endif }; extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, Index: linux-2.6.11/drivers/media/dvb/frontends/dvb-pll.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/media/dvb/frontends/dvb-pll.c 2005-03-08 10:33:15.000000000 +0100 @@ -0,0 +1,168 @@ +/* + * $Id: dvb-pll.c,v 1.7 2005/02/10 11:52:02 kraxel Exp $ + * + * descriptions + helper functions for simple dvb plls. + * + * (c) 2004 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include "dvb-pll.h" + +/* ----------------------------------------------------------- */ +/* descriptions */ + +struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { + .name = "Thomson dtt7579", + .min = 177000000, + .max = 858000000, + .count = 5, + .entries = { + { 0, 36166667, 166666, 0xb4, 0x03 }, /* go sleep */ + { 443250000, 36166667, 166666, 0xb4, 0x02 }, + { 542000000, 36166667, 166666, 0xb4, 0x08 }, + { 771000000, 36166667, 166666, 0xbc, 0x08 }, + { 999999999, 36166667, 166666, 0xf4, 0x08 }, + }, +}; +EXPORT_SYMBOL(dvb_pll_thomson_dtt7579); + +struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { + .name = "Thomson dtt7610", + .min = 44000000, + .max = 958000000, + .count = 3, + .entries = { + { 157250000, 44000000, 62500, 0x8e, 0x39 }, + { 454000000, 44000000, 62500, 0x8e, 0x3a }, + { 999999999, 44000000, 62500, 0x8e, 0x3c }, + }, +}; +EXPORT_SYMBOL(dvb_pll_thomson_dtt7610); + +static void thomson_dtt759x_bw(u8 *buf, int bandwidth) +{ + if (BANDWIDTH_7_MHZ == bandwidth) + buf[3] |= 0x10; +} + +struct dvb_pll_desc dvb_pll_thomson_dtt759x = { + .name = "Thomson dtt759x", + .min = 177000000, + .max = 896000000, + .setbw = thomson_dtt759x_bw, + .count = 6, + .entries = { + { 0, 36166667, 166666, 0x84, 0x03 }, + { 264000000, 36166667, 166666, 0xb4, 0x02 }, + { 470000000, 36166667, 166666, 0xbc, 0x02 }, + { 735000000, 36166667, 166666, 0xbc, 0x08 }, + { 835000000, 36166667, 166666, 0xf4, 0x08 }, + { 999999999, 36166667, 166666, 0xfc, 0x08 }, + }, +}; +EXPORT_SYMBOL(dvb_pll_thomson_dtt759x); + +struct dvb_pll_desc dvb_pll_lg_z201 = { + .name = "LG z201", + .min = 174000000, + .max = 862000000, + .count = 5, + .entries = { + { 0, 36166667, 166666, 0xbc, 0x03 }, + { 443250000, 36166667, 166666, 0xbc, 0x01 }, + { 542000000, 36166667, 166666, 0xbc, 0x02 }, + { 830000000, 36166667, 166666, 0xf4, 0x02 }, + { 999999999, 36166667, 166666, 0xfc, 0x02 }, + }, +}; +EXPORT_SYMBOL(dvb_pll_lg_z201); + +struct dvb_pll_desc dvb_pll_unknown_1 = { + .name = "unknown 1", /* used by dntv live dvb-t */ + .min = 174000000, + .max = 862000000, + .count = 9, + .entries = { + { 150000000, 36166667, 166666, 0xb4, 0x01 }, + { 173000000, 36166667, 166666, 0xbc, 0x01 }, + { 250000000, 36166667, 166666, 0xb4, 0x02 }, + { 400000000, 36166667, 166666, 0xbc, 0x02 }, + { 420000000, 36166667, 166666, 0xf4, 0x02 }, + { 470000000, 36166667, 166666, 0xfc, 0x02 }, + { 600000000, 36166667, 166666, 0xbc, 0x08 }, + { 730000000, 36166667, 166666, 0xf4, 0x08 }, + { 999999999, 36166667, 166666, 0xfc, 0x08 }, + }, +}; +EXPORT_SYMBOL(dvb_pll_unknown_1); + +/* ----------------------------------------------------------- */ +/* code */ + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, + u32 freq, int bandwidth) +{ + u32 div; + int i; + + if (freq != 0 && (freq < desc->min || freq > desc->max)) + return -EINVAL; + + for (i = 0; i < desc->count; i++) { + if (freq > desc->entries[i].limit) + continue; + break; + } + if (debug) + printk("pll: %s: freq=%d bw=%d | i=%d/%d\n", + desc->name, freq, bandwidth, i, desc->count); + BUG_ON(i == desc->count); + + div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize; + buf[0] = div >> 8; + buf[1] = div & 0xff; + buf[2] = desc->entries[i].cb1; + buf[3] = desc->entries[i].cb2; + + if (desc->setbw) + desc->setbw(buf, bandwidth); + + if (debug) + printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", + desc->name, div, buf[0], buf[1], buf[2], buf[3]); + + return 0; +} +EXPORT_SYMBOL(dvb_pll_configure); + +MODULE_DESCRIPTION("dvb pll library"); +MODULE_AUTHOR("Gerd Knorr"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/dvb/frontends/dvb-pll.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/media/dvb/frontends/dvb-pll.h 2005-03-08 10:33:15.000000000 +0100 @@ -0,0 +1,34 @@ +/* + * $Id: dvb-pll.h,v 1.2 2005/02/10 11:43:41 kraxel Exp $ + */ + +struct dvb_pll_desc { + char *name; + u32 min; + u32 max; + void (*setbw)(u8 *buf, int bandwidth); + int count; + struct { + u32 limit; + u32 offset; + u32 stepsize; + u8 cb1; + u8 cb2; + } entries[]; +}; + +extern struct dvb_pll_desc dvb_pll_thomson_dtt7579; +extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; +extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; +extern struct dvb_pll_desc dvb_pll_lg_z201; +extern struct dvb_pll_desc dvb_pll_unknown_1; + +int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, + u32 freq, int bandwidth); + +/* + * Local variables: + * c-basic-offset: 8 + * compile-command: "make DVB=1" + * End: + */ Index: linux-2.6.11/drivers/media/dvb/frontends/mt352.c =================================================================== --- linux-2.6.11.orig/drivers/media/dvb/frontends/mt352.c 2005-03-07 10:12:32.000000000 +0100 +++ linux-2.6.11/drivers/media/dvb/frontends/mt352.c 2005-03-08 10:33:27.000000000 +0100 @@ -41,13 +41,12 @@ #include "mt352.h" struct mt352_state { - struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* configuration settings */ const struct mt352_config* config; + int s0,s1,s3; struct dvb_frontend frontend; }; @@ -66,23 +65,23 @@ static int mt352_single_write(struct dvb .buf = buf, .len = 2 }; int err = i2c_transfer(state->i2c, &msg, 1); if (err != 1) { - dprintk("mt352_write() to reg %x failed (err = %d)!\n", reg, err); + printk("mt352_write() to reg %x failed (err = %d)!\n", reg, err); return err; -} - return 0; + } + return 0; } int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen) { int err,i; for (i=0; i < ilen-1; i++) - if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1]))) + if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1]))) return err; return 0; } -static u8 mt352_read_register(struct mt352_state* state, u8 reg) +static int mt352_read_register(struct mt352_state* state, u8 reg) { int ret; u8 b0 [] = { reg }; @@ -96,41 +95,87 @@ static u8 mt352_read_register(struct mt3 ret = i2c_transfer(state->i2c, msg, 2); - if (ret != 2) - dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + if (ret != 2) { + printk("%s: readreg error (reg=%d, ret==%i)\n", + __FUNCTION__, reg, ret); + return ret; + } return b1[0]; } -u8 mt352_read(struct dvb_frontend *fe, u8 reg) +int mt352_read(struct dvb_frontend *fe, u8 reg) { return mt352_read_register(fe->demodulator_priv,reg); } +static int mt352_sleep(struct dvb_frontend* fe) +{ + static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 }; + mt352_write(fe, mt352_softdown, sizeof(mt352_softdown)); + return 0; +} +static void mt352_calc_nominal_rate(struct mt352_state* state, + enum fe_bandwidth bandwidth, + unsigned char *buf) +{ + u32 adc_clock = 20480; /* 20.340 MHz */ + u32 bw,value; + switch (bandwidth) { + case BANDWIDTH_6_MHZ: + bw = 6; + break; + case BANDWIDTH_7_MHZ: + bw = 7; + break; + case BANDWIDTH_8_MHZ: + default: + bw = 8; + break; + } + if (state->config->adc_clock) + adc_clock = state->config->adc_clock; + value = 64 * bw * (1<<16) / (7 * 8); + value = value * 1000 / adc_clock; + dprintk("%s: bw %d, adc_clock %d => 0x%x\n", + __FUNCTION__, bw, adc_clock, value); + buf[0] = msb(value); + buf[1] = lsb(value); +} - - -static int mt352_sleep(struct dvb_frontend* fe) +static void mt352_calc_input_freq(struct mt352_state* state, + unsigned char *buf) { - static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 }; + int adc_clock = 20480; /* 20.480000 MHz */ + int if2 = 36167; /* 36.166667 MHz */ + int ife,value; - mt352_write(fe, mt352_softdown, sizeof(mt352_softdown)); + if (state->config->adc_clock) + adc_clock = state->config->adc_clock; + if (state->config->if2) + if2 = state->config->if2; - return 0; + ife = (2*adc_clock - if2); + value = -16374 * ife / adc_clock; + dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", + __FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff); + buf[0] = msb(value); + buf[1] = lsb(value); } static int mt352_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; - unsigned char buf[14]; + unsigned char buf[13]; + static unsigned char tuner_go[] = { 0x5d, 0x01 }; + static unsigned char fsm_go[] = { 0x5e, 0x01 }; unsigned int tps = 0; struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - int i; switch (op->code_rate_HP) { case FEC_2_3: @@ -241,39 +286,33 @@ static int mt352_set_parameters(struct d buf[1] = msb(tps); /* TPS_GIVEN_(1|0) */ buf[2] = lsb(tps); - buf[3] = 0x50; - - /** - * these settings assume 20.48MHz f_ADC, for other tuners you might - * need other values. See p. 33 in the MT352 Design Manual. - */ - if (op->bandwidth == BANDWIDTH_8_MHZ) { - buf[4] = 0x72; /* TRL_NOMINAL_RATE_(1|0) */ - buf[5] = 0x49; - } else if (op->bandwidth == BANDWIDTH_7_MHZ) { - buf[4] = 0x64; - buf[5] = 0x00; - } else { /* 6MHz */ - buf[4] = 0x55; - buf[5] = 0xb7; - } - - buf[6] = 0x31; /* INPUT_FREQ_(1|0), 20.48MHz clock, 36.166667MHz IF */ - buf[7] = 0x05; /* see MT352 Design Manual page 32 for details */ + buf[3] = 0x50; // old +// buf[3] = 0xf4; // pinnacle + mt352_calc_nominal_rate(state, op->bandwidth, buf+4); + mt352_calc_input_freq(state, buf+6); state->config->pll_set(fe, param, buf+8); - buf[13] = 0x01; /* TUNER_GO!! */ - +#if 0 /* FIXME: should be catched elsewhere ... */ /* Only send the tuning request if the tuner doesn't have the requested * parameters already set. Enhances tuning time and prevents stream * breakup when retuning the same transponder. */ for (i = 1; i < 13; i++) - if (buf[i] != mt352_read_register(state, i + 0x50)) { - mt352_write(fe, buf, sizeof(buf)); + if (buf[i] != mt352_read_register(state, i + 0x50)) break; - } + if (13 == i) + /* no changes */ + return 0; +#endif + mt352_write(fe, buf, sizeof(buf)); + if (state->config->no_tuner) { + /* start decoding */ + mt352_write(fe, fsm_go, 2); + } else { + /* start tuning */ + mt352_write(fe, tuner_go, 2); + } return 0; } @@ -395,24 +434,39 @@ static int mt352_get_parameters(struct d static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status) { struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; - u8 r; - - *status = 0; - r = mt352_read_register (state, STATUS_0); - if (r & (1 << 4)) - *status = FE_HAS_CARRIER; - if (r & (1 << 1)) - *status |= FE_HAS_VITERBI; - if (r & (1 << 5)) - *status |= FE_HAS_LOCK; +#if 1 + int val; - r = mt352_read_register (state, STATUS_1); - if (r & (1 << 1)) - *status |= FE_HAS_SYNC; + if (0 != mt352_read_register(state, INTERRUPT_0)) { + val = mt352_read_register(state, STATUS_0); + if (-1 != val) + state->s0 = val; + val = mt352_read_register(state, STATUS_1); + if (-1 != val) + state->s1 = val; + val = mt352_read_register(state, STATUS_3); + if (-1 != val) + state->s3 = val; + } +#else + state->s0 = mt352_read_register(state, STATUS_0); + state->s1 = mt352_read_register(state, STATUS_1); + state->s3 = mt352_read_register(state, STATUS_3); + if (-1 == state->s0 || -1 == state->s1 || -1 == state->s3) + return -EIO; +#endif - r = mt352_read_register (state, STATUS_3); - if (r & (1 << 6)) - *status |= FE_HAS_SIGNAL; + *status = 0; + if (state->s0 & (1 << 4)) + *status |= FE_HAS_CARRIER; + if (state->s0 & (1 << 1)) + *status |= FE_HAS_VITERBI; + if (state->s0 & (1 << 5)) + *status |= FE_HAS_LOCK; + if (state->s1 & (1 << 1)) + *status |= FE_HAS_SYNC; + if (state->s3 & (1 << 6)) + *status |= FE_HAS_SIGNAL; if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) @@ -470,7 +524,7 @@ static int mt352_get_tune_settings(struc fe_tune_settings->max_drift = 0; return 0; - } +} static int mt352_init(struct dvb_frontend* fe) { @@ -478,22 +532,24 @@ static int mt352_init(struct dvb_fronten static u8 mt352_reset_attach [] = { RESET, 0xC0 }; + dprintk("%s: hello\n",__FUNCTION__); + if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 || (mt352_read_register(state, CONFIG) & 0x20) == 0) { - /* Do a "hard" reset */ + /* Do a "hard" reset */ mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach)); return state->config->demod_init(fe); } return 0; - } +} static void mt352_release(struct dvb_frontend* fe) { struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; - kfree(state); - } + kfree(state); +} static struct dvb_frontend_ops mt352_ops; @@ -505,6 +561,7 @@ struct dvb_frontend* mt352_attach(const /* allocate memory for the internal state */ state = (struct mt352_state*) kmalloc(sizeof(struct mt352_state), GFP_KERNEL); if (state == NULL) goto error; + memset(state,0,sizeof(*state)); /* setup the state */ state->config = config; @@ -568,3 +625,9 @@ MODULE_LICENSE("GPL"); EXPORT_SYMBOL(mt352_attach); EXPORT_SYMBOL(mt352_write); EXPORT_SYMBOL(mt352_read); +/* + * Local variables: + * c-basic-offset: 8 + * compile-command: "make DVB=1" + * End: + */ Index: linux-2.6.11/drivers/media/dvb/frontends/mt352.h =================================================================== --- linux-2.6.11.orig/drivers/media/dvb/frontends/mt352.h 2005-03-07 10:16:32.000000000 +0100 +++ linux-2.6.11/drivers/media/dvb/frontends/mt352.h 2005-03-08 10:33:27.000000000 +0100 @@ -40,6 +40,13 @@ struct mt352_config /* the demodulator's i2c address */ u8 demod_address; + /* frequencies in kHz */ + int adc_clock; // default: 20480 + int if2; // default: 36166 + + /* set if no pll is connected to the secondary i2c bus */ + int no_tuner; + /* Initialise the demodulator and PLL. Cannot be NULL */ int (*demod_init)(struct dvb_frontend* fe); @@ -54,6 +61,12 @@ extern struct dvb_frontend* mt352_attach struct i2c_adapter* i2c); extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen); -extern u8 mt352_read(struct dvb_frontend *fe, u8 reg); +extern int mt352_read(struct dvb_frontend *fe, u8 reg); #endif // MT352_H + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/dvb/frontends/or51132.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/media/dvb/frontends/or51132.c 2005-03-08 10:33:27.000000000 +0100 @@ -0,0 +1,628 @@ +/* + * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM + * + * Copyright (C) 2005 Kirk Lapray + * + * Based on code from Jack Kelliher (kelliher@xmission.com) + * Copyright (C) 2002 & pcHDTV, inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * +*/ + +/* + * This driver needs two external firmware files. Please copy + * "dvb-fe-or51132-vsb.fw" and "dvb-fe-or51132-qam.fw" to + * /usr/lib/hotplug/firmware/ or /lib/firmware/ + * (depending on configuration of firmware hotplug). + */ +#define OR51132_VSB_FIRMWARE "dvb-fe-or51132-vsb.fw" +#define OR51132_QAM_FIRMWARE "dvb-fe-or51132-qam.fw" + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb-pll.h" +#include "or51132.h" + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "or51132: " args); \ + } while (0) + + +struct or51132_state +{ + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + + /* Configuration settings */ + const struct or51132_config* config; + + struct dvb_frontend frontend; + + /* Demodulator private data */ + fe_modulation_t current_modulation; + + /* Tuner private data */ + u32 current_frequency; +}; + +static int i2c_writebytes (struct or51132_state* state, u8 reg, u8 *buf, int len) +{ + int err; + struct i2c_msg msg; + msg.addr = reg; + msg.flags = 0; + msg.len = len; + msg.buf = buf; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "or51132: i2c_writebytes error (addr %02x, err == %i)\n", reg, err); + return -EREMOTEIO; + } + + return 0; +} + +static u8 i2c_readbytes (struct or51132_state* state, u8 reg, u8* buf, int len) +{ + int err; + struct i2c_msg msg; + msg.addr = reg; + msg.flags = I2C_M_RD; + msg.len = len; + msg.buf = buf; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "or51132: i2c_readbytes error (addr %02x, err == %i)\n", reg, err); + return -EREMOTEIO; + } + + return 0; +} + +static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) +{ + struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + static u8 run_buf[] = {0x7F,0x01}; + static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00}; + u8 rec_buf[14]; + u8 cmd_buf[14]; + u32 firmwareAsize, firmwareBsize; + int i,ret; + + dprintk("Firmware is %ld bytes\n",fw->size); + + /* Get size of firmware A and B */ + firmwareAsize = le32_to_cpu(*((u32*)fw->data)); + dprintk("FirmwareA is %i bytes\n",firmwareAsize); + firmwareBsize = le32_to_cpu(*((u32*)(fw->data+4))); + dprintk("FirmwareB is %i bytes\n",firmwareBsize); + + /* Upload firmware */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + &fw->data[8],firmwareAsize))) { + printk(KERN_WARNING "or51132: load_firmware error 1\n"); + return ret; + } + msleep(1); /* 1ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + &fw->data[8+firmwareAsize],firmwareBsize))) { + printk(KERN_WARNING "or51132: load_firmware error 2\n"); + return ret; + } + msleep(1); /* 1ms */ + + if ((ret = i2c_writebytes(state,state->config->demod_address, + run_buf,2))) { + printk(KERN_WARNING "or51132: load_firmware error 3\n"); + return ret; + } + + /* Wait at least 5 msec */ + msleep(20); /* 10ms */ + + if ((ret = i2c_writebytes(state,state->config->demod_address, + run_buf,2))) { + printk(KERN_WARNING "or51132: load_firmware error 4\n"); + return ret; + } + + /* 50ms for operation to begin */ + msleep(50); + + /* Read back ucode version to besure we loaded correctly and are really up and running */ + /* Get uCode version */ + cmd_buf[0] = 0x10; + cmd_buf[1] = 0x10; + cmd_buf[2] = 0x00; + cmd_buf[3] = 0x00; + msleep(20); /* 20ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + cmd_buf,3))) { + printk(KERN_WARNING "or51132: load_firmware error a\n"); + return ret; + } + + cmd_buf[0] = 0x04; + cmd_buf[1] = 0x17; + cmd_buf[2] = 0x00; + cmd_buf[3] = 0x00; + msleep(20); /* 20ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + cmd_buf,2))) { + printk(KERN_WARNING "or51132: load_firmware error b\n"); + return ret; + } + + cmd_buf[0] = 0x00; + cmd_buf[1] = 0x00; + cmd_buf[2] = 0x00; + cmd_buf[3] = 0x00; + msleep(20); /* 20ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + cmd_buf,2))) { + printk(KERN_WARNING "or51132: load_firmware error c\n"); + return ret; + } + + for(i=0;i<4;i++) { + msleep(20); /* 20ms */ + get_ver_buf[4] = i+1; + if ((ret = i2c_readbytes(state,state->config->demod_address, + &rec_buf[i*2],2))) { + printk(KERN_WARNING + "or51132: load_firmware error d - %d\n",i); + return ret; + } + } + + printk(KERN_WARNING + "or51132: Version: %02X%02X%02X%02X-%02X%02X%02X%02X (%02X%01X-%01X-%02X%01X-%01X)\n", + rec_buf[1],rec_buf[0],rec_buf[3],rec_buf[2], + rec_buf[5],rec_buf[4],rec_buf[7],rec_buf[6], + rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f, + rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f); + + cmd_buf[0] = 0x10; + cmd_buf[1] = 0x00; + cmd_buf[2] = 0x00; + cmd_buf[3] = 0x00; + msleep(20); /* 20ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + cmd_buf,3))) { + printk(KERN_WARNING "or51132: load_firmware error e\n"); + return ret; + } + return 0; +}; + +static int or51132_init(struct dvb_frontend* fe) +{ + return 0; +} + +static int or51132_read_ber(struct dvb_frontend* fe, u32* ber) +{ + *ber = 0; + return 0; +} + +static int or51132_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + *ucblocks = 0; + return 0; +} + +static int or51132_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int or51132_setmode(struct dvb_frontend* fe) +{ + struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + unsigned char cmd_buf[4]; + + dprintk("setmode %d\n",(int)state->current_modulation); + /* set operation mode in Receiver 1 register; */ + cmd_buf[0] = 0x04; + cmd_buf[1] = 0x01; + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + case QAM_AUTO: + /* Auto-deinterleave; MPEG ser, MPEG2tr, phase noise-high*/ + cmd_buf[2] = 0x5F; + break; + case VSB_8: + /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high*/ + cmd_buf[2] = 0x50; + break; + default: + printk("setmode:Modulation set to unsupported value\n"); + }; + cmd_buf[3] = 0x00; + if (i2c_writebytes(state,state->config->demod_address, + cmd_buf,3)) { + printk(KERN_WARNING "or51132: set_mode error 1\n"); + return -1; + } + dprintk("or51132: set #1 to %02x\n", cmd_buf[2]); + + /* Set operation mode in Receiver 6 register */ + cmd_buf[0] = 0x1C; + switch (state->current_modulation) { + case QAM_AUTO: + /* REC MODE Normal Carrier Lock */ + cmd_buf[1] = 0x00; + /* Channel MODE Auto QAM64/256 */ + cmd_buf[2] = 0x4f; + break; + case QAM_256: + /* REC MODE Normal Carrier Lock */ + cmd_buf[1] = 0x00; + /* Channel MODE QAM256 */ + cmd_buf[2] = 0x45; + break; + case QAM_64: + /* REC MODE Normal Carrier Lock */ + cmd_buf[1] = 0x00; + /* Channel MODE QAM64 */ + cmd_buf[2] = 0x43; + break; + case VSB_8: + /* REC MODE inv IF spectrum, Normal */ + cmd_buf[1] = 0x03; + /* Channel MODE ATSC/VSB8 */ + cmd_buf[2] = 0x06; + break; + default: + printk("setmode: Modulation set to unsupported value\n"); + }; + cmd_buf[3] = 0x00; + msleep(20); /* 20ms */ + if (i2c_writebytes(state,state->config->demod_address, + cmd_buf,3)) { + printk(KERN_WARNING "or51132: set_mode error 2\n"); + return -1; + } + dprintk("or51132: set #6 to 0x%02x%02x\n", cmd_buf[1], cmd_buf[2]); + + return 0; +} + +static int or51132_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + int ret; + u8 buf[4]; + struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + const struct firmware *fw; + + /* Change only if we are actually changing the modulation */ + if (state->current_modulation != param->u.vsb.modulation) { + switch(param->u.vsb.modulation) { + case VSB_8: + dprintk("set_parameters VSB MODE\n"); + printk("or51132: Waiting for firmware upload(%s)...\n", + OR51132_VSB_FIRMWARE); + ret = request_firmware(&fw, OR51132_VSB_FIRMWARE, + &state->i2c->dev); + if (ret){ + printk(KERN_WARNING "or51132: No firmware up" + "loaded(timeout or file not found?)\n"); + return ret; + } + /* Set non-punctured clock for VSB */ + state->config->set_ts_params(fe, 0); + break; + case QAM_AUTO: + case QAM_64: + case QAM_256: + dprintk("set_parameters QAM MODE\n"); + printk("or51132: Waiting for firmware upload(%s)...\n", + OR51132_QAM_FIRMWARE); + ret = request_firmware(&fw, OR51132_QAM_FIRMWARE, + &state->i2c->dev); + if (ret){ + printk(KERN_WARNING "or51132: No firmware up" + "loaded(timeout or file not found?)\n"); + return ret; + } + /* Set punctured clock for QAM */ + state->config->set_ts_params(fe, 1); + break; + default: + printk("or51132:Modulation type(%d) UNSUPPORTED\n", + param->u.vsb.modulation); + return -1; + }; + ret = or51132_load_firmware(fe, fw); + release_firmware(fw); + if (ret) { + printk(KERN_WARNING "or51132: Writing firmware to " + "device failed!\n"); + return ret; + } + printk("or51132: Firmware upload complete.\n"); + + state->current_modulation = param->u.vsb.modulation; + or51132_setmode(fe); + } + + /* Change only if we are actually changing the channel */ + if (state->current_frequency != param->frequency) { + dvb_pll_configure(state->config->pll_desc, buf, + param->frequency, 0); + dprintk("set_parameters tuner bytes: 0x%02x 0x%02x " + "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]); + if (i2c_writebytes(state, state->config->pll_address ,buf, 4)) + printk(KERN_WARNING "or51132: set_parameters error " + "writing to tuner\n"); + + /* Set to current mode */ + or51132_setmode(fe); + + /* Update current frequency */ + state->current_frequency = param->frequency; + } + return 0; +} + +static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + unsigned char rec_buf[2]; + unsigned char snd_buf[2]; + *status = 0; + + /* Receiver Status */ + snd_buf[0]=0x04; + snd_buf[1]=0x00; + msleep(30); /* 30ms */ + if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { + printk(KERN_WARNING "or51132: read_status write error\n"); + return -1; + } + msleep(30); /* 30ms */ + if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { + printk(KERN_WARNING "or51132: read_status read error\n"); + return -1; + } + dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]); + + if (rec_buf[1] & 0x01) { /* Receiver Lock */ + *status |= FE_HAS_SIGNAL; + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_LOCK; + } + return 0; +} + +/* log10-1 table at .5 increments from 1 to 100.5 */ +unsigned int i100x20log10[] = { + 0, 352, 602, 795, 954, 1088, 1204, 1306, 1397, 1480, + 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042, + 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380, + 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623, + 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813, + 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968, + 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100, + 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214, + 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316, + 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406, + 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488, + 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563, + 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632, + 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696, + 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755, + 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811, + 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863, + 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913, + 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960, + 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004, +}; + +unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000}; + +unsigned int i20Log10(unsigned short val) +{ + unsigned int rntval = 100; + unsigned int tmp = val; + unsigned int exp = 1; + + while(tmp > 100) {tmp /= 100; exp++;} + + val = (2 * val)/denom[exp]; + if (exp > 1) rntval = 2000*exp; + + rntval += i100x20log10[val]; + return rntval; +} + +static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + unsigned char rec_buf[2]; + unsigned char snd_buf[2]; + u8 rcvr_stat; + u16 snr_equ; + int usK; + + snd_buf[0]=0x04; + snd_buf[1]=0x02; /* SNR after Equalizer */ + msleep(30); /* 30ms */ + if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { + printk(KERN_WARNING "or51132: read_status write error\n"); + return -1; + } + msleep(30); /* 30ms */ + if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { + printk(KERN_WARNING "or51132: read_status read error\n"); + return -1; + } + snr_equ = rec_buf[0] | (rec_buf[1] << 8); + dprintk("read_signal_strength snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ); + + /* Receiver Status */ + snd_buf[0]=0x04; + snd_buf[1]=0x00; + msleep(30); /* 30ms */ + if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { + printk(KERN_WARNING "or51132: read_signal_strength read_status write error\n"); + return -1; + } + msleep(30); /* 30ms */ + if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { + printk(KERN_WARNING "or51132: read_signal_strength read_status read error\n"); + return -1; + } + dprintk("read_signal_strength read_status %x %x\n",rec_buf[0],rec_buf[1]); + rcvr_stat = rec_buf[1]; + usK = (rcvr_stat & 0x10) ? 3 : 0; + + /* The value reported back from the frontend will be FFFF=100% 0000=0% */ + *strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000; + dprintk("read_signal_strength %i\n",*strength); + + return 0; +} + +static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + unsigned char rec_buf[2]; + unsigned char snd_buf[2]; + u16 snr_equ; + + snd_buf[0]=0x04; + snd_buf[1]=0x02; /* SNR after Equalizer */ + msleep(30); /* 30ms */ + if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { + printk(KERN_WARNING "or51132: read_snr write error\n"); + return -1; + } + msleep(30); /* 30ms */ + if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { + printk(KERN_WARNING "or51132: read_snr dvr read error\n"); + return -1; + } + snr_equ = rec_buf[0] | (rec_buf[1] << 8); + dprintk("read_snr snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ); + + *snr = 0xFFFF - snr_equ; + dprintk("read_snr %i\n",*snr); + + return 0; +} + +static int or51132_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 500; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + + return 0; +} + +static void or51132_release(struct dvb_frontend* fe) +{ + struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops or51132_ops; + +struct dvb_frontend* or51132_attach(const struct or51132_config* config, + struct i2c_adapter* i2c) +{ + struct or51132_state* state = NULL; + + /* Allocate memory for the internal state */ + state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); + state->current_frequency = -1; + state->current_modulation = -1; + + /* Create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops or51132_ops = { + + .info = { + .name = "Oren OR51132 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min = 44000000, + .frequency_max = 958000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | + FE_CAN_8VSB + }, + + .release = or51132_release, + + .init = or51132_init, + .sleep = or51132_sleep, + + .set_frontend = or51132_set_parameters, + .get_tune_settings = or51132_get_tune_settings, + + .read_status = or51132_read_status, + .read_ber = or51132_read_ber, + .read_signal_strength = or51132_read_signal_strength, + .read_snr = or51132_read_snr, + .read_ucblocks = or51132_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver"); +MODULE_AUTHOR("Kirk Lapray"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(or51132_attach); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/dvb/frontends/or51132.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/media/dvb/frontends/or51132.h 2005-03-08 10:33:27.000000000 +0100 @@ -0,0 +1,48 @@ +/* + * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM + * + * Copyright (C) 2005 Kirk Lapray + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * +*/ + +#ifndef OR51132_H +#define OR51132_H + +#include +#include + +struct or51132_config +{ + /* The demodulator's i2c address */ + u8 demod_address; + u8 pll_address; + struct dvb_pll_desc *pll_desc; + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); +}; + +extern struct dvb_frontend* or51132_attach(const struct or51132_config* config, + struct i2c_adapter* i2c); + +#endif // OR51132_H + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/radio/miropcm20-radio.c =================================================================== --- linux-2.6.11.orig/drivers/media/radio/miropcm20-radio.c 2005-03-07 10:13:11.000000000 +0100 +++ linux-2.6.11/drivers/media/radio/miropcm20-radio.c 2005-03-08 10:33:15.000000000 +0100 @@ -75,9 +75,7 @@ static int pcm20_getflags(struct pcm20_d if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0) return i; -#ifdef DEBUG - printk("check_sig: 0x%x\n", i); -#endif + pr_debug("check_sig: 0x%x\n", i); if (i & 0x80) { /* no signal from tuner */ *flags=0; @@ -107,9 +105,7 @@ static int pcm20_getflags(struct pcm20_d if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0) return i; -#ifdef DEBUG - printk("rds-signal: %d\n", buf); -#endif + pr_debug("rds-signal: %d\n", buf); if (buf > 15) { printk("miropcm20-radio: RX strengths unexpected high...\n"); buf=15; @@ -172,9 +168,7 @@ static int pcm20_do_ioctl(struct inode * unsigned long *freq = arg; pcm20->freq = *freq; i=pcm20_setfreq(pcm20, pcm20->freq); -#ifdef DEBUG - printk("First view (setfreq): 0x%x\n", i); -#endif + pr_debug("First view (setfreq): 0x%x\n", i); return i; } case VIDIOCGAUDIO: Index: linux-2.6.11/drivers/media/radio/radio-zoltrix.c =================================================================== --- linux-2.6.11.orig/drivers/media/radio/radio-zoltrix.c 2005-03-07 10:15:52.000000000 +0100 +++ linux-2.6.11/drivers/media/radio/radio-zoltrix.c 2005-03-08 10:33:15.000000000 +0100 @@ -29,7 +29,7 @@ #include /* Modules */ #include /* Initdata */ #include /* check_region, request_region */ -#include /* udelay */ +#include /* udelay, msleep */ #include /* outb, outb_p */ #include /* copy to/from user */ #include /* kernel radio structs */ @@ -51,15 +51,6 @@ struct zol_device { struct semaphore lock; }; - -/* local things */ - -static void sleep_delay(void) -{ - /* Sleep nicely for +/- 10 mS */ - schedule(); -} - static int zol_setvol(struct zol_device *dev, int vol) { dev->curvol = vol; @@ -76,7 +67,7 @@ static int zol_setvol(struct zol_device } outb(dev->curvol-1, io); - sleep_delay(); + msleep(10); inb(io + 2); up(&dev->lock); return 0; @@ -176,11 +167,10 @@ static int zol_getsigstr(struct zol_devi down(&dev->lock); outb(0x00, io); /* This stuff I found to do nothing */ outb(dev->curvol, io); - sleep_delay(); - sleep_delay(); + msleep(20); a = inb(io); - sleep_delay(); + msleep(10); b = inb(io); up(&dev->lock); @@ -202,11 +192,10 @@ static int zol_is_stereo (struct zol_dev outb(0x00, io); outb(dev->curvol, io); - sleep_delay(); - sleep_delay(); + msleep(20); x1 = inb(io); - sleep_delay(); + msleep(10); x2 = inb(io); up(&dev->lock); @@ -368,8 +357,7 @@ static int __init zoltrix_init(void) outb(0, io); outb(0, io); - sleep_delay(); - sleep_delay(); + msleep(20); inb(io + 3); zoltrix_unit.curvol = 0; Index: linux-2.6.11/drivers/media/video/Kconfig =================================================================== --- linux-2.6.11.orig/drivers/media/video/Kconfig 2005-03-07 10:15:21.000000000 +0100 +++ linux-2.6.11/drivers/media/video/Kconfig 2005-03-08 10:33:27.000000000 +0100 @@ -249,7 +249,9 @@ config VIDEO_SAA7134 config VIDEO_SAA7134_DVB tristate "DVB Support for saa7134 based TV cards" - depends on VIDEO_SAA7134 && DVB_CORE && BROKEN + depends on VIDEO_SAA7134 && DVB_CORE + select VIDEO_BUF_DVB + select DVB_MT352 ---help--- This adds support for DVB cards based on the Philips saa7134 chip. @@ -305,11 +307,14 @@ config VIDEO_HEXIUM_GEMINI config VIDEO_CX88 tristate "Conexant 2388x (bt878 successor) support" - depends on VIDEO_DEV && PCI && EXPERIMENTAL + depends on VIDEO_DEV && PCI && I2C && EXPERIMENTAL select I2C_ALGOBIT + select FW_LOADER select VIDEO_BTCX select VIDEO_BUF select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_IR ---help--- This is a video4linux driver for Conexant 2388x based TV cards. @@ -319,10 +324,13 @@ config VIDEO_CX88 config VIDEO_CX88_DVB tristate "DVB Support for cx2388x based TV cards" - depends on VIDEO_CX88 && DVB_CORE && BROKEN + depends on VIDEO_CX88 && DVB_CORE select VIDEO_BUF_DVB + select DVB_MT352 + select DVB_CX22702 + select DVB_OR51132 ---help--- - This adds support for DVB cards based on the + This adds support for DVB/ATSC cards based on the Connexant 2388x chip. config VIDEO_OVCAMCHIP Index: linux-2.6.11/drivers/media/video/Makefile =================================================================== --- linux-2.6.11.orig/drivers/media/video/Makefile 2005-03-07 10:13:33.000000000 +0100 +++ linux-2.6.11/drivers/media/video/Makefile 2005-03-07 18:13:01.000000000 +0100 @@ -7,6 +7,7 @@ bttv-objs := bttv-driver.o bttv-cards.o zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o +tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o Index: linux-2.6.11/drivers/media/video/bt832.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/bt832.c 2005-03-07 10:14:50.000000000 +0100 +++ linux-2.6.11/drivers/media/video/bt832.c 2005-03-08 10:33:27.000000000 +0100 @@ -6,7 +6,7 @@ It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly connected to bt848/bt878 GPIO pins on this purpose. (see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets) - + Supported Cards: - Pixelview Rev.4E: 0x8a GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 ! @@ -31,8 +31,8 @@ #include #include -#include "id.h" -#include "audiochip.h" +#include +#include #include "bttv.h" #include "bt832.h" @@ -95,7 +95,7 @@ int bt832_init(struct i2c_client *i2c_cl buf=kmalloc(65,GFP_KERNEL); bt832_hexdump(i2c_client_s,buf); - + if(buf[0x40] != 0x31) { printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]); kfree(buf); @@ -135,7 +135,7 @@ int bt832_init(struct i2c_client *i2c_cl buf[1]= 0x27 & (~0x01); // Default | !skip if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc); - + bt832_hexdump(i2c_client_s,buf); #if 0 @@ -168,8 +168,7 @@ int bt832_init(struct i2c_client *i2c_cl -static int bt832_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) +static int bt832_attach(struct i2c_adapter *adap, int addr, int kind) { struct bt832 *t; @@ -184,27 +183,32 @@ static int bt832_attach(struct i2c_adapt return -ENOMEM; memset(t,0,sizeof(*t)); t->client = client_template; - t->client.data = t; + i2c_set_clientdata(&t->client, t); i2c_attach_client(&t->client); if(! bt832_init(&t->client)) { bt832_detach(&t->client); return -1; } - + return 0; } static int bt832_probe(struct i2c_adapter *adap) { +#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, bt832_attach); +#else + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, bt832_attach); +#endif return 0; } static int bt832_detach(struct i2c_client *client) { - struct bt832 *t = (struct bt832*)client->data; + struct bt832 *t = i2c_get_clientdata(client); printk("bt832: detach.\n"); i2c_detach_client(client); @@ -215,7 +219,7 @@ static int bt832_detach(struct i2c_clien static int bt832_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct bt832 *t = (struct bt832*)client->data; + struct bt832 *t = i2c_get_clientdata(client); printk("bt832: command %x\n",cmd); @@ -249,19 +253,18 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - .name = "bt832", - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + I2C_DEVNAME("bt832"), + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, }; -int bt832_init_module(void) +static int __init bt832_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void bt832_cleanup_module(void) +static void __exit bt832_cleanup_module(void) { i2c_del_driver(&driver); } @@ -269,3 +272,10 @@ static void bt832_cleanup_module(void) module_init(bt832_init_module); module_exit(bt832_cleanup_module); +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/video/bt832.h =================================================================== --- linux-2.6.11.orig/drivers/media/video/bt832.h 2005-03-07 10:14:39.000000000 +0100 +++ linux-2.6.11/drivers/media/video/bt832.h 2005-03-08 10:33:27.000000000 +0100 @@ -1,6 +1,6 @@ /* Bt832 CMOS Camera Video Processor (VP) - The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS + The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS color digital camera directly to video capture devices via an 8-bit, 4:2:2 YUV or YCrCb video interface. @@ -85,7 +85,7 @@ #define BT832_DEVICE_ID 63 # define BT832_DEVICE_ID__31 0x31 // Bt832 has ID 0x31 -/* STMicroelectronivcs VV5404 camera module +/* STMicroelectronivcs VV5404 camera module i2c: 0x20: sensor address i2c: 0xa0: eeprom for ccd defect map */ @@ -256,26 +256,26 @@ For the CCIR-601 standards, the sampling //=========================================================================== // Timing generator SRAM table values for CCIR601 720x480 NTSC //=========================================================================== -// For NTSC CCIR656 +// For NTSC CCIR656 BYTE BtCard::SRAMTable_NTSC[] = { // SRAM Timing Table for NTSC - 0x0c, 0xc0, 0x00, - 0x00, 0x90, 0xc2, - 0x03, 0x10, 0x03, - 0x06, 0x10, 0x34, - 0x12, 0x12, 0x65, - 0x02, 0x13, 0x24, - 0x19, 0x00, 0x24, - 0x39, 0x00, 0x96, - 0x59, 0x08, 0x93, + 0x0c, 0xc0, 0x00, + 0x00, 0x90, 0xc2, + 0x03, 0x10, 0x03, + 0x06, 0x10, 0x34, + 0x12, 0x12, 0x65, + 0x02, 0x13, 0x24, + 0x19, 0x00, 0x24, + 0x39, 0x00, 0x96, + 0x59, 0x08, 0x93, 0x83, 0x08, 0x97, - 0x03, 0x50, 0x30, - 0xc0, 0x40, 0x30, - 0x86, 0x01, 0x01, - 0xa6, 0x0d, 0x62, - 0x03, 0x11, 0x61, - 0x05, 0x37, 0x30, + 0x03, 0x50, 0x30, + 0xc0, 0x40, 0x30, + 0x86, 0x01, 0x01, + 0xa6, 0x0d, 0x62, + 0x03, 0x11, 0x61, + 0x05, 0x37, 0x30, 0xac, 0x21, 0x50 }; Index: linux-2.6.11/drivers/media/video/btcx-risc.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/btcx-risc.c 2005-03-07 10:12:26.000000000 +0100 +++ linux-2.6.11/drivers/media/video/btcx-risc.c 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - $Id: btcx-risc.c,v 1.5 2004/12/10 12:33:39 kraxel Exp $ + $Id: btcx-risc.c,v 1.6 2005/02/21 13:57:59 kraxel Exp $ btcx-risc.c @@ -52,12 +52,13 @@ void btcx_riscmem_free(struct pci_dev *p { if (NULL == risc->cpu) return; - pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); - memset(risc,0,sizeof(*risc)); if (debug) { memcnt--; - printk("btcx: riscmem free [%d]\n",memcnt); + printk("btcx: riscmem free [%d] dma=%lx\n", + memcnt, (unsigned long)risc->dma); } + pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); + memset(risc,0,sizeof(*risc)); } int btcx_riscmem_alloc(struct pci_dev *pci, @@ -78,7 +79,8 @@ int btcx_riscmem_alloc(struct pci_dev *p risc->size = size; if (debug) { memcnt++; - printk("btcx: riscmem alloc size=%d [%d]\n",size,memcnt); + printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", + memcnt, (unsigned long)dma, cpu, size); } } memset(risc->cpu,0,risc->size); Index: linux-2.6.11/drivers/media/video/bttv-cards.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/bttv-cards.c 2005-03-07 10:13:52.000000000 +0100 +++ linux-2.6.11/drivers/media/video/bttv-cards.c 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - $Id: bttv-cards.c,v 1.42 2005/01/13 17:22:33 kraxel Exp $ + $Id: bttv-cards.c,v 1.47 2005/02/22 14:06:32 kraxel Exp $ bttv-cards.c @@ -80,6 +80,9 @@ static void picolo_tetra_init(struct btt static void tibetCS16_muxsel(struct bttv *btv, unsigned int input); static void tibetCS16_init(struct bttv *btv); +static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input); +static void kodicom4400r_init(struct bttv *btv); + static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input); static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input); @@ -101,6 +104,7 @@ static unsigned int pll[BTTV_MAX] = { static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static struct bttv *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL }; #ifdef MODULE static unsigned int autoload = 1; #else @@ -170,6 +174,8 @@ static struct CARD { // some cards ship with byteswapped IDs ... { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" }, { 0xff00bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" }, + // this seems to happen as well ... + { 0xff1211bd, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" }, { 0x263710b4, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" }, @@ -291,7 +297,7 @@ static struct CARD { { 0x07611461, BTTV_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, { 0x001c11bd, BTTV_PINNACLESAT, "Pinnacle PCTV Sat" }, { 0x002611bd, BTTV_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, - { 0x00011822, BTTV_TWINHAN_DST, "Twinhan VisionPlus DVB-T" }, + { 0x00011822, BTTV_TWINHAN_DST, "Twinhan VisionPlus DVB" }, { 0xfc00270f, BTTV_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, { 0x07711461, BTTV_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, { 0xdb1018ac, BTTV_DVICO_DVBT_LITE, "DVICO FusionHDTV DVB-T Lite" }, @@ -1920,6 +1926,7 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .muxsel = { 2, 3, 1, 0}, .tuner_type = TUNER_PHILIPS_ATSC, + .has_dvb = 1, },{ .name = "Twinhan DST + clones", .no_msp34xx = 1, @@ -2188,6 +2195,63 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .tuner_type = -1, .muxsel_hook = tibetCS16_muxsel, +}, +{ + /* Bill Brack */ + /* + * Note that, because of the card's wiring, the "master" + * BT878A chip (i.e. the one which controls the analog switch + * and must use this card type) is the 2nd one detected. The + * other 3 chips should use card type 0x85, whose description + * follows this one. There is a EEPROM on the card (which is + * connected to the I2C of one of those other chips), but is + * not currently handled. There is also a facility for a + * "monitor", which is also not currently implemented. + */ + .name = "Kodicom 4400R (master)", + .video_inputs = 16, + .audio_inputs = 0, + .tuner = -1, + .tuner_type = -1, + .svhs = -1, + /* GPIO bits 0-9 used for analog switch: + * 00 - 03: camera selector + * 04 - 06: channel (controller) selector + * 07: data (1->on, 0->off) + * 08: strobe + * 09: reset + * bit 16 is input from sync separator for the channel + */ + .gpiomask = 0x0003ff, + .no_gpioirq = 1, + .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .no_tda9875 = 1, + .muxsel_hook = kodicom4400r_muxsel, +}, +{ + /* Bill Brack */ + /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the + * one which controls the analog switch, and must use the card type) + * is the 2nd one detected. The other 3 chips should use this card + * type + */ + .name = "Kodicom 4400R (slave)", + .video_inputs = 16, + .audio_inputs = 0, + .tuner = -1, + .tuner_type = -1, + .svhs = -1, + .gpiomask = 0x010000, + .no_gpioirq = 1, + .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .no_tda9875 = 1, + .muxsel_hook = kodicom4400r_muxsel, }}; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -2682,6 +2746,9 @@ void __devinit bttv_init_card2(struct bt case BTTV_TIBET_CS16: tibetCS16_init(btv); break; + case BTTV_KODICOM_4400R: + kodicom4400r_init(btv); + break; } /* pll configuration */ @@ -3894,6 +3961,112 @@ static void tibetCS16_init(struct bttv * gpio_write(0x0f7fff); } +/* + * The following routines for the Kodicom-4400r get a little mind-twisting. + * There is a "master" controller and three "slave" controllers, together + * an analog switch which connects any of 16 cameras to any of the BT87A's. + * The analog switch is controlled by the "master", but the detection order + * of the four BT878A chips is in an order which I just don't understand. + * The "master" is actually the second controller to be detected. The + * logic on the board uses logical numbers for the 4 controlers, but + * those numbers are different from the detection sequence. When working + * with the analog switch, we need to "map" from the detection sequence + * over to the board's logical controller number. This mapping sequence + * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical + * unit 3, the second (which is the master) is logical unit 0, etc. + * We need to maintain the status of the analog switch (which of the 16 + * cameras is connected to which of the 4 controllers). Rather than + * add to the bttv structure for this, we use the data reserved for + * the mbox (unused for this card type). + */ + +/* + * First a routine to set the analog switch, which controls which camera + * is routed to which controller. The switch comprises an X-address + * (gpio bits 0-3, representing the camera, ranging from 0-15), and a + * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3). + * A data value (gpio bit 7) of '1' enables the switch, and '0' disables + * the switch. A STROBE bit (gpio bit 8) latches the data value into the + * specified address. The idea is to set the address and data, then bring + * STROBE high, and finally bring STROBE back to low. + */ +static void kodicom4400r_write(struct bttv *btv, + unsigned char xaddr, + unsigned char yaddr, + unsigned char data) { + unsigned int udata; + + udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf); + gpio_bits(0x1ff, udata); /* write ADDR and DAT */ + gpio_bits(0x1ff, udata | (1 << 8)); /* strobe high */ + gpio_bits(0x1ff, udata); /* strobe low */ +} + +/* + * Next the mux select. Both the "master" and "slave" 'cards' (controllers) + * use this routine. The routine finds the "master" for the card, maps + * the controller number from the detected position over to the logical + * number, writes the appropriate data to the analog switch, and housekeeps + * the local copy of the switch information. The parameter 'input' is the + * requested camera number (0 - 15). + */ +static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input) +{ + char *sw_status; + int xaddr, yaddr; + struct bttv *mctlr; + static unsigned char map[4] = {3, 0, 2, 1}; + + mctlr = master[btv->c.nr]; + if (mctlr == NULL) { /* ignore if master not yet detected */ + return; + } + yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */ + yaddr = map[yaddr]; + sw_status = (char *)(&mctlr->mbox_we); + xaddr = input & 0xf; + /* Check if the controller/camera pair has changed, else ignore */ + if (sw_status[yaddr] != xaddr) + { + /* "open" the old switch, "close" the new one, save the new */ + kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0); + sw_status[yaddr] = xaddr; + kodicom4400r_write(mctlr, xaddr, yaddr, 1); + } +} + +/* + * During initialisation, we need to reset the analog switch. We + * also preset the switch to map the 4 connectors on the card to the + * *user's* (see above description of kodicom4400r_muxsel) channels + * 0 through 3 + */ +static void kodicom4400r_init(struct bttv *btv) +{ + char *sw_status = (char *)(&btv->mbox_we); + int ix; + + gpio_inout(0x0003ff, 0x0003ff); + gpio_write(1 << 9); /* reset MUX */ + gpio_write(0); + /* Preset camera 0 to the 4 controllers */ + for (ix=0; ix<4; ix++) { + sw_status[ix] = ix; + kodicom4400r_write(btv, ix, ix, 1); + } + /* + * Since this is the "master", we need to set up the + * other three controller chips' pointers to this structure + * for later use in the muxsel routine. + */ + if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3)) + return; + master[btv->c.nr-1] = btv; + master[btv->c.nr] = btv; + master[btv->c.nr+1] = btv; + master[btv->c.nr+2] = btv; +} + // The Grandtec X-Guard framegrabber card uses two Dual 4-channel // video multiplexers to provide up to 16 video inputs. These // multiplexers are controlled by the lower 8 GPIO pins of the Index: linux-2.6.11/drivers/media/video/bttv-driver.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/bttv-driver.c 2005-03-07 10:14:53.000000000 +0100 +++ linux-2.6.11/drivers/media/video/bttv-driver.c 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - $Id: bttv-driver.c,v 1.34 2005/01/07 13:11:19 kraxel Exp $ + $Id: bttv-driver.c,v 1.37 2005/02/21 13:57:59 kraxel Exp $ bttv - Bt848 frame grabber driver @@ -3167,6 +3167,82 @@ static struct video_device radio_templat }; /* ----------------------------------------------------------------------- */ +/* some debug code */ + +int bttv_risc_decode(u32 risc) +{ + static char *instr[16] = { + [ BT848_RISC_WRITE >> 28 ] = "write", + [ BT848_RISC_SKIP >> 28 ] = "skip", + [ BT848_RISC_WRITEC >> 28 ] = "writec", + [ BT848_RISC_JUMP >> 28 ] = "jump", + [ BT848_RISC_SYNC >> 28 ] = "sync", + [ BT848_RISC_WRITE123 >> 28 ] = "write123", + [ BT848_RISC_SKIP123 >> 28 ] = "skip123", + [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23", + }; + static int incr[16] = { + [ BT848_RISC_WRITE >> 28 ] = 2, + [ BT848_RISC_JUMP >> 28 ] = 2, + [ BT848_RISC_SYNC >> 28 ] = 2, + [ BT848_RISC_WRITE123 >> 28 ] = 5, + [ BT848_RISC_SKIP123 >> 28 ] = 2, + [ BT848_RISC_WRITE1S23 >> 28 ] = 3, + }; + static char *bits[] = { + "be0", "be1", "be2", "be3/resync", + "set0", "set1", "set2", "set3", + "clr0", "clr1", "clr2", "clr3", + "irq", "res", "eol", "sol", + }; + int i; + + printk("0x%08x [ %s", risc, + instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + if (risc & (1 << (i + 12))) + printk(" %s",bits[i]); + printk(" count=%d ]\n", risc & 0xfff); + return incr[risc >> 28] ? incr[risc >> 28] : 1; +} + +void bttv_risc_disasm(struct bttv *btv, + struct btcx_riscmem *risc) +{ + unsigned int i,j,n; + + printk("%s: risc disasm: %p [dma=0x%08lx]\n", + btv->c.name, risc->cpu, (unsigned long)risc->dma); + for (i = 0; i < (risc->size >> 2); i += n) { + printk("%s: 0x%lx: ", btv->c.name, + (unsigned long)(risc->dma + (i<<2))); + n = bttv_risc_decode(risc->cpu[i]); + for (j = 1; j < n; j++) + printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n", + btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)), + risc->cpu[i+j], j); + if (0 == risc->cpu[i]) + break; + } +} + +static void bttv_print_riscaddr(struct bttv *btv) +{ + printk(" main: %08Lx\n", + (unsigned long long)btv->main.dma); + printk(" vbi : o=%08Lx e=%08Lx\n", + btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, + btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); + printk(" cap : o=%08Lx e=%08Lx\n", + btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, + btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); + printk(" scr : o=%08Lx e=%08Lx\n", + btv->screen ? (unsigned long long)btv->screen->top.dma : 0, + btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); + bttv_risc_disasm(btv, &btv->main); +} + +/* ----------------------------------------------------------------------- */ /* irq handler */ static char *irq_name[] = { @@ -3204,21 +3280,6 @@ static void bttv_print_irqbits(u32 print } } -static void bttv_print_riscaddr(struct bttv *btv) -{ - printk(" main: %08Lx\n", - (unsigned long long)btv->main.dma); - printk(" vbi : o=%08Lx e=%08Lx\n", - btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, - btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); - printk(" cap : o=%08Lx e=%08Lx\n", - btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, - btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); - printk(" scr : o=%08Lx e=%08Lx\n", - btv->screen ? (unsigned long long)btv->screen->top.dma : 0, - btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); -} - static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc) { printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", @@ -3921,7 +3982,7 @@ static void __devexit bttv_remove(struct return; } -static int bttv_suspend(struct pci_dev *pci_dev, u32 state) +static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) { struct bttv *btv = pci_get_drvdata(pci_dev); struct bttv_buffer_set idle; Index: linux-2.6.11/drivers/media/video/bttv-gpio.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/bttv-gpio.c 2005-03-07 10:14:52.000000000 +0100 +++ linux-2.6.11/drivers/media/video/bttv-gpio.c 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - $Id: bttv-gpio.c,v 1.6 2004/11/03 09:04:50 kraxel Exp $ + $Id: bttv-gpio.c,v 1.7 2005/02/16 12:14:10 kraxel Exp $ bttv-gpio.c -- gpio sub drivers @@ -94,6 +94,7 @@ int bttv_sub_del_devices(struct bttv_cor list_for_each_safe(item,save,&core->subs) { sub = list_entry(item,struct bttv_sub_device,list); + list_del(&sub->list); device_unregister(&sub->dev); } return 0; @@ -113,20 +114,6 @@ void bttv_gpio_irq(struct bttv_core *cor } } -void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach) -{ - struct bttv_sub_driver *drv; - struct bttv_sub_device *dev; - struct list_head *item; - - list_for_each(item,&core->subs) { - dev = list_entry(item,struct bttv_sub_device,list); - drv = to_bttv_sub_drv(dev->dev.driver); - if (drv && drv->i2c_info) - drv->i2c_info(dev,client,attach); - } -} - /* ----------------------------------------------------------------------- */ /* external: sub-driver register/unregister */ Index: linux-2.6.11/drivers/media/video/bttv-i2c.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/bttv-i2c.c 2005-03-07 10:12:39.000000000 +0100 +++ linux-2.6.11/drivers/media/video/bttv-i2c.c 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - $Id: bttv-i2c.c,v 1.17 2004/12/14 15:33:30 kraxel Exp $ + $Id: bttv-i2c.c,v 1.18 2005/02/16 12:14:10 kraxel Exp $ bttv-i2c.c -- all the i2c code is here @@ -39,7 +39,6 @@ static struct i2c_adapter bttv_i2c_adap_ static struct i2c_client bttv_i2c_client_template; static int attach_inform(struct i2c_client *client); -static int detach_inform(struct i2c_client *client); static int i2c_debug = 0; static int i2c_hw = 0; @@ -112,7 +111,6 @@ static struct i2c_adapter bttv_i2c_adap_ I2C_DEVNAME("bt848"), .id = I2C_HW_B_BT848, .client_register = attach_inform, - .client_unregister = detach_inform, }; /* ----------------------------------------------------------------------- */ @@ -290,7 +288,6 @@ static struct i2c_adapter bttv_i2c_adap_ .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, .algo = &bttv_algo, .client_register = attach_inform, - .client_unregister = detach_inform, }; /* ----------------------------------------------------------------------- */ @@ -305,22 +302,12 @@ static int attach_inform(struct i2c_clie if (btv->pinnacle_id != UNSET) bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, &btv->pinnacle_id); - bttv_i2c_info(&btv->c, client, 1); - if (bttv_debug) printk("bttv%d: i2c attach [client=%s]\n", btv->c.nr, i2c_clientname(client)); return 0; } -static int detach_inform(struct i2c_client *client) -{ - struct bttv *btv = i2c_get_adapdata(client->adapter); - - bttv_i2c_info(&btv->c, client, 0); - return 0; -} - void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) { if (0 != btv->i2c_rc) Index: linux-2.6.11/drivers/media/video/bttv.h =================================================================== --- linux-2.6.11.orig/drivers/media/video/bttv.h 2005-03-07 10:12:47.000000000 +0100 +++ linux-2.6.11/drivers/media/video/bttv.h 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: bttv.h,v 1.14 2005/01/07 13:11:19 kraxel Exp $ + * $Id: bttv.h,v 1.17 2005/02/22 14:06:32 kraxel Exp $ * * bttv - Bt848 frame grabber driver * @@ -134,6 +134,7 @@ #define BTTV_APAC_VIEWCOMP 0x7f #define BTTV_DVICO_DVBT_LITE 0x80 #define BTTV_TIBET_CS16 0x83 +#define BTTV_KODICOM_4400R 0x84 /* i2c address list */ #define I2C_TSA5522 0xc2 @@ -302,8 +303,6 @@ struct bttv_sub_driver { struct device_driver drv; char wanted[BUS_ID_SIZE]; void (*gpio_irq)(struct bttv_sub_device *sub); - void (*i2c_info)(struct bttv_sub_device *sub, - struct i2c_client *client, int attach); }; #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) Index: linux-2.6.11/drivers/media/video/bttvp.h =================================================================== --- linux-2.6.11.orig/drivers/media/video/bttvp.h 2005-03-07 10:16:20.000000000 +0100 +++ linux-2.6.11/drivers/media/video/bttvp.h 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - $Id: bttvp.h,v 1.15 2004/12/14 15:33:30 kraxel Exp $ + $Id: bttvp.h,v 1.17 2005/02/16 12:14:10 kraxel Exp $ bttv - Bt848 frame grabber driver @@ -209,7 +209,6 @@ extern struct bus_type bttv_sub_bus_type int bttv_sub_add_device(struct bttv_core *core, char *name); int bttv_sub_del_devices(struct bttv_core *core); void bttv_gpio_irq(struct bttv_core *core); -void bttv_i2c_info(struct bttv_core *core, struct i2c_client *client, int attach); /* ---------------------------------------------------------- */ Index: linux-2.6.11/drivers/media/video/cx88/Makefile =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/Makefile 2005-03-07 10:13:03.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/Makefile 2005-03-08 10:33:15.000000000 +0100 @@ -1,4 +1,5 @@ -cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o +cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \ + cx88-input.o cx8800-objs := cx88-video.o cx88-vbi.o cx8802-objs := cx88-mpeg.o Index: linux-2.6.11/drivers/media/video/cx88/cx88-blackbird.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88-blackbird.c 2005-03-07 10:15:01.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88-blackbird.c 2005-03-08 10:33:20.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: cx88-blackbird.c,v 1.17 2004/11/07 13:17:15 kraxel Exp $ + * $Id: cx88-blackbird.c,v 1.26 2005/03/07 15:58:05 kraxel Exp $ * * Support for a cx23416 mpeg encoder via cx2388x host port. * "blackbird" reference design. @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -207,10 +208,6 @@ static int register_write(struct cx88_co cx_read(P1_RADDR0); return wait_ready_gpio0_bit1(core,1); -#if 0 - udelay(1000); /* without this, things don't go right (subsequent memory_write()'s don't get through */ - /* ? would this be safe here? set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); */ -#endif } @@ -283,7 +280,7 @@ static int blackbird_api_cmd(struct cx88 timeout = jiffies + msecs_to_jiffies(10); for (;;) { memory_read(dev->core, dev->mailbox, &flag); - if (0 == (flag & 4)) + if (0 != (flag & 4)) break; if (time_after(jiffies,timeout)) { dprintk(0, "ERROR: API Mailbox timeout\n"); @@ -324,7 +321,7 @@ static int blackbird_find_mailbox(struct signaturecnt = 0; if (4 == signaturecnt) { dprintk(1, "Mailbox signature found\n"); - return i; + return i+1; } } dprintk(0, "Mailbox signature values not found!\n"); @@ -427,7 +424,8 @@ static void blackbird_codec_settings(str blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAMERATE, 1, 0, 0); /* assign frame size */ - blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0, 480, 720); + blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0, + dev->height, dev->width); /* assign aspect ratio */ blackbird_api_cmd(dev, IVTV_API_ASSIGN_ASPECT_RATIO, 1, 0, 2); @@ -629,8 +627,8 @@ static int mpeg_do_ioctl(struct inode *i memset(f,0,sizeof(*f)); f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->fmt.pix.width = 720; - f->fmt.pix.height = 576; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = 1024 * 512 /* FIXME: BUFFER_SIZE */; } @@ -694,6 +692,10 @@ static int mpeg_open(struct inode *inode file->private_data = fh; fh->dev = dev; + /* FIXME: locking against other video device */ + cx88_set_scale(dev->core, dev->width, dev->height, + V4L2_FIELD_INTERLACED); + videobuf_queue_init(&fh->mpegq, &blackbird_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, @@ -715,6 +717,7 @@ static int mpeg_release(struct inode *in if (fh->mpegq.reading) videobuf_read_stop(&fh->mpegq); + videobuf_mmap_free(&fh->mpegq); file->private_data = NULL; kfree(fh); return 0; @@ -821,6 +824,8 @@ static int __devinit blackbird_probe(str memset(dev,0,sizeof(*dev)); dev->pci = pci_dev; dev->core = core; + dev->width = 720; + dev->height = 480; err = cx8802_init_common(dev); if (0 != err) @@ -852,6 +857,8 @@ static void __devexit blackbird_remove(s /* common */ cx8802_fini_common(dev); + cx88_core_put(dev->core,dev->pci); + kfree(dev); } static struct pci_device_id cx8802_pci_tbl[] = { @@ -885,7 +892,7 @@ static int blackbird_init(void) printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif - return pci_module_init(&blackbird_pci_driver); + return pci_register_driver(&blackbird_pci_driver); } static void blackbird_fini(void) Index: linux-2.6.11/drivers/media/video/cx88/cx88-cards.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88-cards.c 2005-03-07 10:14:56.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88-cards.c 2005-03-08 10:33:15.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: cx88-cards.c,v 1.47 2004/11/03 09:04:50 kraxel Exp $ + * $Id: cx88-cards.c,v 1.66 2005/03/04 09:12:23 kraxel Exp $ * * device driver for Conexant 2388x based TV cards * card-specific stuff. @@ -26,14 +26,7 @@ #include #include -#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) -# define WITH_DVB 1 -#endif - #include "cx88.h" -#ifdef WITH_DVB -#include "cx22702.h" -#endif /* ------------------------------------------------------------------ */ /* board config info */ @@ -59,6 +52,7 @@ struct cx88_board cx88_boards[] = { [CX88_BOARD_HAUPPAUGE] = { .name = "Hauppauge WinTV 34xxx models", .tuner_type = UNSET, + .tda9887_conf = TDA9887_PRESENT, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -91,7 +85,7 @@ struct cx88_board cx88_boards[] = { }, [CX88_BOARD_PIXELVIEW] = { .name = "PixelView", - .tuner_type = UNSET, + .tuner_type = 5, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -126,7 +120,7 @@ struct cx88_board cx88_boards[] = { .gpio0 = 0x03fe, }}, }, - [CX88_BOARD_WINFAST2000XP] = { + [CX88_BOARD_WINFAST2000XP_EXPERT] = { .name = "Leadtek Winfast 2000XP Expert", .tuner_type = 44, .tda9887_conf = TDA9887_PRESENT, @@ -217,26 +211,55 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - }}, + .gpio0 = 0x0035e700, + .gpio1 = 0x00003004, + .gpio2 = 0x0035e700, + .gpio3 = 0x02000000, + },{ + + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0035c700, + .gpio1 = 0x00003004, + .gpio2 = 0x0035c700, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0035c700, + .gpio1 = 0x0035c700, + .gpio2 = 0x02000000, + .gpio3 = 0x02000000, + }}, .radio = { - .type = CX88_RADIO, - }, + .type = CX88_RADIO, + .gpio0 = 0x0035d700, + .gpio1 = 0x00007004, + .gpio2 = 0x0035d700, + .gpio3 = 0x02000000, + }, }, [CX88_BOARD_LEADTEK_PVR2000] = { + // gpio values for PAL version from regspy by DScaler .name = "Leadtek PVR 2000", .tuner_type = 38, + .tda9887_conf = TDA9887_PRESENT, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, + .gpio0 = 0x0000bde6, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, + .gpio0 = 0x0000bde6, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, + .gpio0 = 0x0000bde6, }}, .radio = { .type = CX88_RADIO, + .gpio0 = 0x0000bd62, }, .blackbird = 1, }, @@ -320,14 +343,15 @@ struct cx88_board cx88_boards[] = { .name = "KWorld/VStream XPert DVB-T", .tuner_type = TUNER_ABSENT, .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, + .gpio0 = 0x0700, + .gpio2 = 0x0101, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, + .gpio0 = 0x0700, + .gpio2 = 0x0101, }}, .dvb = 1, }, @@ -452,6 +476,131 @@ struct cx88_board cx88_boards[] = { }}, .dvb = 1, }, + [CX88_BOARD_DNTV_LIVE_DVB_T] = { + .name = "digitalnow DNTV Live! DVB-T", + .tuner_type = TUNER_ABSENT, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00000700, + .gpio2 = 0x00000101, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00000700, + .gpio2 = 0x00000101, + }}, + .dvb = 1, + }, + [CX88_BOARD_PCHDTV_HD3000] = { + .name = "pcHDTV HD3000 HDTV", + .tuner_type = TUNER_THOMSON_DTT7610, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00008484, + .gpio1 = 0x00000000, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00008400, + .gpio1 = 0x00000000, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00008400, + .gpio1 = 0x00000000, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + }}, + .radio = { + .type = CX88_RADIO, + .vmux = 2, + .gpio0 = 0x00008400, + .gpio1 = 0x00000000, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + }, + .dvb = 1, + }, + [CX88_BOARD_HAUPPAUGE_ROSLYN] = { + // entry added by Kaustubh D. Bhalerao + // GPIO values obtained from regspy, courtesy Sean Covel + .name = "Hauppauge WinTV 28xxx (Roslyn) models", + .tuner_type = UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xed12, // internal decoder + .gpio2 = 0x00ff, + },{ + .type = CX88_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, // mono from tuner chip + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xed92, + .gpio2 = 0x00ff, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xed96, + .gpio2 = 0x00ff, + }, + .blackbird = 1, + }, + [CX88_BOARD_DIGITALLOGIC_MEC] = { + /* params copied over from Leadtek PVR 2000 */ + .name = "Digital-Logic MICROSPACE Entertainment Center (MEC)", + /* not sure yet about the tuner type */ + .tuner_type = 38, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0000bde6, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0000bde6, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0000bde6, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0000bd62, + }, + .blackbird = 1, + }, + [CX88_BOARD_IODATA_GVBCTV7E] = { + .name = "IODATA GV/BCTV7E", + .tuner_type = TUNER_PHILIPS_FQ1286, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 1, + .gpio1 = 0x0000e03f, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 2, + .gpio1 = 0x0000e07f, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 3, + .gpio1 = 0x0000e07f, + }} + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -482,11 +631,11 @@ struct cx88_subid cx88_subids[] = { },{ .subvendor = 0x107d, .subdevice = 0x6611, - .card = CX88_BOARD_WINFAST2000XP, + .card = CX88_BOARD_WINFAST2000XP_EXPERT, },{ .subvendor = 0x107d, .subdevice = 0x6613, /* NTSC */ - .card = CX88_BOARD_WINFAST2000XP, + .card = CX88_BOARD_WINFAST2000XP_EXPERT, },{ .subvendor = 0x107d, .subdevice = 0x6620, @@ -543,6 +692,30 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x18AC, .subdevice = 0xDB10, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, + },{ + .subvendor = 0x1554, + .subdevice = 0x4811, + .card = CX88_BOARD_PIXELVIEW, + },{ + .subvendor = 0x7063, + .subdevice = 0x3000, /* HD-3000 card */ + .card = CX88_BOARD_PCHDTV_HD3000, + },{ + .subvendor = 0x17DE, + .subdevice = 0xA8A6, + .card = CX88_BOARD_DNTV_LIVE_DVB_T, + },{ + .subvendor = 0x0070, + .subdevice = 0x2801, + .card = CX88_BOARD_HAUPPAUGE_ROSLYN, + },{ + .subvendor = 0x14F1, + .subdevice = 0x0342, + .card = CX88_BOARD_DIGITALLOGIC_MEC, + },{ + .subvendor = 0x10fc, + .subdevice = 0xd035, + .card = CX88_BOARD_IODATA_GVBCTV7E, } }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -552,7 +725,7 @@ const unsigned int cx88_idcount = ARRAY_ static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) { - /* This is just for the Winfast 2000 XP board ATM; I don't have data on + /* This is just for the "Winfast 2000XP Expert" board ATM; I don't have data on * any others. * * Byte 0 is 1 on the NTSC board. @@ -569,108 +742,27 @@ static void __devinit leadtek_eeprom(str core->has_radio = 1; core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38; - printk(KERN_INFO "%s: Leadtek Winfast 2000 XP config: " + printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: " "tuner=%d, eeprom[0]=0x%02x\n", core->name, core->tuner_type, eeprom_data[0]); } /* ----------------------------------------------------------------------- */ -/* some hauppauge specific stuff */ - -static struct { - int id; - char *name; -} hauppauge_tuner[] __devinitdata = { - { TUNER_ABSENT, "" }, - { TUNER_ABSENT, "External" }, - { TUNER_ABSENT, "Unspecified" }, - { TUNER_PHILIPS_PAL, "Philips FI1216" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, - { TUNER_PHILIPS_PAL_DK,"Philips FI1256" }, - { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, - { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" }, - { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, - { TUNER_TEMIC_PAL, "Temic 4002FH5" }, - { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, - { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, - { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" }, - { TUNER_PHILIPS_PAL, "Philips FM1216" }, - { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FM1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, - { TUNER_PHILIPS_PAL_DK,"Philips FM1256" }, - { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, - { TUNER_ABSENT, "Samsung TCPN9082D" }, - { TUNER_ABSENT, "Samsung TCPM9092P" }, - { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, - { TUNER_ABSENT, "Samsung TCPN9085D" }, - { TUNER_ABSENT, "Samsung TCPB9085P" }, - { TUNER_ABSENT, "Samsung TCPL9091P" }, - { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, - { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, - { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, - { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ - { TUNER_ABSENT, "Philips FI1256MP" }, - { TUNER_ABSENT, "Samsung TCPQ9091P" }, - { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" }, - { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, - { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, - { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, - { TUNER_ABSENT, "Philips TD1536D_FH_44"}, - { TUNER_LG_NTSC_FM, "LG TPI8NSR01F"}, - { TUNER_LG_PAL_FM, "LG TPI8PSB01D"}, - { TUNER_LG_PAL, "LG TPI8PSB11D"}, - { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, - { TUNER_LG_PAL_I, "LG TAPC-I701D"} -}; static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) { - unsigned int blk2,tuner,radio,model; - - if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0) { - printk(KERN_WARNING "%s: Hauppauge eeprom: invalid\n", - core->name); - return; - } - - /* Block 2 starts after len+3 bytes header */ - blk2 = eeprom_data[1] + 3; - - /* decode + use some config infos */ - model = eeprom_data[12] << 8 | eeprom_data[11]; - tuner = eeprom_data[9]; - radio = eeprom_data[blk2-1] & 0x01; - - if (tuner < ARRAY_SIZE(hauppauge_tuner)) - core->tuner_type = hauppauge_tuner[tuner].id; - if (radio) - core->has_radio = 1; + struct tveeprom tv; - printk(KERN_INFO "%s: hauppauge eeprom: model=%d, " - "tuner=%s (%d), radio=%s\n", - core->name, model, (tuner < ARRAY_SIZE(hauppauge_tuner) - ? hauppauge_tuner[tuner].name : "?"), - core->tuner_type, radio ? "yes" : "no"); + tveeprom_hauppauge_analog(&tv, eeprom_data); + core->tuner_type = tv.tuner_type; + core->has_radio = tv.has_radio; } -#ifdef WITH_DVB static int hauppauge_eeprom_dvb(struct cx88_core *core, u8 *ee) { int model; int tuner; - char *tname; /* Make sure we support the board model */ model = ee[0x1f] << 24 | ee[0x1e] << 16 | ee[0x1d] << 8 | ee[0x1c]; @@ -689,26 +781,18 @@ static int hauppauge_eeprom_dvb(struct c /* Make sure we support the tuner */ tuner = ee[0x2d]; switch(tuner) { - case 0x4B: - tname = "Thomson DTT 7595"; - core->pll_type = PLLTYPE_DTT7595; - break; - case 0x4C: - tname = "Thomson DTT 7592"; - core->pll_type = PLLTYPE_DTT7592; + case 0x4B: /* dtt 7595 */ + case 0x4C: /* dtt 7592 */ break; default: printk("%s: error: unknown hauppauge tuner 0x%02x\n", core->name, tuner); return -ENODEV; } - printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%s (%d)\n", - core->name, model, tname, tuner); - - core->pll_addr = 0x61; - core->demod_addr = 0x43; + printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%d\n", + core->name, model, tuner); + return 0; } -#endif /* ----------------------------------------------------------------------- */ /* some GDI (was: Modular Technology) specific stuff */ @@ -763,36 +847,6 @@ static void gdi_eeprom(struct cx88_core /* ----------------------------------------------------------------------- */ -static int -i2c_eeprom(struct i2c_client *c, unsigned char *eedata, int len) -{ - unsigned char buf; - int err; - - c->addr = 0xa0 >> 1; - buf = 0; - if (1 != (err = i2c_master_send(c,&buf,1))) { - printk(KERN_INFO "cx88: Huh, no eeprom present (err=%d)?\n", - err); - return -1; - } - if (len != (err = i2c_master_recv(c,eedata,len))) { - printk(KERN_WARNING "cx88: i2c eeprom read error (err=%d)\n", - err); - return -1; - } -#if 0 - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "cx88 ee: %02x:",i); - printk(" %02x",eedata[i]); - if (15 == (i % 16)) - printk("\n"); - } -#endif - return 0; -} - void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) { int i; @@ -823,41 +877,46 @@ void cx88_card_setup(struct cx88_core *c { static u8 eeprom[128]; + if (0 == core->i2c_rc) { + core->i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); + } + switch (core->board) { case CX88_BOARD_HAUPPAUGE: + case CX88_BOARD_HAUPPAUGE_ROSLYN: if (0 == core->i2c_rc) - i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom)); - hauppauge_eeprom(core,eeprom+8); + hauppauge_eeprom(core,eeprom+8); break; case CX88_BOARD_GDI: if (0 == core->i2c_rc) - i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom)); - gdi_eeprom(core,eeprom); + gdi_eeprom(core,eeprom); break; - case CX88_BOARD_WINFAST2000XP: + case CX88_BOARD_WINFAST2000XP_EXPERT: if (0 == core->i2c_rc) - i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom)); - leadtek_eeprom(core,eeprom); + leadtek_eeprom(core,eeprom); + break; + case CX88_BOARD_HAUPPAUGE_DVB_T1: + if (0 == core->i2c_rc) + hauppauge_eeprom_dvb(core,eeprom); break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: - /* Tuner reset is hooked to the tuner out of reset */ + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: + /* GPIO0:0 is hooked to mt352 reset pin */ cx_set(MO_GP0_IO, 0x00000101); cx_clear(MO_GP0_IO, 0x00000001); msleep(1); cx_set(MO_GP0_IO, 0x00000101); break; -#ifdef WITH_DVB - case CX88_BOARD_HAUPPAUGE_DVB_T1: - if (0 == core->i2c_rc) - i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom)); - hauppauge_eeprom_dvb(core,eeprom); - break; - case CX88_BOARD_CONEXANT_DVB_T1: - core->pll_type = PLLTYPE_DTT7579; - core->pll_addr = 0x60; - core->demod_addr = 0x43; + case CX88_BOARD_KWORLD_DVB_T: + case CX88_BOARD_DNTV_LIVE_DVB_T: + cx_set(MO_GP0_IO, 0x00000707); + cx_set(MO_GP2_IO, 0x00000101); + cx_clear(MO_GP2_IO, 0x00000001); + msleep(1); + cx_clear(MO_GP0_IO, 0x00000007); + cx_set(MO_GP2_IO, 0x00000101); break; -#endif } if (cx88_boards[core->board].radio.type == CX88_RADIO) core->has_radio = 1; Index: linux-2.6.11/drivers/media/video/cx88/cx88-core.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88-core.c 2005-03-07 10:13:16.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88-core.c 2005-03-08 10:33:15.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: cx88-core.c,v 1.15 2004/10/25 11:26:36 kraxel Exp $ + * $Id: cx88-core.c,v 1.24 2005/01/19 12:01:55 kraxel Exp $ * * device driver for Conexant 2388x based TV cards * driver core @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,10 @@ static unsigned int nicam = 0; module_param(nicam,int,0644); MODULE_PARM_DESC(nicam,"tv audio is nicam"); +static unsigned int nocomb = 0; +module_param(nocomb,int,0644); +MODULE_PARM_DESC(nocomb,"disable comb filter"); + #define dprintk(level,fmt, arg...) if (core_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) @@ -462,6 +467,7 @@ int cx88_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } +#if 0 /* currently unused, but useful for debugging */ void cx88_risc_disasm(struct cx88_core *core, struct btcx_riscmem *risc) { @@ -479,6 +485,7 @@ void cx88_risc_disasm(struct cx88_core * break; } } +#endif void cx88_sram_channel_dump(struct cx88_core *core, struct sram_channel *ch) @@ -579,10 +586,19 @@ void cx88_print_irqbits(char *name, char /* ------------------------------------------------------------------ */ -void cx88_irq(struct cx88_core *core, u32 status, u32 mask) +int cx88_core_irq(struct cx88_core *core, u32 status) { - cx88_print_irqbits(core->name, "irq pci", - cx88_pci_irqs, status, mask); + int handled = 0; + + if (status & (1<<18)) { + cx88_ir_irq(core); + handled++; + } + if (!handled) + cx88_print_irqbits(core->name, "irq pci", + cx88_pci_irqs, status, + core->pci_irqmask); + return handled; } void cx88_wakeup(struct cx88_core *core, @@ -800,6 +816,8 @@ int cx88_set_scale(struct cx88_core *cor value |= (1 << 0); // 3-tap interpolation if (width < 193) value |= (1 << 1); // 5-tap interpolation + if (nocomb) + value |= (3 << 5); // disable comb filter cx_write(MO_FILTER_EVEN, value); cx_write(MO_FILTER_ODD, value); @@ -887,8 +905,8 @@ static int set_tvaudio(struct cx88_core cx88_set_tvaudio(core); // cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); - cx_write(MO_AUDD_LNGTH, 128/8); /* fifo size */ - cx_write(MO_AUDR_LNGTH, 128/8); /* fifo size */ + cx_write(MO_AUDD_LNGTH, 128); /* fifo size */ + cx_write(MO_AUDR_LNGTH, 128); /* fifo size */ cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */ return 0; } @@ -969,6 +987,9 @@ int cx88_set_tvnorm(struct cx88_core *co cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */ norm_vbipack(norm))); + // this is needed as well to set all tvnorm parameter + cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED); + // audio set_tvaudio(core); @@ -1105,9 +1126,10 @@ struct cx88_core* cx88_core_get(struct p goto fail_unlock; memset(core,0,sizeof(*core)); + atomic_inc(&core->refcount); core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); - atomic_inc(&core->refcount); + core->pci_irqmask = 0x00fc00; core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); @@ -1150,6 +1172,7 @@ struct cx88_core* cx88_core_get(struct p cx88_reset(core); cx88_i2c_init(core,pci); cx88_card_setup(core); + cx88_ir_init(core,pci); up(&devlist); return core; @@ -1170,6 +1193,7 @@ void cx88_core_put(struct cx88_core *cor return; down(&devlist); + cx88_ir_fini(core); if (0 == core->i2c_rc) i2c_bit_del_bus(&core->i2c_adap); list_del(&core->devlist); @@ -1187,7 +1211,7 @@ EXPORT_SYMBOL(cx88_vid_irqs); EXPORT_SYMBOL(cx88_mpeg_irqs); EXPORT_SYMBOL(cx88_print_irqbits); -EXPORT_SYMBOL(cx88_irq); +EXPORT_SYMBOL(cx88_core_irq); EXPORT_SYMBOL(cx88_wakeup); EXPORT_SYMBOL(cx88_reset); EXPORT_SYMBOL(cx88_shutdown); @@ -1197,8 +1221,6 @@ EXPORT_SYMBOL(cx88_risc_databuffer); EXPORT_SYMBOL(cx88_risc_stopper); EXPORT_SYMBOL(cx88_free_buffer); -EXPORT_SYMBOL(cx88_risc_disasm); - EXPORT_SYMBOL(cx88_sram_channels); EXPORT_SYMBOL(cx88_sram_channel_setup); EXPORT_SYMBOL(cx88_sram_channel_dump); Index: linux-2.6.11/drivers/media/video/cx88/cx88-dvb.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88-dvb.c 2005-03-07 10:14:23.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88-dvb.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: cx88-dvb.c,v 1.19 2004/11/07 14:44:59 kraxel Exp $ + * $Id: cx88-dvb.c,v 1.31 2005/03/07 15:58:05 kraxel Exp $ * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines @@ -30,10 +30,20 @@ #include #include +/* those two frontends need merging via linuxtv cvs ... */ +#define HAVE_CX22702 1 +#define HAVE_OR51132 1 + #include "cx88.h" -#include "cx22702.h" +#include "dvb-pll.h" #include "mt352.h" -#include "mt352_priv.h" /* FIXME */ +#include "mt352_priv.h" +#if HAVE_CX22702 +# include "cx22702.h" +#endif +#if HAVE_OR51132 +# include "or51132.h" +#endif MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); MODULE_AUTHOR("Chris Pascoe "); @@ -110,111 +120,144 @@ static int dvico_fusionhdtv_demod_init(s return 0; } -#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - -static int lg_z201_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params, u8* pllbuf) +static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe) { - u32 div; - unsigned char cp = 0; - unsigned char bs = 0; - - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency < 542000000) cp = 0xbc; - else if (params->frequency < 830000000) cp = 0xf4; - else cp = 0xfc; + static u8 clock_config [] = { 0x89, 0x38, 0x39 }; + static u8 reset [] = { 0x50, 0x80 }; + static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x40, 0x40 }; + static u8 dntv_extra[] = { 0xB5, 0x7A }; + static u8 capt_range_cfg[] = { 0x75, 0x32 }; - if (params->frequency == 0) bs = 0x03; - else if (params->frequency < 157500000) bs = 0x01; - else if (params->frequency < 443250000) bs = 0x02; - else bs = 0x04; + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(2000); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - pllbuf[0] = 0xC2; /* Note: non-linux standard PLL I2C address */ - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = cp; - pllbuf[4] = bs; + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + udelay(2000); + mt352_write(fe, dntv_extra, sizeof(dntv_extra)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); return 0; } -static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params, - u8* pllbuf) +static int mt352_pll_set(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params, + u8* pllbuf) { - u32 div; - unsigned char cp = 0; - unsigned char bs = 0; - - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency < 542000000) cp = 0xb4; - else if (params->frequency < 771000000) cp = 0xbc; - else cp = 0xf4; - - if (params->frequency == 0) bs = 0x03; - else if (params->frequency < 443250000) bs = 0x02; - else bs = 0x08; - - pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = cp; - pllbuf[4] = bs; + struct cx8802_dev *dev= fe->dvb->priv; + pllbuf[0] = dev->core->pll_addr << 1; + dvb_pll_configure(dev->core->pll_desc, pllbuf+1, + params->frequency, + params->u.ofdm.bandwidth); return 0; } -struct mt352_config dvico_fusionhdtv_dvbt1 = { +static struct mt352_config dvico_fusionhdtv = { .demod_address = 0x0F, .demod_init = dvico_fusionhdtv_demod_init, - .pll_set = lg_z201_pll_set, + .pll_set = mt352_pll_set, }; -struct mt352_config dvico_fusionhdtv_dvbt_plus = { - .demod_address = 0x0F, - .demod_init = dvico_fusionhdtv_demod_init, - .pll_set = thomson_dtt7579_pll_set, +static struct mt352_config dntv_live_dvbt_config = { + .demod_address = 0x0f, + .demod_init = dntv_live_dvbt_demod_init, + .pll_set = mt352_pll_set, +}; + +#if HAVE_CX22702 +static struct cx22702_config connexant_refboard_config = { + .demod_address = 0x43, + .pll_address = 0x60, + .pll_desc = &dvb_pll_thomson_dtt7579, +}; + +static struct cx22702_config hauppauge_novat_config = { + .demod_address = 0x43, + .pll_address = 0x61, + .pll_desc = &dvb_pll_thomson_dtt759x, }; +#endif + +#if HAVE_OR51132 +static int or51132_set_ts_param(struct dvb_frontend* fe, + int is_punctured) +{ + struct cx8802_dev *dev= fe->dvb->priv; + dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; + return 0; +} + +struct or51132_config pchdtv_hd3000 = { + .demod_address = 0x15, + .pll_address = 0x61, + .pll_desc = &dvb_pll_thomson_dtt7610, + .set_ts_params = or51132_set_ts_param, +}; +#endif static int dvb_register(struct cx8802_dev *dev) { /* init struct videobuf_dvb */ dev->dvb.name = dev->core->name; + dev->ts_gen_cntrl = 0x0c; /* init frontend */ switch (dev->core->board) { +#if HAVE_CX22702 case CX88_BOARD_HAUPPAUGE_DVB_T1: + dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config, + &dev->core->i2c_adap); + break; case CX88_BOARD_CONEXANT_DVB_T1: - dev->dvb.frontend = cx22702_create(&dev->core->i2c_adap, - dev->core->pll_addr, - dev->core->pll_type, - dev->core->demod_addr); + dev->dvb.frontend = cx22702_attach(&connexant_refboard_config, + &dev->core->i2c_adap); break; +#endif case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: - dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt1, + dev->core->pll_addr = 0x61; + dev->core->pll_desc = &dvb_pll_lg_z201; + dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv, &dev->core->i2c_adap); - if (dev->dvb.frontend) { - dev->dvb.frontend->ops->info.frequency_min = 174000000; - dev->dvb.frontend->ops->info.frequency_max = 862000000; - } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: - dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt_plus, + dev->core->pll_addr = 0x60; + dev->core->pll_desc = &dvb_pll_thomson_dtt7579; + dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv, + &dev->core->i2c_adap); + break; + case CX88_BOARD_KWORLD_DVB_T: + case CX88_BOARD_DNTV_LIVE_DVB_T: + dev->core->pll_addr = 0x61; + dev->core->pll_desc = &dvb_pll_unknown_1; + dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config, + &dev->core->i2c_adap); + break; +#if HAVE_OR51132 + case CX88_BOARD_PCHDTV_HD3000: + dev->dvb.frontend = or51132_attach(&pchdtv_hd3000, &dev->core->i2c_adap); - if (dev->dvb.frontend) { - dev->dvb.frontend->ops->info.frequency_min = 174000000; - dev->dvb.frontend->ops->info.frequency_max = 862000000; - } break; +#endif default: - printk("%s: FIXME: frontend handling not here yet ...\n", - dev->core->name); + printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n" + "%s: you might want to look out for patches here:\n" + "%s: http://dl.bytesex.org/patches/\n", + dev->core->name, dev->core->name, dev->core->name); break; } - if (NULL == dev->dvb.frontend) + if (NULL == dev->dvb.frontend) { + printk("%s: frontend initialization failed\n",dev->core->name); return -1; + } + + if (dev->core->pll_desc) { + dev->dvb.frontend->ops->info.frequency_min = dev->core->pll_desc->min; + dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max; + } /* Copy the board name into the DVB structure */ strlcpy(dev->dvb.frontend->ops->info.name, @@ -222,7 +265,7 @@ static int dvb_register(struct cx8802_de sizeof(dev->dvb.frontend->ops->info.name)); /* register everything */ - return videobuf_dvb_register(&dev->dvb); + return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev); } /* ----------------------------------------------------------- */ @@ -319,7 +362,7 @@ static int dvb_init(void) printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif - return pci_module_init(&dvb_pci_driver); + return pci_register_driver(&dvb_pci_driver); } static void dvb_fini(void) Index: linux-2.6.11/drivers/media/video/cx88/cx88-i2c.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88-i2c.c 2005-03-07 10:13:32.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88-i2c.c 2005-03-08 10:33:15.000000000 +0100 @@ -1,5 +1,5 @@ /* - $Id: cx88-i2c.c,v 1.18 2004/10/13 10:39:00 kraxel Exp $ + $Id: cx88-i2c.c,v 1.20 2005/02/15 15:59:35 kraxel Exp $ cx88-i2c.c -- all the i2c code is here @@ -25,6 +25,7 @@ */ #include +#include #include #include Index: linux-2.6.11/drivers/media/video/cx88/cx88-input.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/media/video/cx88/cx88-input.c 2005-03-08 10:33:15.000000000 +0100 @@ -0,0 +1,396 @@ +/* + * $Id: cx88-input.c,v 1.9 2005/03/04 09:12:23 kraxel Exp $ + * + * Device driver for GPIO attached remote control interfaces + * on Conexant 2388x based TV/DVB cards. + * + * Copyright (c) 2003 Pavel Machek + * Copyright (c) 2004 Gerd Knorr + * Copyright (c) 2004 Chris Pascoe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "cx88.h" + +/* ---------------------------------------------------------------------- */ + +/* DigitalNow DNTV Live DVB-T Remote */ +static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = { + [ 0x00 ] = KEY_ESC, // 'go up a level?' + [ 0x01 ] = KEY_KP1, // '1' + [ 0x02 ] = KEY_KP2, // '2' + [ 0x03 ] = KEY_KP3, // '3' + [ 0x04 ] = KEY_KP4, // '4' + [ 0x05 ] = KEY_KP5, // '5' + [ 0x06 ] = KEY_KP6, // '6' + [ 0x07 ] = KEY_KP7, // '7' + [ 0x08 ] = KEY_KP8, // '8' + [ 0x09 ] = KEY_KP9, // '9' + [ 0x0a ] = KEY_KP0, // '0' + [ 0x0b ] = KEY_TUNER, // 'tv/fm' + [ 0x0c ] = KEY_SEARCH, // 'scan' + [ 0x0d ] = KEY_STOP, // 'stop' + [ 0x0e ] = KEY_PAUSE, // 'pause' + [ 0x0f ] = KEY_LIST, // 'source' + + [ 0x10 ] = KEY_MUTE, // 'mute' + [ 0x11 ] = KEY_REWIND, // 'backward <<' + [ 0x12 ] = KEY_POWER, // 'power' + [ 0x13 ] = KEY_S, // 'snap' + [ 0x14 ] = KEY_AUDIO, // 'stereo' + [ 0x15 ] = KEY_CLEAR, // 'reset' + [ 0x16 ] = KEY_PLAY, // 'play' + [ 0x17 ] = KEY_ENTER, // 'enter' + [ 0x18 ] = KEY_ZOOM, // 'full screen' + [ 0x19 ] = KEY_FASTFORWARD, // 'forward >>' + [ 0x1a ] = KEY_CHANNELUP, // 'channel +' + [ 0x1b ] = KEY_VOLUMEUP, // 'volume +' + [ 0x1c ] = KEY_INFO, // 'preview' + [ 0x1d ] = KEY_RECORD, // 'record' + [ 0x1e ] = KEY_CHANNELDOWN, // 'channel -' + [ 0x1f ] = KEY_VOLUMEDOWN, // 'volume -' +}; + +/* ---------------------------------------------------------------------- */ + +/* IO-DATA BCTV7E Remote */ +static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = { + [ 0x40 ] = KEY_TV, // TV + [ 0x20 ] = KEY_RADIO, // FM + [ 0x60 ] = KEY_EPG, // EPG + [ 0x00 ] = KEY_POWER, // power + + [ 0x50 ] = KEY_KP1, // 1 + [ 0x30 ] = KEY_KP2, // 2 + [ 0x70 ] = KEY_KP3, // 3 + [ 0x10 ] = KEY_L, // Live + + [ 0x48 ] = KEY_KP4, // 4 + [ 0x28 ] = KEY_KP5, // 5 + [ 0x68 ] = KEY_KP6, // 6 + [ 0x08 ] = KEY_T, // Time Shift + + [ 0x58 ] = KEY_KP7, // 7 + [ 0x38 ] = KEY_KP8, // 8 + [ 0x78 ] = KEY_KP9, // 9 + [ 0x18 ] = KEY_PLAYPAUSE, // Play + + [ 0x44 ] = KEY_KP0, // 10 + [ 0x24 ] = KEY_ENTER, // 11 + [ 0x64 ] = KEY_ESC, // 12 + [ 0x04 ] = KEY_M, // Multi + + [ 0x54 ] = KEY_VIDEO, // VIDEO + [ 0x34 ] = KEY_CHANNELUP, // channel + + [ 0x74 ] = KEY_VOLUMEUP, // volume + + [ 0x14 ] = KEY_MUTE, // Mute + + [ 0x4c ] = KEY_S, // SVIDEO + [ 0x2c ] = KEY_CHANNELDOWN, // channel - + [ 0x6c ] = KEY_VOLUMEDOWN, // volume - + [ 0x0c ] = KEY_ZOOM, // Zoom + + [ 0x5c ] = KEY_PAUSE, // pause + [ 0x3c ] = KEY_C, // || (red) + [ 0x7c ] = KEY_RECORD, // recording + [ 0x1c ] = KEY_STOP, // stop + + [ 0x41 ] = KEY_REWIND, // backward << + [ 0x21 ] = KEY_PLAY, // play + [ 0x61 ] = KEY_FASTFORWARD, // forward >> + [ 0x01 ] = KEY_NEXT, // skip >| +}; + +/* ---------------------------------------------------------------------- */ + +struct cx88_IR { + struct cx88_core *core; + struct input_dev input; + struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* sample from gpio pin 16 */ + int sampling; + u32 samples[16]; + int scount; + unsigned long release; + + /* poll external decoder */ + int polling; + struct work_struct work; + struct timer_list timer; + u32 gpio_addr; + u32 last_gpio; + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; +}; + +static int ir_debug = 0; +module_param(ir_debug, int, 0644); /* debug level [IR] */ +MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); + +#define ir_dprintk(fmt, arg...) if (ir_debug) \ + printk(KERN_DEBUG "%s IR: " fmt , ir->core->name, ## arg) + +/* ---------------------------------------------------------------------- */ + +static void cx88_ir_handle_key(struct cx88_IR *ir) +{ + struct cx88_core *core = ir->core; + u32 gpio, data; + + /* read gpio value */ + gpio = cx_read(ir->gpio_addr); + if (ir->polling) { + if (ir->last_gpio == gpio) + return; + ir->last_gpio = gpio; + } + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n", + gpio, data, + ir->polling ? "poll" : "irq", + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); + + if (ir->mask_keydown) { + /* bit set on keydown */ + if (gpio & ir->mask_keydown) { + ir_input_keydown(&ir->input,&ir->ir,data,data); + } else { + ir_input_nokey(&ir->input,&ir->ir); + } + + } else if (ir->mask_keyup) { + /* bit cleared on keydown */ + if (0 == (gpio & ir->mask_keyup)) { + ir_input_keydown(&ir->input,&ir->ir,data,data); + } else { + ir_input_nokey(&ir->input,&ir->ir); + } + + } else { + /* can't distinguish keydown/up :-/ */ + ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_nokey(&ir->input,&ir->ir); + } +} + +static void ir_timer(unsigned long data) +{ + struct cx88_IR *ir = (struct cx88_IR*)data; + + schedule_work(&ir->work); +} + +static void cx88_ir_work(void *data) +{ + struct cx88_IR *ir = data; + unsigned long timeout; + + cx88_ir_handle_key(ir); + timeout = jiffies + (ir->polling * HZ / 1000); + mod_timer(&ir->timer, timeout); +} + +/* ---------------------------------------------------------------------- */ + +int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) +{ + struct cx88_IR *ir; + IR_KEYTAB_TYPE *ir_codes = NULL; + int ir_type = IR_TYPE_OTHER; + + ir = kmalloc(sizeof(*ir),GFP_KERNEL); + if (NULL == ir) + return -ENOMEM; + memset(ir,0,sizeof(*ir)); + + /* detect & configure */ + switch (core->board) { + case CX88_BOARD_DNTV_LIVE_DVB_T: + ir_codes = ir_codes_dntv_live_dvb_t; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x1f; + ir->mask_keyup = 0x60; + ir->polling = 50; // ms + break; + case CX88_BOARD_HAUPPAUGE: + case CX88_BOARD_HAUPPAUGE_DVB_T1: + ir_codes = ir_codes_hauppauge_new; + ir_type = IR_TYPE_RC5; + ir->sampling = 1; + break; + case CX88_BOARD_WINFAST2000XP_EXPERT: + ir_codes = ir_codes_winfast; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0x8f8; + ir->mask_keyup = 0x100; + ir->polling = 1; // ms + break; + case CX88_BOARD_IODATA_GVBCTV7E: + ir_codes = ir_codes_iodata_bctv7e; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0xfd; + ir->mask_keydown = 0x02; + ir->polling = 5; // ms + break; + } + if (NULL == ir_codes) { + kfree(ir); + return -ENODEV; + } + + /* init input device */ + snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", + cx88_boards[core->board].name); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", + pci_name(pci)); + + ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes); + ir->input.name = ir->name; + ir->input.phys = ir->phys; + ir->input.id.bustype = BUS_PCI; + ir->input.id.version = 1; + if (pci->subsystem_vendor) { + ir->input.id.vendor = pci->subsystem_vendor; + ir->input.id.product = pci->subsystem_device; + } else { + ir->input.id.vendor = pci->vendor; + ir->input.id.product = pci->device; + } + + /* record handles to ourself */ + ir->core = core; + core->ir = ir; + + if (ir->polling) { + INIT_WORK(&ir->work, cx88_ir_work, ir); + init_timer(&ir->timer); + ir->timer.function = ir_timer; + ir->timer.data = (unsigned long)ir; + schedule_work(&ir->work); + } + if (ir->sampling) { + core->pci_irqmask |= (1<<18); // IR_SMP_INT + cx_write(MO_DDS_IO, 0xa80a80); // 4 kHz sample rate + cx_write(MO_DDSCFG_IO, 0x5); // enable + } + + /* all done */ + input_register_device(&ir->input); + printk("%s: registered IR remote control\n", core->name); + + return 0; +} + +int cx88_ir_fini(struct cx88_core *core) +{ + struct cx88_IR *ir = core->ir; + + /* skip detach on non attached boards */ + if (NULL == ir) + return 0; + + if (ir->polling) { + del_timer(&ir->timer); + flush_scheduled_work(); + } + + input_unregister_device(&ir->input); + kfree(ir); + + /* done */ + core->ir = NULL; + return 0; +} + +/* ---------------------------------------------------------------------- */ + +void cx88_ir_irq(struct cx88_core *core) +{ + struct cx88_IR *ir = core->ir; + u32 samples,rc5; + int i; + + if (NULL == ir) + return; + if (!ir->sampling) + return; + + samples = cx_read(MO_SAMPLE_IO); + if (0 != samples && 0xffffffff != samples) { + /* record sample data */ + if (ir->scount < ARRAY_SIZE(ir->samples)) + ir->samples[ir->scount++] = samples; + return; + } + if (!ir->scount) { + /* nothing to sample */ + if (ir->ir.keypressed && time_after(jiffies,ir->release)) + ir_input_nokey(&ir->input,&ir->ir); + return; + } + + /* have a complete sample */ + if (ir->scount < ARRAY_SIZE(ir->samples)) + ir->samples[ir->scount++] = samples; + for (i = 0; i < ir->scount; i++) + ir->samples[i] = ~ir->samples[i]; + if (ir_debug) + ir_dump_samples(ir->samples,ir->scount); + + /* decode it */ + switch (core->board) { + case CX88_BOARD_HAUPPAUGE: + case CX88_BOARD_HAUPPAUGE_DVB_T1: + rc5 = ir_decode_biphase(ir->samples,ir->scount,5,7); + ir_dprintk("biphase decoded: %x\n",rc5); + if ((rc5 & 0xfffff000) != 0x3000) + break; + ir_input_keydown(&ir->input, &ir->ir, rc5 & 0x3f, rc5); + ir->release = jiffies + msecs_to_jiffies(120); + break; + } + + ir->scount = 0; + return; +} + +/* ---------------------------------------------------------------------- */ + +MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe"); +MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/video/cx88/cx88-mpeg.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88-mpeg.c 2005-03-07 10:16:04.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88-mpeg.c 2005-03-08 10:33:15.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: cx88-mpeg.c,v 1.14 2004/10/25 11:26:36 kraxel Exp $ + * $Id: cx88-mpeg.c,v 1.25 2005/03/07 14:18:00 kraxel Exp $ * * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -68,8 +69,14 @@ static int cx8802_start_dma(struct cx880 * also: move to cx88-blackbird + cx88-dvb source files? */ if (cx88_boards[core->board].dvb) { - /* Setup TS portion of chip */ - cx_write(TS_GEN_CNTRL, 0x0c); + /* negedge driven & software reset */ + cx_write(TS_GEN_CNTRL, 0x40); + udelay(100); + cx_write(MO_PINMUX_IO, 0x00); + cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00); + cx_write(TS_SOP_STAT,0x00); + cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); + udelay(100); } if (cx88_boards[core->board].blackbird) { @@ -93,7 +100,7 @@ static int cx8802_start_dma(struct cx880 q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, 0x00fc04); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04); cx_write(MO_TS_INTMSK, 0x1f0011); /* start dma */ @@ -292,19 +299,18 @@ static irqreturn_t cx8802_irq(int irq, v { struct cx8802_dev *dev = dev_id; struct cx88_core *core = dev->core; - u32 status, mask; + u32 status; int loop, handled = 0; for (loop = 0; loop < 10; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (~0x1f | 0x04); - mask = cx_read(MO_PCI_INTMSK); - if (0 == (status & mask)) + status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04); + if (0 == status) goto out; handled = 1; cx_write(MO_PCI_INTSTAT, status); - if (status & mask & ~0x1f) - cx88_irq(core,status,mask); + if (status & core->pci_irqmask) + cx88_core_irq(core,status); if (status & 0x04) cx8802_mpeg_irq(dev); }; @@ -323,6 +329,7 @@ static irqreturn_t cx8802_irq(int irq, v int cx8802_init_common(struct cx8802_dev *dev) { + struct cx88_core *core = dev->core; int err; /* pci init */ @@ -354,11 +361,6 @@ int cx8802_init_common(struct cx8802_dev cx88_risc_stopper(dev->pci,&dev->mpegq.stopper, MO_TS_DMACNTRL,0x11,0x00); -#if 0 /* FIXME */ - /* initialize hardware */ - cx8802_reset(dev); -#endif - /* get irq */ err = request_irq(dev->pci->irq, cx8802_irq, SA_SHIRQ | SA_INTERRUPT, dev->core->name, dev); @@ -367,11 +369,7 @@ int cx8802_init_common(struct cx8802_dev dev->core->name, dev->pci->irq); return err; } - -#if 0 /* FIXME */ - /* register i2c bus + load i2c helpers */ - cx88_card_setup(dev); -#endif + cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* everything worked */ pci_set_drvdata(dev->pci,dev); @@ -393,7 +391,7 @@ void cx8802_fini_common(struct cx8802_de /* ----------------------------------------------------------- */ -int cx8802_suspend_common(struct pci_dev *pci_dev, u32 state) +int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -413,7 +411,7 @@ int cx8802_suspend_common(struct pci_dev #endif pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, state)) { + if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { pci_disable_device(pci_dev); dev->state.disabled = 1; } @@ -429,7 +427,7 @@ int cx8802_resume_common(struct pci_dev pci_enable_device(pci_dev); dev->state.disabled = 0; } - pci_set_power_state(pci_dev, 0); + pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); #if 1 Index: linux-2.6.11/drivers/media/video/cx88/cx88-tvaudio.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88-tvaudio.c 2005-03-07 10:13:41.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88-tvaudio.c 2005-03-08 10:33:20.000000000 +0100 @@ -1,5 +1,5 @@ /* - $Id: cx88-tvaudio.c,v 1.24 2004/10/25 11:51:00 kraxel Exp $ + $Id: cx88-tvaudio.c,v 1.34 2005/03/07 16:10:51 kraxel Exp $ cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver @@ -37,6 +37,7 @@ */ #include +#include #include #include #include @@ -56,7 +57,7 @@ #include "cx88.h" -static unsigned int audio_debug = 1; +static unsigned int audio_debug = 0; module_param(audio_debug,int,0644); MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]"); @@ -141,6 +142,13 @@ static void set_audio_finish(struct cx88 { u32 volume; + if (cx88_boards[core->board].blackbird) { + // 'pass-thru mode': this enables the i2s output to the mpeg encoder + cx_set(AUD_CTL, 0x2000); + cx_write(AUD_I2SOUTPUTCNTL, 1); + //cx_write(AUD_APB_IN_RATE_ADJ, 0); + } + // finish programming cx_write(AUD_SOFT_RESET, 0x0000); @@ -263,6 +271,7 @@ static void set_audio_standard_BTSC(stru set_audio_finish(core); } +#if 0 static void set_audio_standard_NICAM(struct cx88_core *core) { static const struct rlist nicam_common[] = { @@ -335,128 +344,243 @@ static void set_audio_standard_NICAM(str }; set_audio_finish(core); } +#endif -static void set_audio_standard_NICAM_L(struct cx88_core *core) +static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo) { - /* This is officially weird.. register dumps indicate windows - * uses audio mode 4.. A2. Let's operate and find out. */ + /* This is probably weird.. + * Let's operate and find out. */ - static const struct rlist nicam_l[] = { - // setup QAM registers - { AUD_PDF_DDS_CNST_BYTE2, 0x48 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x3d }, - { AUD_PDF_DDS_CNST_BYTE0, 0xf5 }, - { AUD_QAM_MODE, 0x00 }, - { AUD_PHACC_FREQ_8MSB, 0x3a }, - { AUD_PHACC_FREQ_8LSB, 0x4a }, + static const struct rlist nicam_l_mono[] = { + { AUD_ERRLOGPERIOD_R, 0x00000064 }, + { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, + { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, - { AUD_POLY0_DDS_CONSTANT, 0x000e4db2 }, - { AUD_IIR1_0_SEL, 0x00000000 }, - { AUD_IIR1_1_SEL, 0x00000002 }, - { AUD_IIR1_2_SEL, 0x00000023 }, - { AUD_IIR1_3_SEL, 0x00000004 }, - { AUD_IIR1_4_SEL, 0x00000005 }, - { AUD_IIR1_5_SEL, 0x00000007 }, - { AUD_IIR1_0_SHIFT, 0x00000007 }, - { AUD_IIR1_1_SHIFT, 0x00000000 }, - { AUD_IIR1_2_SHIFT, 0x00000000 }, - { AUD_IIR1_3_SHIFT, 0x00000007 }, - { AUD_IIR1_4_SHIFT, 0x00000007 }, - { AUD_IIR1_5_SHIFT, 0x00000007 }, - { AUD_IIR2_0_SEL, 0x00000002 }, - { AUD_IIR2_1_SEL, 0x00000003 }, - { AUD_IIR2_2_SEL, 0x00000004 }, - { AUD_IIR2_3_SEL, 0x00000005 }, - { AUD_IIR3_0_SEL, 0x00000007 }, - { AUD_IIR3_1_SEL, 0x00000023 }, - { AUD_IIR3_2_SEL, 0x00000016 }, - { AUD_IIR4_0_SHIFT, 0x00000000 }, - { AUD_IIR4_1_SHIFT, 0x00000000 }, - { AUD_IIR3_2_SHIFT, 0x00000002 }, - { AUD_IIR4_0_SEL, 0x0000001d }, - { AUD_IIR4_1_SEL, 0x00000019 }, - { AUD_IIR4_2_SEL, 0x00000008 }, - { AUD_IIR4_0_SHIFT, 0x00000000 }, - { AUD_IIR4_1_SHIFT, 0x00000007 }, - { AUD_IIR4_2_SHIFT, 0x00000007 }, - { AUD_IIR4_0_CA0, 0x0003e57e }, - { AUD_IIR4_0_CA1, 0x00005e11 }, - { AUD_IIR4_0_CA2, 0x0003a7cf }, - { AUD_IIR4_0_CB0, 0x00002368 }, - { AUD_IIR4_0_CB1, 0x0003bf1b }, - { AUD_IIR4_1_CA0, 0x00006349 }, - { AUD_IIR4_1_CA1, 0x00006f27 }, - { AUD_IIR4_1_CA2, 0x0000e7a3 }, - { AUD_IIR4_1_CB0, 0x00005653 }, - { AUD_IIR4_1_CB1, 0x0000cf97 }, - { AUD_IIR4_2_CA0, 0x00006349 }, - { AUD_IIR4_2_CA1, 0x00006f27 }, - { AUD_IIR4_2_CA2, 0x0000e7a3 }, - { AUD_IIR4_2_CB0, 0x00005653 }, - { AUD_IIR4_2_CB1, 0x0000cf97 }, - { AUD_HP_MD_IIR4_1, 0x00000001 }, - { AUD_HP_PROG_IIR4_1, 0x0000001a }, - { AUD_DN0_FREQ, 0x00000000 }, - { AUD_DN1_FREQ, 0x00003318 }, - { AUD_DN1_SRC_SEL, 0x00000017 }, - { AUD_DN1_SHFT, 0x00000007 }, - { AUD_DN1_AFC, 0x00000000 }, - { AUD_DN1_FREQ_SHIFT, 0x00000000 }, - { AUD_DN2_FREQ, 0x00003551 }, - { AUD_DN2_SRC_SEL, 0x00000001 }, - { AUD_DN2_SHFT, 0x00000000 }, - { AUD_DN2_AFC, 0x00000002 }, - { AUD_DN2_FREQ_SHIFT, 0x00000000 }, - { AUD_PDET_SRC, 0x00000014 }, - { AUD_PDET_SHIFT, 0x00000000 }, - { AUD_DEEMPH0_SRC_SEL, 0x00000011 }, - { AUD_DEEMPH1_SRC_SEL, 0x00000011 }, - { AUD_DEEMPH0_SHIFT, 0x00000000 }, - { AUD_DEEMPH1_SHIFT, 0x00000000 }, - { AUD_DEEMPH0_G0, 0x00007000 }, - { AUD_DEEMPH0_A0, 0x00000000 }, - { AUD_DEEMPH0_B0, 0x00000000 }, - { AUD_DEEMPH0_A1, 0x00000000 }, - { AUD_DEEMPH0_B1, 0x00000000 }, - { AUD_DEEMPH1_G0, 0x00007000 }, - { AUD_DEEMPH1_A0, 0x00000000 }, - { AUD_DEEMPH1_B0, 0x00000000 }, - { AUD_DEEMPH1_A1, 0x00000000 }, - { AUD_DEEMPH1_B1, 0x00000000 }, - { AUD_DMD_RA_DDS, 0x00f5c285 }, - { AUD_RATE_ADJ1, 0x00000100 }, - { AUD_RATE_ADJ2, 0x00000200 }, - { AUD_RATE_ADJ3, 0x00000300 }, - { AUD_RATE_ADJ4, 0x00000400 }, - { AUD_RATE_ADJ5, 0x00000500 }, - { AUD_C2_UP_THR, 0x00005400 }, - { AUD_C2_LO_THR, 0x00003000 }, - { AUD_C1_UP_THR, 0x00007000 }, - { AUD_C2_LO_THR, 0x00005400 }, - { AUD_CTL, 0x0000100c }, - { AUD_DCOC_0_SRC, 0x00000021 }, - { AUD_DCOC_1_SRC, 0x00000003 }, - { AUD_DCOC1_SHIFT, 0x00000000 }, - { AUD_DCOC_1_SHIFT_IN0, 0x0000000a }, - { AUD_DCOC_1_SHIFT_IN1, 0x00000008 }, - { AUD_DCOC_PASS_IN, 0x00000000 }, - { AUD_DCOC_2_SRC, 0x0000001b }, - { AUD_IIR4_0_SEL, 0x0000001d }, - { AUD_POLY0_DDS_CONSTANT, 0x000e4db2 }, - { AUD_PHASE_FIX_CTL, 0x00000000 }, - { AUD_CORDIC_SHIFT_1, 0x00000007 }, - { AUD_PLL_EN, 0x00000000 }, - { AUD_PLL_PRESCALE, 0x00000002 }, - { AUD_PLL_INT, 0x0000001e }, - { AUD_OUT1_SHIFT, 0x00000000 }, + { AUD_PDF_DDS_CNST_BYTE2, 0x48 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x3D }, + { AUD_QAM_MODE, 0x00 }, + { AUD_PDF_DDS_CNST_BYTE0, 0xf5 }, + { AUD_PHACC_FREQ_8MSB, 0x3a }, + { AUD_PHACC_FREQ_8LSB, 0x4a }, - { /* end of list */ }, - }; + { AUD_DEEMPHGAIN_R, 0x6680 }, + { AUD_DEEMPHNUMER1_R, 0x353DE }, + { AUD_DEEMPHNUMER2_R, 0x1B1 }, + { AUD_DEEMPHDENOM1_R, 0x0F3D0 }, + { AUD_DEEMPHDENOM2_R, 0x0 }, + { AUD_FM_MODE_ENABLE, 0x7 }, + { AUD_POLYPH80SCALEFAC, 0x3 }, + { AUD_AFE_12DB_EN, 0x1 }, + { AAGC_GAIN, 0x0 }, + { AAGC_HYST, 0x18 }, + { AAGC_DEF, 0x20 }, + { AUD_DN0_FREQ, 0x0 }, + { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 }, + { AUD_DCOC_0_SRC, 0x21 }, + { AUD_IIR1_0_SEL, 0x0 }, + { AUD_IIR1_0_SHIFT, 0x7 }, + { AUD_IIR1_1_SEL, 0x2 }, + { AUD_IIR1_1_SHIFT, 0x0 }, + { AUD_DCOC_1_SRC, 0x3 }, + { AUD_DCOC1_SHIFT, 0x0 }, + { AUD_DCOC_PASS_IN, 0x0 }, + { AUD_IIR1_2_SEL, 0x23 }, + { AUD_IIR1_2_SHIFT, 0x0 }, + { AUD_IIR1_3_SEL, 0x4 }, + { AUD_IIR1_3_SHIFT, 0x7 }, + { AUD_IIR1_4_SEL, 0x5 }, + { AUD_IIR1_4_SHIFT, 0x7 }, + { AUD_IIR3_0_SEL, 0x7 }, + { AUD_IIR3_0_SHIFT, 0x0 }, + { AUD_DEEMPH0_SRC_SEL, 0x11 }, + { AUD_DEEMPH0_SHIFT, 0x0 }, + { AUD_DEEMPH0_G0, 0x7000 }, + { AUD_DEEMPH0_A0, 0x0 }, + { AUD_DEEMPH0_B0, 0x0 }, + { AUD_DEEMPH0_A1, 0x0 }, + { AUD_DEEMPH0_B1, 0x0 }, + { AUD_DEEMPH1_SRC_SEL, 0x11 }, + { AUD_DEEMPH1_SHIFT, 0x0 }, + { AUD_DEEMPH1_G0, 0x7000 }, + { AUD_DEEMPH1_A0, 0x0 }, + { AUD_DEEMPH1_B0, 0x0 }, + { AUD_DEEMPH1_A1, 0x0 }, + { AUD_DEEMPH1_B1, 0x0 }, + { AUD_OUT0_SEL, 0x3F }, + { AUD_OUT1_SEL, 0x3F }, + { AUD_DMD_RA_DDS, 0x0F5C285 }, + { AUD_PLL_INT, 0x1E }, + { AUD_PLL_DDS, 0x0 }, + { AUD_PLL_FRAC, 0x0E542 }, - dprintk("%s (status: unknown)\n",__FUNCTION__); - set_audio_start(core, 0x0004, - 0 /* FIXME */); - set_audio_registers(core, nicam_l); + // setup QAM registers + { AUD_RATE_ADJ1, 0x00000100 }, + { AUD_RATE_ADJ2, 0x00000200 }, + { AUD_RATE_ADJ3, 0x00000300 }, + { AUD_RATE_ADJ4, 0x00000400 }, + { AUD_RATE_ADJ5, 0x00000500 }, + { AUD_RATE_THRES_DMD, 0x000000C0 }, + { /* end of list */ }, + }; + + static const struct rlist nicam_l[] = { + // setup QAM registers + { AUD_RATE_ADJ1, 0x00000060 }, + { AUD_RATE_ADJ2, 0x000000F9 }, + { AUD_RATE_ADJ3, 0x000001CC }, + { AUD_RATE_ADJ4, 0x000002B3 }, + { AUD_RATE_ADJ5, 0x00000726 }, + { AUD_DEEMPHDENOM1_R, 0x0000F3D0 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_ERRLOGPERIOD_R, 0x00000064 }, + { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, + { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, + { AUD_POLYPH80SCALEFAC, 0x00000003 }, + { AUD_DMD_RA_DDS, 0x00C00000 }, + { AUD_PLL_INT, 0x0000001E }, + { AUD_PLL_DDS, 0x00000000 }, + { AUD_PLL_FRAC, 0x0000E542 }, + { AUD_START_TIMER, 0x00000000 }, + { AUD_DEEMPHNUMER1_R, 0x000353DE }, + { AUD_DEEMPHNUMER2_R, 0x000001B1 }, + { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, + { AUD_QAM_MODE, 0x05 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, + { AUD_PHACC_FREQ_8MSB, 0x34 }, + { AUD_PHACC_FREQ_8LSB, 0x4C }, + { AUD_DEEMPHGAIN_R, 0x00006680 }, + { AUD_RATE_THRES_DMD, 0x000000C0 }, + { /* end of list */ }, + } ; + dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); + + if (!stereo) { + /* AM mono sound */ + set_audio_start(core, 0x0004, + 0x100c /* FIXME again */); + set_audio_registers(core, nicam_l_mono); + } else { + set_audio_start(core, 0x0010, + 0x1924 /* FIXME again */); + set_audio_registers(core, nicam_l); + } + set_audio_finish(core); + +} + +static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo) +{ + static const struct rlist pal_i_fm_mono[] = { + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_QAM_MODE, 0x05}, + {AUD_PHACC_FREQ_8MSB, 0x3a}, + {AUD_PHACC_FREQ_8LSB, 0x93}, + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_PLL_INT, 0x0000001e}, + {AUD_PLL_DDS, 0x00000004}, + {AUD_PLL_FRAC, 0x0000e542}, + {AUD_RATE_ADJ1, 0x00000100}, + {AUD_RATE_ADJ2, 0x00000200}, + {AUD_RATE_ADJ3, 0x00000300}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00000500}, + {AUD_THR_FR, 0x00000000}, + {AUD_PILOT_BQD_1_K0, 0x0000755b}, + {AUD_PILOT_BQD_1_K1, 0x00551340}, + {AUD_PILOT_BQD_1_K2, 0x006d30be}, + {AUD_PILOT_BQD_1_K3, 0xffd394af}, + {AUD_PILOT_BQD_1_K4, 0x00400000}, + {AUD_PILOT_BQD_2_K0, 0x00040000}, + {AUD_PILOT_BQD_2_K1, 0x002a4841}, + {AUD_PILOT_BQD_2_K2, 0x00400000}, + {AUD_PILOT_BQD_2_K3, 0x00000000}, + {AUD_PILOT_BQD_2_K4, 0x00000000}, + {AUD_MODE_CHG_TIMER, 0x00000060}, + {AUD_AFE_12DB_EN, 0x00000001}, + {AAGC_HYST, 0x0000000a}, + {AUD_CORDIC_SHIFT_0, 0x00000007}, + {AUD_CORDIC_SHIFT_1, 0x00000007}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_DCOC0_SHIFT, 0x00000000}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_IIR3_0_SEL, 0x00000021}, + {AUD_DN2_AFC, 0x00000002}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_IIR3_1_SEL, 0x00000023}, + {AUD_DN0_FREQ, 0x000035a3}, + {AUD_DN2_FREQ, 0x000029c7}, + {AUD_CRDC0_SRC_SEL, 0x00000511}, + {AUD_IIR1_0_SEL, 0x00000001}, + {AUD_IIR1_1_SEL, 0x00000000}, + {AUD_IIR3_2_SEL, 0x00000003}, + {AUD_IIR3_2_SHIFT, 0x00000000}, + {AUD_IIR3_0_SEL, 0x00000002}, + {AUD_IIR2_0_SEL, 0x00000021}, + {AUD_IIR2_0_SHIFT, 0x00000002}, + {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, + {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, + {AUD_POLYPH80SCALEFAC, 0x00000001}, + {AUD_START_TIMER, 0x00000000}, + { /* end of list */ }, + }; + + static const struct rlist pal_i_nicam[] = { + { AUD_RATE_ADJ1, 0x00000010 }, + { AUD_RATE_ADJ2, 0x00000040 }, + { AUD_RATE_ADJ3, 0x00000100 }, + { AUD_RATE_ADJ4, 0x00000400 }, + { AUD_RATE_ADJ5, 0x00001000 }, + // { AUD_DMD_RA_DDS, 0x00c0d5ce }, + { AUD_DEEMPHGAIN_R, 0x000023c2 }, + { AUD_DEEMPHNUMER1_R, 0x0002a7bc }, + { AUD_DEEMPHNUMER2_R, 0x0003023e }, + { AUD_DEEMPHDENOM1_R, 0x0000f3d0 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_ERRLOGPERIOD_R, 0x00000fff }, + { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff }, + { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f }, + { AUD_POLYPH80SCALEFAC, 0x00000003 }, + { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, + { AUD_QAM_MODE, 0x05 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, + { AUD_PHACC_FREQ_8MSB, 0x3a }, + { AUD_PHACC_FREQ_8LSB, 0x93 }, + { /* end of list */ }, + }; + + dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); + + if (!stereo) { + // FM mono + set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1); + set_audio_registers(core, pal_i_fm_mono); + } else { + // Nicam Stereo + set_audio_start(core, 0x0010, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO); + set_audio_registers(core, pal_i_nicam); + } set_audio_finish(core); } @@ -553,13 +677,6 @@ static void set_audio_standard_A2(struct set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO); set_audio_registers(core, a2_common); switch (core->tvaudio) { - case WW_NICAM_I: - /* gives at least mono according to the dscaler guys */ - /* so use use that while nicam is broken ... */ - dprintk("%s PAL-I mono (status: unknown)\n",__FUNCTION__); - set_audio_registers(core, a2_table1); - cx_write(AUD_CTL, EN_A2_FORCE_MONO1); - break; case WW_A2_BG: dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__); set_audio_registers(core, a2_table1); @@ -646,11 +763,12 @@ void cx88_set_tvaudio(struct cx88_core * case WW_BTSC: set_audio_standard_BTSC(core,0); break; - // case WW_NICAM_I: case WW_NICAM_BGDKL: - set_audio_standard_NICAM(core); + set_audio_standard_NICAM_L(core,0); break; case WW_NICAM_I: + set_audio_standard_PAL_I(core,0); + break; case WW_A2_BG: case WW_A2_DK: case WW_A2_M: @@ -663,7 +781,7 @@ void cx88_set_tvaudio(struct cx88_core * set_audio_standard_FM(core); break; case WW_SYSTEM_L_AM: - set_audio_standard_NICAM_L(core); + set_audio_standard_NICAM_L(core, 1); break; case WW_NONE: default: @@ -674,6 +792,19 @@ void cx88_set_tvaudio(struct cx88_core * return; } +void cx88_newstation(struct cx88_core *core) +{ + core->audiomode_manual = UNSET; + + switch (core->tvaudio) { + case WW_SYSTEM_L_AM: + /* try nicam ... */ + core->audiomode_current = V4L2_TUNER_MODE_STEREO; + set_audio_standard_NICAM_L(core, 1); + break; + } +} + void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) { static char *m[] = {"stereo", "dual mono", "mono", "sap"}; @@ -721,22 +852,37 @@ void cx88_get_stereo(struct cx88_core *c } break; case WW_NICAM_BGDKL: - if (0 == mode) + if (0 == mode) { t->audmode = V4L2_TUNER_MODE_STEREO; + t->rxsubchans |= V4L2_TUNER_SUB_STEREO; + } break; + case WW_SYSTEM_L_AM: + if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) { + t->audmode = V4L2_TUNER_MODE_STEREO; + t->rxsubchans |= V4L2_TUNER_SUB_STEREO; + } + break ; default: - t->rxsubchans = V4L2_TUNER_SUB_MONO; - t->audmode = V4L2_TUNER_MODE_MONO; + /* nothing */ break; } return; } -void cx88_set_stereo(struct cx88_core *core, u32 mode) +void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) { u32 ctl = UNSET; u32 mask = UNSET; + if (manual) { + core->audiomode_manual = mode; + } else { + if (UNSET != core->audiomode_manual) + return; + } + core->audiomode_current = mode; + switch (core->tvaudio) { case WW_BTSC: switch (mode) { @@ -789,6 +935,28 @@ void cx88_set_stereo(struct cx88_core *c break; } break; + case WW_SYSTEM_L_AM: + switch (mode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: /* FIXME */ + set_audio_standard_NICAM_L(core, 0); + break; + case V4L2_TUNER_MODE_STEREO: + set_audio_standard_NICAM_L(core, 1); + break; + } + break; + case WW_NICAM_I: + switch (mode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + set_audio_standard_PAL_I(core, 0); + break; + case V4L2_TUNER_MODE_STEREO: + set_audio_standard_PAL_I(core, 1); + break; + } + break; case WW_FM: switch (mode) { case V4L2_TUNER_MODE_MONO: @@ -804,13 +972,11 @@ void cx88_set_stereo(struct cx88_core *c } if (UNSET != ctl) { - cx_write(AUD_SOFT_RESET, 0x0001); - cx_andor(AUD_CTL, mask, ctl); - cx_write(AUD_SOFT_RESET, 0x0000); dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x " "[status=0x%x,ctl=0x%x,vol=0x%x]\n", mask, ctl, cx_read(AUD_STATUS), cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL)); + cx_andor(AUD_CTL, mask, ctl); } return; } @@ -819,16 +985,32 @@ int cx88_audio_thread(void *data) { struct cx88_core *core = data; struct v4l2_tuner t; + u32 mode = 0; dprintk("cx88: tvaudio thread started\n"); for (;;) { + msleep_interruptible(1000); if (kthread_should_stop()) break; /* just monitor the audio status for now ... */ memset(&t,0,sizeof(t)); cx88_get_stereo(core,&t); - msleep_interruptible(1000); + + if (UNSET != core->audiomode_manual) + /* manually set, don't do anything. */ + continue; + + /* monitor signal */ + if (t.rxsubchans & V4L2_TUNER_SUB_STEREO) + mode = V4L2_TUNER_MODE_STEREO; + else + mode = V4L2_TUNER_MODE_MONO; + if (mode == core->audiomode_current) + continue; + + /* automatically switch to best available mode */ + cx88_set_stereo(core, mode, 0); } dprintk("cx88: tvaudio thread exiting\n"); @@ -838,6 +1020,7 @@ int cx88_audio_thread(void *data) /* ----------------------------------------------------------- */ EXPORT_SYMBOL(cx88_set_tvaudio); +EXPORT_SYMBOL(cx88_newstation); EXPORT_SYMBOL(cx88_set_stereo); EXPORT_SYMBOL(cx88_get_stereo); EXPORT_SYMBOL(cx88_audio_thread); Index: linux-2.6.11/drivers/media/video/cx88/cx88-vbi.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88-vbi.c 2005-03-07 10:13:49.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88-vbi.c 2005-03-08 10:33:15.000000000 +0100 @@ -1,8 +1,9 @@ /* - * $Id: cx88-vbi.c,v 1.14 2004/11/07 13:17:15 kraxel Exp $ + * $Id: cx88-vbi.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $ */ #include #include +#include #include #include @@ -64,7 +65,7 @@ int cx8800_start_vbi_dma(struct cx8800_d q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, 0x00fc01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); cx_set(MO_VID_INTMSK, 0x0f0088); /* enable capture */ Index: linux-2.6.11/drivers/media/video/cx88/cx88-video.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88-video.c 2005-03-07 10:14:10.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88-video.c 2005-03-08 10:33:20.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: cx88-video.c,v 1.46 2004/11/07 14:44:59 kraxel Exp $ + * $Id: cx88-video.c,v 1.58 2005/03/07 15:58:05 kraxel Exp $ * * device driver for Conexant 2388x based TV cards * video4linux video interface @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -428,7 +429,7 @@ static int start_video_dma(struct cx8800 q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, 0x00fc01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); cx_set(MO_VID_INTMSK, 0x0f0011); /* enable capture */ @@ -994,7 +995,7 @@ static int video_open(struct inode *inod cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3); dev->core->tvaudio = WW_FM; cx88_set_tvaudio(core); - cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO); + cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); cx88_call_i2c_clients(dev->core,AUDC_SET_RADIO,NULL); } @@ -1002,7 +1003,7 @@ static int video_open(struct inode *inod } static ssize_t -video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +video_read(struct file *file, char *data, size_t count, loff_t *ppos) { struct cx8800_fh *fh = file->private_data; @@ -1083,6 +1084,8 @@ static int video_release(struct inode *i res_free(dev,fh,RESOURCE_VBI); } + videobuf_mmap_free(&fh->vidq); + videobuf_mmap_free(&fh->vbiq); file->private_data = NULL; kfree(fh); return 0; @@ -1338,7 +1341,6 @@ static int video_do_ioctl(struct inode * 0; if (UNSET != core->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; - return 0; } @@ -1429,6 +1431,7 @@ static int video_do_ioctl(struct inode * if (*i >= 4) return -EINVAL; down(&dev->lock); + cx88_newstation(core); video_mux(dev,*i); up(&dev->lock); return 0; @@ -1560,7 +1563,7 @@ static int video_do_ioctl(struct inode * return -EINVAL; if (0 != t->index) return -EINVAL; - cx88_set_stereo(core, t->audmode); + cx88_set_stereo(core, t->audmode, 1); return 0; } case VIDIOC_G_FREQUENCY: @@ -1590,6 +1593,7 @@ static int video_do_ioctl(struct inode * return -EINVAL; down(&dev->lock); dev->freq = f->frequency; + cx88_newstation(core); #ifdef V4L2_I2C_CLIENTS cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f); #else @@ -1880,19 +1884,18 @@ static irqreturn_t cx8800_irq(int irq, v { struct cx8800_dev *dev = dev_id; struct cx88_core *core = dev->core; - u32 status, mask; + u32 status; int loop, handled = 0; for (loop = 0; loop < 10; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (~0x1f | 0x01); - mask = cx_read(MO_PCI_INTMSK); - if (0 == (status & mask)) + status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01); + if (0 == status) goto out; cx_write(MO_PCI_INTSTAT, status); handled = 1; - if (status & mask & ~0x1f) - cx88_irq(core,status,mask); + if (status & core->pci_irqmask) + cx88_core_irq(core,status); if (status & 0x01) cx8800_vid_irq(dev); }; @@ -2055,6 +2058,7 @@ static int __devinit cx8800_initdev(stru core->name,pci_dev->irq); goto fail_core; } + cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* load and configure helper modules */ if (TUNER_ABSENT != core->tuner_type) @@ -2156,7 +2160,7 @@ static void __devexit cx8800_finidev(str kfree(dev); } -static int cx8800_suspend(struct pci_dev *pci_dev, u32 state) +static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) { struct cx8800_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -2181,7 +2185,7 @@ static int cx8800_suspend(struct pci_dev #endif pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, state)) { + if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { pci_disable_device(pci_dev); dev->state.disabled = 1; } @@ -2197,7 +2201,7 @@ static int cx8800_resume(struct pci_dev pci_enable_device(pci_dev); dev->state.disabled = 0; } - pci_set_power_state(pci_dev, 0); + pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); #if 1 @@ -2254,7 +2258,7 @@ static int cx8800_init(void) printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif - return pci_module_init(&cx8800_pci_driver); + return pci_register_driver(&cx8800_pci_driver); } static void cx8800_fini(void) Index: linux-2.6.11/drivers/media/video/cx88/cx88.h =================================================================== --- linux-2.6.11.orig/drivers/media/video/cx88/cx88.h 2005-03-07 10:15:48.000000000 +0100 +++ linux-2.6.11/drivers/media/video/cx88/cx88.h 2005-03-08 10:33:15.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: cx88.h,v 1.40 2004/11/03 09:04:51 kraxel Exp $ + * $Id: cx88.h,v 1.56 2005/03/04 09:12:23 kraxel Exp $ * * v4l2 device driver for cx2388x based TV cards * @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -139,7 +140,7 @@ extern struct sram_channel cx88_sram_cha #define CX88_BOARD_GDI 2 #define CX88_BOARD_PIXELVIEW 3 #define CX88_BOARD_ATI_WONDER_PRO 4 -#define CX88_BOARD_WINFAST2000XP 5 +#define CX88_BOARD_WINFAST2000XP_EXPERT 5 #define CX88_BOARD_AVERTV_303 6 #define CX88_BOARD_MSI_TVANYWHERE_MASTER 7 #define CX88_BOARD_WINFAST_DV2000 8 @@ -156,6 +157,11 @@ extern struct sram_channel cx88_sram_cha #define CX88_BOARD_CONEXANT_DVB_T1 19 #define CX88_BOARD_PROVIDEO_PV259 20 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21 +#define CX88_BOARD_PCHDTV_HD3000 22 +#define CX88_BOARD_DNTV_LIVE_DVB_T 23 +#define CX88_BOARD_HAUPPAUGE_ROSLYN 24 +#define CX88_BOARD_DIGITALLOGIC_MEC 25 +#define CX88_BOARD_IODATA_GVBCTV7E 26 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -238,6 +244,7 @@ struct cx88_core { u32 __iomem *lmmio; u8 __iomem *bmmio; u32 shadow[SHADOW_MAX]; + int pci_irqmask; /* i2c i/o */ struct i2c_adapter i2c_adap; @@ -252,16 +259,20 @@ struct cx88_core { unsigned int has_radio; /* config info -- dvb */ - unsigned int pll_type; + struct dvb_pll_desc *pll_desc; unsigned int pll_addr; - unsigned int demod_addr; /* state info */ struct task_struct *kthread; struct cx88_tvnorm *tvnorm; u32 tvaudio; + u32 audiomode_manual; + u32 audiomode_current; u32 input; u32 astat; + + /* IR remote control state */ + struct cx88_IR *ir; }; struct cx8800_dev; @@ -371,11 +382,16 @@ struct cx8802_dev { struct list_head devlist; struct video_device *mpeg_dev; u32 mailbox; + int width; + int height; /* for dvb only */ struct videobuf_dvb dvb; void* fe_handle; int (*fe_release)(void *handle); + + /* for switching modulation types */ + unsigned char ts_gen_cntrl; }; /* ----------------------------------------------------------- */ @@ -411,7 +427,7 @@ extern void cx88_print_irqbits(char *nam u32 bits, u32 mask); extern void cx88_print_ioctl(char *name, unsigned int cmd); -extern void cx88_irq(struct cx88_core *core, u32 status, u32 mask); +extern int cx88_core_irq(struct cx88_core *core, u32 status); extern void cx88_wakeup(struct cx88_core *core, struct cx88_dmaqueue *q, u32 count); extern void cx88_shutdown(struct cx88_core *core); @@ -503,11 +519,19 @@ extern void cx88_card_setup(struct cx88_ #define WW_FM 12 void cx88_set_tvaudio(struct cx88_core *core); +void cx88_newstation(struct cx88_core *core); void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); -void cx88_set_stereo(struct cx88_core *core, u32 mode); +void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); int cx88_audio_thread(void *data); /* ----------------------------------------------------------- */ +/* cx88-input.c */ + +int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci); +int cx88_ir_fini(struct cx88_core *core); +void cx88_ir_irq(struct cx88_core *core); + +/* ----------------------------------------------------------- */ /* cx88-mpeg.c */ int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf); @@ -517,7 +541,7 @@ void cx8802_cancel_buffers(struct cx8802 int cx8802_init_common(struct cx8802_dev *dev); void cx8802_fini_common(struct cx8802_dev *dev); -int cx8802_suspend_common(struct pci_dev *pci_dev, u32 state); +int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state); int cx8802_resume_common(struct pci_dev *pci_dev); /* Index: linux-2.6.11/drivers/media/video/ir-kbd-gpio.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/ir-kbd-gpio.c 2005-03-07 10:14:58.000000000 +0100 +++ linux-2.6.11/drivers/media/video/ir-kbd-gpio.c 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: ir-kbd-gpio.c,v 1.11 2004/10/25 11:26:36 kraxel Exp $ + * $Id: ir-kbd-gpio.c,v 1.12 2005/02/22 12:28:40 kraxel Exp $ * * Copyright (c) 2003 Gerd Knorr * Copyright (c) 2003 Pavel Machek @@ -114,51 +114,6 @@ static IR_KEYTAB_TYPE ir_codes_avermedia [ 0x3e ] = KEY_VOLUMEUP, // 'volume +' }; -static IR_KEYTAB_TYPE winfast_codes[IR_KEYTAB_SIZE] = { - [ 5 ] = KEY_KP1, - [ 6 ] = KEY_KP2, - [ 7 ] = KEY_KP3, - [ 9 ] = KEY_KP4, - [ 10 ] = KEY_KP5, - [ 11 ] = KEY_KP6, - [ 13 ] = KEY_KP7, - [ 14 ] = KEY_KP8, - [ 15 ] = KEY_KP9, - [ 18 ] = KEY_KP0, - - [ 0 ] = KEY_POWER, -// [ 27 ] = MTS button - [ 2 ] = KEY_TUNER, // TV/FM - [ 30 ] = KEY_VIDEO, -// [ 22 ] = display button - [ 4 ] = KEY_VOLUMEUP, - [ 8 ] = KEY_VOLUMEDOWN, - [ 12 ] = KEY_CHANNELUP, - [ 16 ] = KEY_CHANNELDOWN, - [ 3 ] = KEY_ZOOM, // fullscreen - [ 31 ] = KEY_SUBTITLE, // closed caption/teletext - [ 32 ] = KEY_SLEEP, -// [ 41 ] = boss key - [ 20 ] = KEY_MUTE, - [ 43 ] = KEY_RED, - [ 44 ] = KEY_GREEN, - [ 45 ] = KEY_YELLOW, - [ 46 ] = KEY_BLUE, - [ 24 ] = KEY_KPPLUS, //fine tune + - [ 25 ] = KEY_KPMINUS, //fine tune - -// [ 42 ] = picture in picture - [ 33 ] = KEY_KPDOT, - [ 19 ] = KEY_KPENTER, -// [ 17 ] = recall - [ 34 ] = KEY_BACK, - [ 35 ] = KEY_PLAYPAUSE, - [ 36 ] = KEY_NEXT, -// [ 37 ] = time shifting - [ 38 ] = KEY_STOP, - [ 39 ] = KEY_RECORD -// [ 40 ] = snapshot -}; - static IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = { [ 2 ] = KEY_KP0, [ 1 ] = KEY_KP1, @@ -388,12 +343,12 @@ static int ir_probe(struct device *dev) break; case BTTV_WINFAST2000: - ir_codes = winfast_codes; + ir_codes = ir_codes_winfast; ir->mask_keycode = 0x1f8; break; case BTTV_MAGICTVIEW061: case BTTV_MAGICTVIEW063: - ir_codes = winfast_codes; + ir_codes = ir_codes_winfast; ir->mask_keycode = 0x0008e000; ir->mask_keydown = 0x00200000; break; Index: linux-2.6.11/drivers/media/video/msp3400.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/msp3400.c 2005-03-07 10:14:23.000000000 +0100 +++ linux-2.6.11/drivers/media/video/msp3400.c 2005-03-07 18:13:02.000000000 +0100 @@ -380,7 +380,9 @@ static void msp3400c_setvolume(struct i2 int val = 0, bal = 0; if (!muted) { - val = (volume * 0x7F / 65535) << 8; + /* 0x7f instead if 0x73 here has sound quality issues, + * probably due to overmodulation + clipping ... */ + val = (volume * 0x73 / 65535) << 8; } if (val) { bal = (balance / 256) - 128; @@ -993,7 +995,13 @@ static int msp34xx_modus(int norm) { switch (norm) { case VIDEO_MODE_PAL: +#if 1 + /* experimental: not sure this works with all chip versions */ + return 0x7003; +#else + /* previous value, try this if it breaks ... */ return 0x1003; +#endif case VIDEO_MODE_NTSC: /* BTSC */ return 0x2003; case VIDEO_MODE_SECAM: @@ -1260,6 +1268,7 @@ static int msp34xxg_thread(void *data) int val, std, i; printk("msp34xxg: daemon started\n"); + msp->source = 1; /* default */ for (;;) { d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n"); msp34xx_sleep(msp,-1); @@ -1330,8 +1339,9 @@ static void msp34xxg_set_source(struct i /* fix matrix mode to stereo and let the msp choose what * to output according to 'source', as recommended + * for MONO (source==0) downmixing set bit[7:0] to 0x30 */ - int value = (source&0x07)<<8|(source==0 ? 0x00:0x20); + int value = (source&0x07)<<8|(source==0 ? 0x30:0x20); dprintk("msp34xxg: set source to %d (0x%x)\n", source, value); msp3400c_write(client, I2C_MSP3400C_DFP, @@ -1355,7 +1365,7 @@ static void msp34xxg_set_source(struct i msp3400c_write(client, I2C_MSP3400C_DEM, 0x22, /* a2 threshold for stereo/bilingual */ - source==0 ? 0x7f0:stereo_threshold); + stereo_threshold); msp->source=source; } @@ -1390,7 +1400,7 @@ static void msp34xxg_detect_stereo(struc static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) { struct msp3400c *msp = i2c_get_clientdata(client); - int source = 0; + int source; switch (audmode) { case V4L2_TUNER_MODE_MONO: @@ -1406,9 +1416,10 @@ static void msp34xxg_set_audmode(struct case V4L2_TUNER_MODE_LANG2: source=4; /* stereo or B */ break; - default: /* doing nothing: a safe, sane default */ + default: audmode = 0; - return; + source = 1; + break; } msp->audmode = audmode; msp34xxg_set_source(client, source); @@ -1510,12 +1521,9 @@ static int msp_attach(struct i2c_adapter msp->opmode = opmode; if (OPMODE_AUTO == msp->opmode) { -#if 0 /* seems to work for ivtv only, disable by default for now ... */ if (HAVE_SIMPLER(msp)) msp->opmode = OPMODE_SIMPLER; - else -#endif - if (HAVE_SIMPLE(msp)) + else if (HAVE_SIMPLE(msp)) msp->opmode = OPMODE_SIMPLE; else msp->opmode = OPMODE_MANUAL; Index: linux-2.6.11/drivers/media/video/mt20xx.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/media/video/mt20xx.c 2005-03-07 18:13:02.000000000 +0100 @@ -0,0 +1,558 @@ +/* + * $Id: mt20xx.c,v 1.4 2005/03/04 09:24:56 kraxel Exp $ + * + * i2c tv tuner chip device driver + * controls microtune tuners, mt2032 + mt2050 at the moment. + */ +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +static unsigned int optimize_vco = 1; +module_param(optimize_vco, int, 0644); + +static unsigned int tv_antenna = 1; +module_param(tv_antenna, int, 0644); + +static unsigned int radio_antenna = 0; +module_param(radio_antenna, int, 0644); + +/* ---------------------------------------------------------------------- */ + +#define MT2032 0x04 +#define MT2030 0x06 +#define MT2040 0x07 +#define MT2050 0x42 + +static char *microtune_part[] = { + [ MT2030 ] = "MT2030", + [ MT2032 ] = "MT2032", + [ MT2040 ] = "MT2040", + [ MT2050 ] = "MT2050", +}; + +// IsSpurInBand()? +static int mt2032_spurcheck(struct i2c_client *c, + int f1, int f2, int spectrum_from,int spectrum_to) +{ + struct tuner *t = i2c_get_clientdata(c); + int n1=1,n2,f; + + f1=f1/1000; //scale to kHz to avoid 32bit overflows + f2=f2/1000; + spectrum_from/=1000; + spectrum_to/=1000; + + tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n", + f1,f2,spectrum_from,spectrum_to); + + do { + n2=-n1; + f=n1*(f1-f2); + do { + n2--; + f=f-f2; + tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); + + if( (f>spectrum_from) && (f(f2-spectrum_to)) || (n2>-5)); + n1++; + } while (n1<5); + + return 1; +} + +static int mt2032_compute_freq(struct i2c_client *c, + unsigned int rfin, + unsigned int if1, unsigned int if2, + unsigned int spectrum_from, + unsigned int spectrum_to, + unsigned char *buf, + int *ret_sel, + unsigned int xogc) //all in Hz +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, + desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; + + fref= 5250 *1000; //5.25MHz + desired_lo1=rfin+if1; + + lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); + lo1n=lo1/8; + lo1a=lo1-(lo1n*8); + + s=rfin/1000/1000+1090; + + if(optimize_vco) { + if(s>1890) sel=0; + else if(s>1720) sel=1; + else if(s>1530) sel=2; + else if(s>1370) sel=3; + else sel=4; // >1090 + } + else { + if(s>1790) sel=0; // <1958 + else if(s>1617) sel=1; + else if(s>1449) sel=2; + else if(s>1291) sel=3; + else sel=4; // >1090 + } + *ret_sel=sel; + + lo1freq=(lo1a+8*lo1n)*fref; + + tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", + rfin,lo1,lo1n,lo1a,sel,lo1freq); + + desired_lo2=lo1freq-rfin-if2; + lo2=(desired_lo2)/fref; + lo2n=lo2/8; + lo2a=lo2-(lo2n*8); + lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith + lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; + + tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", + rfin,lo2,lo2n,lo2a,lo2num,lo2freq); + + if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) { + tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", + lo1a, lo1n, lo2a,lo2n); + return(-1); + } + + mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to); + // should recalculate lo1 (one step up/down) + + // set up MT2032 register map for transfer over i2c + buf[0]=lo1n-1; + buf[1]=lo1a | (sel<<4); + buf[2]=0x86; // LOGC + buf[3]=0x0f; //reserved + buf[4]=0x1f; + buf[5]=(lo2n-1) | (lo2a<<5); + if(rfin >400*1000*1000) + buf[6]=0xe4; + else + buf[6]=0xf4; // set PKEN per rev 1.2 + buf[7]=8+xogc; + buf[8]=0xc3; //reserved + buf[9]=0x4e; //reserved + buf[10]=0xec; //reserved + buf[11]=(lo2num&0xff); + buf[12]=(lo2num>>8) |0x80; // Lo2RST + + return 0; +} + +static int mt2032_check_lo_lock(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + int try,lock=0; + unsigned char buf[2]; + + for(try=0;try<10;try++) { + buf[0]=0x0e; + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); + lock=buf[0] &0x06; + + if (lock==6) + break; + + tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); + udelay(1000); + } + return lock; +} + +static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buf[2]; + int tad1; + + buf[0]=0x0f; + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); + tad1=buf[0]&0x07; + + if(tad1 ==0) return lock; + if(tad1 ==1) return lock; + + if(tad1==2) { + if(sel==0) + return lock; + else sel--; + } + else { + if(sel<4) + sel++; + else + return lock; + } + + tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel); + + buf[0]=0x0f; + buf[1]=sel; + i2c_master_send(c,buf,2); + lock=mt2032_check_lo_lock(c); + return lock; +} + + +static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, + unsigned int if1, unsigned int if2, + unsigned int from, unsigned int to) +{ + unsigned char buf[21]; + int lint_try,ret,sel,lock=0; + struct tuner *t = i2c_get_clientdata(c); + + tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", + rfin,if1,if2,from,to); + + buf[0]=0; + ret=i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,21); + + buf[0]=0; + ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc); + if (ret<0) + return; + + // send only the relevant registers per Rev. 1.2 + buf[0]=0; + ret=i2c_master_send(c,buf,4); + buf[5]=5; + ret=i2c_master_send(c,buf+5,4); + buf[11]=11; + ret=i2c_master_send(c,buf+11,3); + if(ret!=3) + tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); + + // wait for PLLs to lock (per manual), retry LINT if not. + for(lint_try=0; lint_try<2; lint_try++) { + lock=mt2032_check_lo_lock(c); + + if(optimize_vco) + lock=mt2032_optimize_vco(c,sel,lock); + if(lock==6) break; + + tuner_dbg("mt2032: re-init PLLs by LINT\n"); + buf[0]=7; + buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs + i2c_master_send(c,buf,2); + mdelay(10); + buf[1]=8+t->xogc; + i2c_master_send(c,buf,2); + } + + if (lock!=6) + tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n"); + + buf[0]=2; + buf[1]=0x20; // LOGC for optimal phase noise + ret=i2c_master_send(c,buf,2); + if (ret!=2) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); +} + + +static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + int if2,from,to; + + // signal bandwidth and picture carrier + if (t->std & V4L2_STD_525_60) { + // NTSC + from = 40750*1000; + to = 46750*1000; + if2 = 45750*1000; + } else { + // PAL + from = 32900*1000; + to = 39900*1000; + if2 = 38900*1000; + } + + mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, + 1090*1000*1000, if2, from, to); +} + +static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + int if2 = t->radio_if2; + + // per Manual for FM tuning: first if center freq. 1085 MHz + mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, + 1085*1000*1000,if2,if2,if2); +} + +// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 +static int mt2032_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buf[21]; + int ret,xogc,xok=0; + + // Initialize Registers per spec. + buf[1]=2; // Index to register 2 + buf[2]=0xff; + buf[3]=0x0f; + buf[4]=0x1f; + ret=i2c_master_send(c,buf+1,4); + + buf[5]=6; // Index register 6 + buf[6]=0xe4; + buf[7]=0x8f; + buf[8]=0xc3; + buf[9]=0x4e; + buf[10]=0xec; + ret=i2c_master_send(c,buf+5,6); + + buf[12]=13; // Index register 13 + buf[13]=0x32; + ret=i2c_master_send(c,buf+12,2); + + // Adjust XOGC (register 7), wait for XOK + xogc=7; + do { + tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); + mdelay(10); + buf[0]=0x0e; + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + xok=buf[0]&0x01; + tuner_dbg("mt2032: xok = 0x%02x\n",xok); + if (xok == 1) break; + + xogc--; + tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); + if (xogc == 3) { + xogc=4; // min. 4 per spec + break; + } + buf[0]=0x07; + buf[1]=0x88 + xogc; + ret=i2c_master_send(c,buf,2); + if (ret!=2) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); + } while (xok != 1 ); + t->xogc=xogc; + + t->tv_freq = mt2032_set_tv_freq; + t->radio_freq = mt2032_set_radio_freq; + return(1); +} + +static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buf[2]; + int ret; + + buf[0] = 6; + buf[1] = antenna ? 0x11 : 0x10; + ret=i2c_master_send(c,buf,2); + tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); +} + +static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned int if1=1218*1000*1000; + unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; + int ret; + unsigned char buf[6]; + + tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", + freq,if1,if2); + + f_lo1=freq+if1; + f_lo1=(f_lo1/1000000)*1000000; + + f_lo2=f_lo1-freq-if2; + f_lo2=(f_lo2/50000)*50000; + + lo1=f_lo1/4000000; + lo2=f_lo2/4000000; + + f_lo1_modulo= f_lo1-(lo1*4000000); + f_lo2_modulo= f_lo2-(lo2*4000000); + + num1=4*f_lo1_modulo/4000000; + num2=4096*(f_lo2_modulo/1000)/4000; + + // todo spurchecks + + div1a=(lo1/12)-1; + div1b=lo1-(div1a+1)*12; + + div2a=(lo2/8)-1; + div2b=lo2-(div2a+1)*8; + + if (tuner_debug > 1) { + tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); + tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", + num1,num2,div1a,div1b,div2a,div2b); + } + + buf[0]=1; + buf[1]= 4*div1b + num1; + if(freq<275*1000*1000) buf[1] = buf[1]|0x80; + + buf[2]=div1a; + buf[3]=32*div2b + num2/256; + buf[4]=num2-(num2/256)*256; + buf[5]=div2a; + if(num2!=0) buf[5]=buf[5]|0x40; + + if (tuner_debug > 1) { + int i; + tuner_dbg("bufs is: "); + for(i=0;i<6;i++) + printk("%x ",buf[i]); + printk("\n"); + } + + ret=i2c_master_send(c,buf,6); + if (ret!=6) + tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); +} + +static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned int if2; + + if (t->std & V4L2_STD_525_60) { + // NTSC + if2 = 45750*1000; + } else { + // PAL + if2 = 38900*1000; + } + if (V4L2_TUNER_DIGITAL_TV == t->mode) { + // DVB (pinnacle 300i) + if2 = 36150*1000; + } + mt2050_set_if_freq(c, freq*62500, if2); + mt2050_set_antenna(c, tv_antenna); +} + +static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + int if2 = t->radio_if2; + + mt2050_set_if_freq(c, freq*62500, if2); + mt2050_set_antenna(c, radio_antenna); +} + +static int mt2050_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buf[2]; + int ret; + + buf[0]=6; + buf[1]=0x10; + ret=i2c_master_send(c,buf,2); // power + + buf[0]=0x0f; + buf[1]=0x0f; + ret=i2c_master_send(c,buf,2); // m1lo + + buf[0]=0x0d; + ret=i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + + tuner_dbg("mt2050: sro is %x\n",buf[0]); + t->tv_freq = mt2050_set_tv_freq; + t->radio_freq = mt2050_set_radio_freq; + return 0; +} + +int microtune_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + char *name; + unsigned char buf[21]; + int company_code; + + memset(buf,0,sizeof(buf)); + t->tv_freq = NULL; + t->radio_freq = NULL; + name = "unknown"; + + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,21); + if (tuner_debug) { + int i; + tuner_dbg("MT20xx hexdump:"); + for(i=0;i<21;i++) { + printk(" %02x",buf[i]); + if(((i+1)%8)==0) printk(" "); + } + printk("\n"); + } + company_code = buf[0x11] << 8 | buf[0x12]; + tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", + company_code,buf[0x13],buf[0x14]); + +#if 0 + /* seems to cause more problems than it solves ... */ + switch (company_code) { + case 0x30bf: + case 0x3cbf: + case 0x3dbf: + case 0x4d54: + case 0x8e81: + case 0x8e91: + /* ok (?) */ + break; + default: + tuner_warn("tuner: microtune: unknown companycode\n"); + return 0; + } +#endif + + if (buf[0x13] < ARRAY_SIZE(microtune_part) && + NULL != microtune_part[buf[0x13]]) + name = microtune_part[buf[0x13]]; + switch (buf[0x13]) { + case MT2032: + mt2032_init(c); + break; + case MT2050: + mt2050_init(c); + break; + default: + tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", + name); + return 0; + } + + strlcpy(c->name, name, sizeof(c->name)); + tuner_info("microtune %s found, OK\n",name); + return 0; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/video/planb.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/planb.c 2005-03-07 10:14:57.000000000 +0100 +++ linux-2.6.11/drivers/media/video/planb.c 2005-03-08 10:33:15.000000000 +0100 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1609,8 +1610,7 @@ static int planb_ioctl(struct video_devi } planb_lock(pb); /* empty the grabbing queue */ - while(pb->grabbing) - interruptible_sleep_on(&pb->capq); + wait_event(pb->capq, !pb->grabbing); pb->maxlines = maxlines; pb->win.norm = v.norm; /* Stop overlay if running */ Index: linux-2.6.11/drivers/media/video/saa5246a.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa5246a.c 2005-03-07 10:13:46.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa5246a.c 2005-03-08 10:33:15.000000000 +0100 @@ -65,18 +65,7 @@ static struct video_device saa_template; /* Addresses to scan */ static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END }; static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; - -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; +I2C_CLIENT_INSMOD; static struct i2c_client client_template; Index: linux-2.6.11/drivers/media/video/saa5249.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa5249.c 2005-03-07 10:14:50.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa5249.c 2005-03-08 10:33:15.000000000 +0100 @@ -133,18 +133,7 @@ static struct video_device saa_template; /* Addresses to scan */ static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END}; static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; - -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; +I2C_CLIENT_INSMOD; static struct i2c_client client_template; Index: linux-2.6.11/drivers/media/video/saa7110.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7110.c 2005-03-07 10:12:20.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7110.c 2005-03-08 10:33:15.000000000 +0100 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -205,13 +206,16 @@ static const unsigned char initseq[] = { static int determine_norm (struct i2c_client *client) { + DEFINE_WAIT(wait); struct saa7110 *decoder = i2c_get_clientdata(client); int status; /* mode changed, start automatic detection */ saa7110_write_block(client, initseq, sizeof(initseq)); saa7110_selmux(client, decoder->input); - sleep_on_timeout(&decoder->wq, HZ / 4); + prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/4); + finish_wait(&decoder->wq, &wait); status = saa7110_read(client); if (status & 0x40) { dprintk(1, KERN_INFO "%s: status=0x%02x (no signal)\n", @@ -250,7 +254,9 @@ determine_norm (struct i2c_client *clien saa7110_write(client, 0x11, 0x59); //saa7110_write(client,0x2E,0x9A); - sleep_on_timeout(&decoder->wq, HZ / 4); + prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/4); + finish_wait(&decoder->wq, &wait); status = saa7110_read(client); if ((status & 0x03) == 0x01) { Index: linux-2.6.11/drivers/media/video/saa7134/Makefile =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/Makefile 2005-03-07 10:16:02.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/Makefile 2005-03-08 10:33:27.000000000 +0100 @@ -8,3 +8,4 @@ obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa71 EXTRA_CFLAGS += -I$(src)/.. EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core +EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends Index: linux-2.6.11/drivers/media/video/saa7134/saa6752hs.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa6752hs.c 2005-03-07 10:15:39.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa6752hs.c 2005-03-08 10:33:27.000000000 +0100 @@ -11,9 +11,14 @@ #include #include #include +#include #include -#include + +#define MPEG_VIDEO_TARGET_BITRATE_MAX 27000 +#define MPEG_VIDEO_MAX_BITRATE_MAX 27000 +#define MPEG_TOTAL_TARGET_BITRATE_MAX 27000 +#define MPEG_PID_MAX ((1 << 14) - 1) /* Addresses to scan */ static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END}; @@ -27,6 +32,10 @@ MODULE_LICENSE("GPL"); static struct i2c_driver driver; static struct i2c_client client_template; +struct saa6752hs_state { + struct i2c_client client; + struct v4l2_mpeg_compression params; +}; enum saa6752hs_command { SAA6752HS_COMMAND_RESET = 0, @@ -40,7 +49,6 @@ enum saa6752hs_command { SAA6752HS_COMMAND_MAX }; - /* ---------------------------------------------------------------------- */ static u8 PAT[] = { @@ -64,9 +72,9 @@ static u8 PAT[] = { 0x00, 0x01, // program_number(1) - 0xe0, 0x10, // PMT PID(0x10) + 0xe0, 0x00, // PMT PID - 0x76, 0xf1, 0x44, 0xd1 // CRC32 + 0x00, 0x00, 0x00, 0x00 // CRC32 }; static u8 PMT[] = { @@ -74,7 +82,7 @@ static u8 PMT[] = { 0x01, // table number for encoder 0x47, // sync - 0x40, 0x10, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0x10) + 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) 0x00, // PSI pointer to start of table @@ -88,27 +96,50 @@ static u8 PMT[] = { 0x00, 0x00, // section_number(0), last_section_number(0) - 0xe1, 0x04, // PCR_PID (0x104) + 0xe0, 0x00, // PCR_PID 0xf0, 0x00, // program_info_length(0) - 0x02, 0xe1, 0x00, 0xf0, 0x00, // video stream type(2), pid(0x100) - 0x04, 0xe1, 0x03, 0xf0, 0x00, // audio stream type(4), pid(0x103) + 0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid + 0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid - 0xa1, 0xca, 0x0f, 0x82 // CRC32 + 0x00, 0x00, 0x00, 0x00 // CRC32 }; -static struct mpeg_params mpeg_params_template = +static struct v4l2_mpeg_compression param_defaults = { - .bitrate_mode = MPEG_BITRATE_MODE_CBR, - .video_target_bitrate = 5000, - .audio_bitrate = MPEG_AUDIO_BITRATE_256, - .total_bitrate = 6000, -}; + .st_type = V4L2_MPEG_TS_2, + .st_bitrate = { + .mode = V4L2_BITRATE_CBR, + .target = 7000, + }, + .ts_pid_pmt = 16, + .ts_pid_video = 260, + .ts_pid_audio = 256, + .ts_pid_pcr = 259, -/* ---------------------------------------------------------------------- */ + .vi_type = V4L2_MPEG_VI_2, + .vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3, + .vi_bitrate = { + .mode = V4L2_BITRATE_VBR, + .target = 4000, + .max = 6000, + }, + .au_type = V4L2_MPEG_AU_2_II, + .au_bitrate = { + .mode = V4L2_BITRATE_CBR, + .target = 256, + }, + +#if 0 + /* FIXME: size? via S_FMT? */ + .video_format = MPEG_VIDEO_FORMAT_D1, +#endif +}; + +/* ---------------------------------------------------------------------- */ static int saa6752hs_chip_command(struct i2c_client* client, enum saa6752hs_command command) @@ -124,7 +155,7 @@ static int saa6752hs_chip_command(struct break; case SAA6752HS_COMMAND_STOP: - buf[0] = 0x03; + buf[0] = 0x03; break; case SAA6752HS_COMMAND_START: @@ -180,74 +211,117 @@ static int saa6752hs_chip_command(struct static int saa6752hs_set_bitrate(struct i2c_client* client, - struct mpeg_params* params) + struct v4l2_mpeg_compression* params) { u8 buf[3]; // set the bitrate mode buf[0] = 0x71; - buf[1] = params->bitrate_mode; + buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1; i2c_master_send(client, buf, 2); // set the video bitrate - if (params->bitrate_mode == MPEG_BITRATE_MODE_VBR) { + if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) { // set the target bitrate buf[0] = 0x80; - buf[1] = params->video_target_bitrate >> 8; - buf[2] = params->video_target_bitrate & 0xff; + buf[1] = params->vi_bitrate.target >> 8; + buf[2] = params->vi_bitrate.target & 0xff; i2c_master_send(client, buf, 3); // set the max bitrate buf[0] = 0x81; - buf[1] = params->video_max_bitrate >> 8; - buf[2] = params->video_max_bitrate & 0xff; + buf[1] = params->vi_bitrate.max >> 8; + buf[2] = params->vi_bitrate.max & 0xff; i2c_master_send(client, buf, 3); } else { // set the target bitrate (no max bitrate for CBR) buf[0] = 0x81; - buf[1] = params->video_target_bitrate >> 8; - buf[2] = params->video_target_bitrate & 0xff; + buf[1] = params->vi_bitrate.target >> 8; + buf[2] = params->vi_bitrate.target & 0xff; i2c_master_send(client, buf, 3); } // set the audio bitrate buf[0] = 0x94; - buf[1] = params->audio_bitrate; + buf[1] = (256 == params->au_bitrate.target) ? 0 : 1; i2c_master_send(client, buf, 2); // set the total bitrate buf[0] = 0xb1; - buf[1] = params->total_bitrate >> 8; - buf[2] = params->total_bitrate & 0xff; + buf[1] = params->st_bitrate.target >> 8; + buf[2] = params->st_bitrate.target & 0xff; i2c_master_send(client, buf, 3); + // return success return 0; } -static int saa6752hs_init(struct i2c_client* client, struct mpeg_params* params) +static void saa6752hs_set_params(struct i2c_client* client, + struct v4l2_mpeg_compression* params) { - unsigned char buf[3]; - void *data; + struct saa6752hs_state *h = i2c_get_clientdata(client); - // check the bitrate parameters first - if (params != NULL) { - if (params->bitrate_mode >= MPEG_BITRATE_MODE_MAX) - return -EINVAL; - if (params->video_target_bitrate >= MPEG_VIDEO_TARGET_BITRATE_MAX) - return -EINVAL; - if (params->video_max_bitrate >= MPEG_VIDEO_MAX_BITRATE_MAX) - return -EINVAL; - if (params->audio_bitrate >= MPEG_AUDIO_BITRATE_MAX) - return -EINVAL; - if (params->total_bitrate >= MPEG_TOTAL_BITRATE_MAX) - return -EINVAL; - if (params->bitrate_mode == MPEG_BITRATE_MODE_MAX && - params->video_target_bitrate <= params->video_max_bitrate) - return -EINVAL; - } + /* check PIDs */ + if (params->ts_pid_pmt <= MPEG_PID_MAX) + h->params.ts_pid_pmt = params->ts_pid_pmt; + if (params->ts_pid_pcr <= MPEG_PID_MAX) + h->params.ts_pid_pcr = params->ts_pid_pcr; + if (params->ts_pid_video <= MPEG_PID_MAX) + h->params.ts_pid_video = params->ts_pid_video; + if (params->ts_pid_audio <= MPEG_PID_MAX) + h->params.ts_pid_audio = params->ts_pid_audio; - // Set GOP structure {3, 13} + /* check bitrate parameters */ + if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) || + (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) + h->params.vi_bitrate.mode = params->vi_bitrate.mode; + if (params->vi_bitrate.mode != V4L2_BITRATE_NONE) + h->params.st_bitrate.target = params->st_bitrate.target; + if (params->vi_bitrate.mode != V4L2_BITRATE_NONE) + h->params.vi_bitrate.target = params->vi_bitrate.target; + if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) + h->params.vi_bitrate.max = params->vi_bitrate.max; + if (params->au_bitrate.mode != V4L2_BITRATE_NONE) + h->params.au_bitrate.target = params->au_bitrate.target; + + /* aspect ratio */ + if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 || + params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) + h->params.vi_aspect_ratio = params->vi_aspect_ratio; + + /* range checks */ + if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX) + h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX; + if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX) + h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX; + if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX) + h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX; + if (h->params.au_bitrate.target <= 256) + h->params.au_bitrate.target = 256; + else + h->params.au_bitrate.target = 384; +} + +static int saa6752hs_init(struct i2c_client* client) +{ + unsigned char buf[9], buf2[4]; + struct saa6752hs_state *h; + u32 crc; + unsigned char localPAT[256]; + unsigned char localPMT[256]; + + h = i2c_get_clientdata(client); + + // Set video format - must be done first as it resets other settings + buf[0] = 0x41; + buf[1] = 0 /* MPEG_VIDEO_FORMAT_D1 */; + i2c_master_send(client, buf, 2); + + // set bitrate + saa6752hs_set_bitrate(client, &h->params); + + // Set GOP structure {3, 13} buf[0] = 0x72; buf[1] = 0x03; buf[2] = 0x0D; @@ -265,7 +339,7 @@ static int saa6752hs_init(struct i2c_cli // Set Output Protocol buf[0] = 0xD0; - buf[1] = 0x01; + buf[1] = 0x81; i2c_master_send(client,buf,2); // Set video output stream format {TS} @@ -273,25 +347,53 @@ static int saa6752hs_init(struct i2c_cli buf[1] = 0x05; i2c_master_send(client,buf,2); - // Set Audio PID {0x103} + /* compute PAT */ + memcpy(localPAT, PAT, sizeof(PAT)); + localPAT[17] = 0xe0 | ((h->params.ts_pid_pmt >> 8) & 0x0f); + localPAT[18] = h->params.ts_pid_pmt & 0xff; + crc = crc32_be(~0, &localPAT[7], sizeof(PAT) - 7 - 4); + localPAT[sizeof(PAT) - 4] = (crc >> 24) & 0xFF; + localPAT[sizeof(PAT) - 3] = (crc >> 16) & 0xFF; + localPAT[sizeof(PAT) - 2] = (crc >> 8) & 0xFF; + localPAT[sizeof(PAT) - 1] = crc & 0xFF; + + /* compute PMT */ + memcpy(localPMT, PMT, sizeof(PMT)); + localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f); + localPMT[4] = h->params.ts_pid_pmt & 0xff; + localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F); + localPMT[16] = h->params.ts_pid_pcr & 0xFF; + localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F); + localPMT[21] = h->params.ts_pid_video & 0xFF; + localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F); + localPMT[26] = h->params.ts_pid_audio & 0xFF; + crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4); + localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF; + localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF; + localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF; + localPMT[sizeof(PMT) - 1] = crc & 0xFF; + + // Set Audio PID buf[0] = 0xC1; - buf[1] = 0x01; - buf[2] = 0x03; + buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF; + buf[2] = h->params.ts_pid_audio & 0xFF; i2c_master_send(client,buf,3); - // setup bitrate settings - data = i2c_get_clientdata(client); - if (params) { - saa6752hs_set_bitrate(client, params); - memcpy(data, params, sizeof(struct mpeg_params)); - } else { - // parameters were not supplied. use the previous set - saa6752hs_set_bitrate(client, (struct mpeg_params*) data); - } + // Set Video PID + buf[0] = 0xC0; + buf[1] = (h->params.ts_pid_video >> 8) & 0xFF; + buf[2] = h->params.ts_pid_video & 0xFF; + i2c_master_send(client,buf,3); + + // Set PCR PID + buf[0] = 0xC4; + buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF; + buf[2] = h->params.ts_pid_pcr & 0xFF; + i2c_master_send(client,buf,3); // Send SI tables - i2c_master_send(client,PAT,sizeof(PAT)); - i2c_master_send(client,PMT,sizeof(PMT)); + i2c_master_send(client,localPAT,sizeof(PAT)); + i2c_master_send(client,localPMT,sizeof(PMT)); // mute then unmute audio. This removes buzzing artefacts buf[0] = 0xa4; @@ -303,31 +405,56 @@ static int saa6752hs_init(struct i2c_cli // start it going saa6752hs_chip_command(client, SAA6752HS_COMMAND_START); + // readout current state + buf[0] = 0xE1; + buf[1] = 0xA7; + buf[2] = 0xFE; + buf[3] = 0x82; + buf[4] = 0xB0; + i2c_master_send(client, buf, 5); + i2c_master_recv(client, buf2, 4); + + // change aspect ratio + buf[0] = 0xE0; + buf[1] = 0xA7; + buf[2] = 0xFE; + buf[3] = 0x82; + buf[4] = 0xB0; + buf[5] = buf2[0]; + switch(h->params.vi_aspect_ratio) { + case V4L2_MPEG_ASPECT_16_9: + buf[6] = buf2[1] | 0x40; + break; + case V4L2_MPEG_ASPECT_4_3: + default: + buf[6] = buf2[1] & 0xBF; + break; + break; + } + buf[7] = buf2[2]; + buf[8] = buf2[3]; + i2c_master_send(client, buf, 9); + + // return success return 0; } static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind) { - struct i2c_client *client; - struct mpeg_params* params; - - client_template.adapter = adap; - client_template.addr = addr; + struct saa6752hs_state *h; printk("saa6752hs: chip found @ 0x%x\n", addr<<1); - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) + if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL))) return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - strlcpy(client->name, "saa6752hs", sizeof(client->name)); - - if (NULL == (params = kmalloc(sizeof(struct mpeg_params), GFP_KERNEL))) - return -ENOMEM; - memcpy(params,&mpeg_params_template,sizeof(struct mpeg_params)); - i2c_set_clientdata(client, params); - - i2c_attach_client(client); + memset(h,0,sizeof(*h)); + h->client = client_template; + h->params = param_defaults; + h->client.adapter = adap; + h->client.addr = addr; + i2c_set_clientdata(&h->client, h); + i2c_attach_client(&h->client); return 0; } @@ -340,30 +467,39 @@ static int saa6752hs_probe(struct i2c_ad static int saa6752hs_detach(struct i2c_client *client) { - void *data; + struct saa6752hs_state *h; - data = i2c_get_clientdata(client); + h = i2c_get_clientdata(client); i2c_detach_client(client); - kfree(data); - kfree(client); + kfree(h); return 0; } static int saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct mpeg_params* init_arg = arg; + struct saa6752hs_state *h = i2c_get_clientdata(client); + struct v4l2_mpeg_compression *params = arg; + int err = 0; switch (cmd) { - case MPEG_SETPARAMS: - return saa6752hs_init(client, init_arg); - + case VIDIOC_S_MPEGCOMP: + if (NULL == params) { + /* apply settings and start encoder */ + saa6752hs_init(client); + break; + } + saa6752hs_set_params(client, params); + /* fall through */ + case VIDIOC_G_MPEGCOMP: + *params = h->params; + break; default: /* nothing */ break; } - return 0; + return err; } /* ----------------------------------------------------------------------- */ @@ -380,7 +516,7 @@ static struct i2c_driver driver = { static struct i2c_client client_template = { - I2C_DEVNAME("(saa6752hs unset)"), + I2C_DEVNAME("saa6752hs"), .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, }; Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-cards.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-cards.c 2005-03-07 10:15:07.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-cards.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,6 @@ + /* - * $Id: saa7134-cards.c,v 1.35 2004/11/07 14:44:59 kraxel Exp $ + * $Id: saa7134-cards.c,v 1.54 2005/03/07 12:01:51 kraxel Exp $ * * device driver for philips saa7134 based TV cards * card-specific stuff. @@ -156,11 +157,11 @@ struct saa7134_board saa7134_boards[] = .gpio = 0x8000, }, }, - [SAA7134_BOARD_FLYTVPLATINUM] = { + [SAA7134_BOARD_FLYTVPLATINUM_MINI] = { /* "Arnaud Quette" */ - .name = "LifeView FlyTV Platinum", + .name = "LifeView FlyTV Platinum Mini", .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_SECAM, + .tuner_type = TUNER_PHILIPS_TDA8290, .inputs = {{ .name = name_tv, .vmux = 1, @@ -176,6 +177,47 @@ struct saa7134_board saa7134_boards[] = .amux = LINE2, }}, }, + [SAA7134_BOARD_FLYTVPLATINUM_FM] = { + /* LifeView FlyTV Platinum FM (LR214WF) */ + /* "Peter Missel */ + .name = "LifeView FlyTV Platinum FM", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_TDA8290, +// .gpiomask = 0xe000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, +// .gpio = 0x0000, + .tv = 1, + },{ +/* .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .gpio = 0x0000, + .tv = 1, + },{ +*/ .name = name_comp1, /* Composite signal on S-Video input */ + .vmux = 0, + .amux = LINE2, +// .gpio = 0x4000, + },{ + .name = name_comp2, /* Composite input */ + .vmux = 3, + .amux = LINE2, +// .gpio = 0x4000, + },{ + .name = name_svideo, /* S-Video signal on S-Video input */ + .vmux = 8, + .amux = LINE2, +// .gpio = 0x4000, + }}, +/* .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x2000, + }, +*/ }, [SAA7134_BOARD_EMPRESS] = { /* "Gert Vervoort" */ .name = "EMPRESS", @@ -436,6 +478,7 @@ struct saa7134_board saa7134_boards[] = .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .tda9887_conf = TDA9887_PRESENT, + .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, .vmux = 1, @@ -444,11 +487,11 @@ struct saa7134_board saa7134_boards[] = },{ .name = name_comp1, .vmux = 0, - .amux = LINE2, + .amux = LINE1, },{ .name = name_svideo, .vmux = 8, - .amux = LINE2, + .amux = LINE1, }}, .radio = { .name = name_radio, @@ -544,6 +587,34 @@ struct saa7134_board saa7134_boards[] = .amux = LINE1, }, }, + [SAA7135_BOARD_ASUSTeK_TVFM7135] = { + .name = "ASUS TV-FM 7135", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .gpiomask = 0x200000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .gpio = 0x0000, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE2, + .gpio = 0x0000, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE2, + .gpio = 0x0000, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x200000, + }, + }, [SAA7134_BOARD_VA1000POWER] = { .name = "AOPEN VA1000 POWER", .audio_clock = 0x00187de7, @@ -749,7 +820,7 @@ struct saa7134_board saa7134_boards[] = },{ .name = name_tv, .vmux = 3, - .amux = LINE2, + .amux = TV, .tv = 1, }}, .mpeg = SAA7134_MPEG_EMPRESS, @@ -828,6 +899,10 @@ struct saa7134_board saa7134_boards[] = .name = name_radio, .amux = LINE2, }, + .mute = { + .name = name_mute, + .amux = LINE1, + }, }, [SAA7134_BOARD_MANLI_MTV001] = { /* Ognjen Nastic UNTESTED */ @@ -975,6 +1050,9 @@ struct saa7134_board saa7134_boards[] = .inputs = {{ .name = name_comp1, .vmux = 3, + },{ + .name = name_svideo, + .vmux = 8, }}, }, [SAA7134_BOARD_NOVAC_PRIMETV7133] = { @@ -995,11 +1073,12 @@ struct saa7134_board saa7134_boards[] = .vmux = 8, }}, }, - [SAA7134_BOARD_AVERMEDIA_305] = { - .name = "AverMedia 305", + [SAA7134_BOARD_AVERMEDIA_STUDIO_305] = { + .name = "AverMedia AverTV Studio 305", .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tuner_type = TUNER_PHILIPS_FM1256_IH3, .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x3, .inputs = {{ .name = name_tv, .vmux = 1, @@ -1104,23 +1183,23 @@ struct saa7134_board saa7134_boards[] = .name = name_svideo, .vmux = 8, .amux = LINE1, - .gpio = 0x00080 + .gpio = 0x00080, },{ .name = name_comp1, .vmux = 3, .amux = LINE1, - .gpio = 0x00080 + .gpio = 0x00080, },{ .name = name_tv, .vmux = 1, - .amux = LINE2, + .amux = LINE2_LEFT, .tv = 1, - .gpio = 0x00080 + .gpio = 0x00080, }}, .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x80000 + .name = name_radio, + .amux = LINE2, + .gpio = 0x80000, }, .mute = { .name = name_mute, @@ -1129,21 +1208,20 @@ struct saa7134_board saa7134_boards[] = }, }, [SAA7134_BOARD_SABRENT_SBTTVFM] = { - /* Michael Rodriguez-Torrent */ + /* Michael Rodriguez-Torrent */ .name = "Sabrent SBT-TVFM (saa7130)", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, - .tda9887_conf = TDA9887_PRESENT, .inputs = {{ + .name = name_comp1, + .vmux = 1, + .amux = LINE2, + },{ .name = name_tv, .vmux = 3, .amux = LINE2, .tv = 1, },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE2, - },{ .name = name_svideo, .vmux = 8, .amux = LINE2, @@ -1208,32 +1286,41 @@ struct saa7134_board saa7134_boards[] = } }, [SAA7134_BOARD_AVERMEDIA_307] = { - /* Nickolay V. Shmyrev */ + /* + Nickolay V. Shmyrev + Lots of thanks to Andrey Zolotarev + */ .name = "Avermedia AVerTV Studio 307", .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tuner_type = TUNER_PHILIPS_FM1256_IH3, .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x03, .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, .tv = 1, + .gpio = 0x00, },{ .name = name_comp1, .vmux = 0, .amux = LINE2, + .gpio = 0x00, },{ .name = name_comp2, .vmux = 3, .amux = LINE2, + .gpio = 0x00, },{ .name = name_svideo, .vmux = 8, .amux = LINE2, + .gpio = 0x00, }}, .radio = { .name = name_radio, - .amux = TV, + .amux = LINE1, + .gpio = 0x01, }, }, [SAA7134_BOARD_AVERMEDIA_CARDBUS] = { @@ -1263,10 +1350,17 @@ struct saa7134_board saa7134_boards[] = [SAA7134_BOARD_CINERGY400_CARDBUS] = { .name = "Terratec Cinergy 400 mobile", .audio_clock = 0x187de7, - .tuner_type = UNSET /* not supported yet :/ */, + .tuner_type = TUNER_ALPS_TSBE5_PAL, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, - .vmux = 5, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, .tv = 1, },{ .name = name_comp1, @@ -1274,8 +1368,182 @@ struct saa7134_board saa7134_boards[] = .amux = LINE1, },{ .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_CINERGY600_MK3] = { + .name = "Terratec Cinergy 600 TV MK3", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, .vmux = 4, .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp2, // CVideo over SVideo Connector + .vmux = 0, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = { + /* Dylan Walkden */ + .name = "Compro VideoMate Gold+ Pal", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_PAL, + .gpiomask = 0x1ce780, + .inputs = {{ + .name = name_svideo, + .vmux = 0, // CVideo over SVideo Connector - ok? + .amux = LINE1, + .gpio = 0x008080, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x008080, + },{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x008080, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x80000, + }, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x0c8000, + }, + }, + [SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = { + .name = "Pinnacle PCTV 300i DVB-T + PAL", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_MT2032, + .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_PROVIDEO_PV952] = { + /* andreas.kretschmer@web.de */ + .name = "ProVideo PV952", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_AVERMEDIA_305] = { + /* much like the "studio" version but without radio + * and another tuner (sirspiritus@yandex.ru) */ + .name = "AverMedia AverTV/305", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x3, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + }, + [SAA7134_BOARD_FLYDVBTDUO] = { + /* LifeView FlyDVB-T DUO */ + /* "Nico Sabbi */ + .name = "LifeView FlyDVB-T DUO", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_TDA8290, +// .gpiomask = 0xe000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, +// .gpio = 0x0000, + .tv = 1, + },{ + .name = name_comp1, /* Composite signal on S-Video input */ + .vmux = 0, + .amux = LINE2, +// .gpio = 0x4000, + },{ + .name = name_comp2, /* Composite input */ + .vmux = 3, + .amux = LINE2, +// .gpio = 0x4000, + },{ + .name = name_svideo, /* S-Video signal on S-Video input */ + .vmux = 8, + .amux = LINE2, +// .gpio = 0x4000, }}, }, }; @@ -1322,6 +1590,12 @@ struct pci_device_id saa7134_pci_tbl[] = .subdevice = 0x1143, .driver_data = SAA7134_BOARD_CINERGY600, },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x153B, + .subdevice = 0x1158, + .driver_data = SAA7134_BOARD_CINERGY600_MK3, + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x153b, @@ -1349,8 +1623,14 @@ struct pci_device_id saa7134_pci_tbl[] = .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7135, .subvendor = 0x5168, - .subdevice = 0x0212, - .driver_data = SAA7134_BOARD_FLYTVPLATINUM, + .subdevice = 0x0212, /* minipci, LR212 */ + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5168, + .subdevice = 0x0214, /* Standard PCI, LR214WF */ + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -1377,6 +1657,12 @@ struct pci_device_id saa7134_pci_tbl[] = .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, },{ .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4845, + .driver_data = SAA7135_BOARD_ASUSTeK_TVFM7135, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = PCI_VENDOR_ID_ASUSTEK, .subdevice = 0x4830, @@ -1452,6 +1738,12 @@ struct pci_device_id saa7134_pci_tbl[] = .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0x2115, + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x2108, .driver_data = SAA7134_BOARD_AVERMEDIA_305, },{ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -1483,8 +1775,8 @@ struct pci_device_id saa7134_pci_tbl[] = .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x11bd, - .subdevice = 0x002d, /* 300i DVB-T + PAL */ - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, + .subdevice = 0x002d, + .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -1509,20 +1801,43 @@ struct pci_device_id saa7134_pci_tbl[] = .subvendor = 0x153B, .subdevice = 0x1152, .driver_data = SAA7134_BOARD_CINERGY200, - },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x185b, .subdevice = 0xc100, .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, - },{ .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x1131, + .subdevice = 0, + .driver_data = SAA7134_BOARD_SABRENT_SBTTVFM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x9715, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x9715, .driver_data = SAA7134_BOARD_AVERMEDIA_307, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x185b, + .subdevice = 0xc200, + .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1540, + .subdevice = 0x9524, + .driver_data = SAA7134_BOARD_PROVIDEO_PV952, + + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5168, + .subdevice = 0x0306, + .driver_data = SAA7134_BOARD_FLYDVBTDUO, },{ /* --- boards without eeprom + subsystem ID --- */ @@ -1631,16 +1946,19 @@ int saa7134_board_init1(struct saa7134_d case SAA7134_BOARD_FLYVIDEO2000: case SAA7134_BOARD_FLYVIDEO3000: dev->has_remote = 1; - /* fall throuth */ - case SAA7134_BOARD_FLYTVPLATINUM: board_flyvideo(dev); break; case SAA7134_BOARD_CINERGY400: case SAA7134_BOARD_CINERGY600: + case SAA7134_BOARD_CINERGY600_MK3: case SAA7134_BOARD_ECS_TVP3XP: case SAA7134_BOARD_ECS_TVP3XP_4CB5: case SAA7134_BOARD_MD2819: + case SAA7134_BOARD_AVERMEDIA_STUDIO_305: + case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_307: +// case SAA7134_BOARD_SABRENT_SBTTVFM: /* not finished yet */ + case SAA7134_BOARD_VIDEOMATE_TV_PVR: dev->has_remote = 1; break; case SAA7134_BOARD_AVACSSMARTTV: @@ -1656,8 +1974,13 @@ int saa7134_board_init1(struct saa7134_d /* power-up tuner chip */ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000); + msleep(1); break; } + if (dev->has_remote) + dev->irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 | + SAA7134_IRQ2_INTE_GPIO18A | + SAA7134_IRQ2_INTE_GPIO16 ); return 0; } @@ -1676,6 +1999,7 @@ int saa7134_board_init2(struct saa7134_d : SAA7134_BOARD_BMK_MPEX_TUNER; if (board == dev->board) break; + dev->board = board; printk("%s: board type fixup: %s\n", dev->name, saa7134_boards[dev->board].name); dev->tuner_type = saa7134_boards[dev->board].tuner_type; Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-core.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-core.c 2005-03-07 10:13:26.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-core.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-core.c,v 1.15 2004/11/07 14:44:59 kraxel Exp $ + * $Id: saa7134-core.c,v 1.28 2005/02/22 09:56:29 kraxel Exp $ * * device driver for philips saa7134 based TV cards * driver core @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -88,7 +89,7 @@ MODULE_PARM_DESC(card, "card type"); static DECLARE_MUTEX(devlist_lock); LIST_HEAD(saa7134_devlist); static LIST_HEAD(mops_list); -unsigned int saa7134_devcount; +static unsigned int saa7134_devcount; #define dprintk(fmt, arg...) if (core_debug) \ printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg) @@ -620,7 +621,7 @@ static irqreturn_t saa7134_irq(int irq, dump_statusregs(dev); #endif - if (report & SAA7134_IRQ_REPORT_INTL) + if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */) saa7134_irq_video_intl(dev); if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && @@ -642,8 +643,8 @@ static irqreturn_t saa7134_irq(int irq, SAA7134_IRQ_REPORT_GPIO18)) && dev->remote) saa7134_input_irq(dev); + } - }; if (10 == loop) { print_irqstatus(dev,loop,report,status); if (report & SAA7134_IRQ_REPORT_PE) { @@ -651,6 +652,13 @@ static irqreturn_t saa7134_irq(int irq, printk(KERN_WARNING "%s/irq: looping -- " "clearing PE (parity error!) enable bit\n",dev->name); saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE); + } else if (report & (SAA7134_IRQ_REPORT_GPIO16 | + SAA7134_IRQ_REPORT_GPIO18)) { + /* disable gpio IRQs */ + printk(KERN_WARNING "%s/irq: looping -- " + "clearing GPIO enable bits\n",dev->name); + saa_clearl(SAA7134_IRQ2, (SAA7134_IRQ2_INTE_GPIO16 | + SAA7134_IRQ2_INTE_GPIO18)); } else { /* disable all irqs */ printk(KERN_WARNING "%s/irq: looping -- " @@ -725,20 +733,7 @@ static int saa7134_hwinit2(struct saa713 /* enable IRQ's */ saa_writel(SAA7134_IRQ1, 0); - saa_writel(SAA7134_IRQ2, - SAA7134_IRQ2_INTE_GPIO18 | - SAA7134_IRQ2_INTE_GPIO18A | - SAA7134_IRQ2_INTE_GPIO16 | - SAA7134_IRQ2_INTE_SC2 | - SAA7134_IRQ2_INTE_SC1 | - SAA7134_IRQ2_INTE_SC0 | - /* SAA7134_IRQ2_INTE_DEC5 | FIXME: TRIG_ERR ??? */ - SAA7134_IRQ2_INTE_DEC3 | - SAA7134_IRQ2_INTE_DEC2 | - /* SAA7134_IRQ2_INTE_DEC1 | */ - SAA7134_IRQ2_INTE_DEC0 | - SAA7134_IRQ2_INTE_PE | - SAA7134_IRQ2_INTE_AR); + saa_writel(SAA7134_IRQ2, dev->irq2_mask); return 0; } @@ -959,6 +954,13 @@ static int __devinit saa7134_initdev(str } /* initialize hardware #1 */ + dev->irq2_mask = + SAA7134_IRQ2_INTE_DEC3 | + SAA7134_IRQ2_INTE_DEC2 | + SAA7134_IRQ2_INTE_DEC1 | + SAA7134_IRQ2_INTE_DEC0 | + SAA7134_IRQ2_INTE_PE | + SAA7134_IRQ2_INTE_AR; saa7134_board_init1(dev); saa7134_hwinit1(dev); @@ -1060,6 +1062,9 @@ static int __devinit saa7134_initdev(str } list_add_tail(&dev->devlist,&saa7134_devlist); up(&devlist_lock); + + /* check for signal */ + saa7134_irq_video_intl(dev); return 0; fail5: @@ -1207,6 +1212,8 @@ static int saa7134_init(void) static void saa7134_fini(void) { + if (pending_registered) + unregister_module_notifier(&pending_notifier); pci_unregister_driver(&saa7134_pci_driver); } Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-dvb.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-dvb.c 2005-03-07 10:14:28.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-dvb.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-dvb.c,v 1.4 2004/11/07 14:44:59 kraxel Exp $ + * $Id: saa7134-dvb.c,v 1.12 2005/02/18 12:28:29 kraxel Exp $ * * (c) 2004 Gerd Knorr [SuSE Labs] * @@ -30,35 +30,211 @@ #include "saa7134-reg.h" #include "saa7134.h" +#include "dvb-pll.h" +#include "mt352.h" +#include "mt352_priv.h" /* FIXME */ +#include "tda1004x.h" + MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); +static unsigned int antenna_pwr = 0; +module_param(antenna_pwr, int, 0444); +MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)"); + /* ------------------------------------------------------------------ */ -static int dvb_init(struct saa7134_dev *dev) +static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) { - printk("%s: %s\n",dev->name,__FUNCTION__); + u32 ok; + + if (!on) { + saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26)); + saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); + return 0; + } + + saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26)); + saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); + udelay(10); + + saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 28)); + saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); + udelay(10); + saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); + udelay(10); + ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); + printk("%s: %s %s\n", dev->name, __FUNCTION__, + ok ? "on" : "off"); + + if (!ok) + saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); + return ok; +} + +static int mt352_pinnacle_init(struct dvb_frontend* fe) +{ + static u8 clock_config [] = { CLOCK_CTL, 0x3d, 0x28 }; + static u8 reset [] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x31 }; + static u8 fsm_ctl_cfg[] = { 0x7b, 0x04 }; + static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x0f }; + static u8 scan_ctl_cfg [] = { SCAN_CTL, 0x0d }; + static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; + struct saa7134_dev *dev= fe->dvb->priv; + + printk("%s: %s called\n",dev->name,__FUNCTION__); + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + + mt352_write(fe, fsm_ctl_cfg, sizeof(fsm_ctl_cfg)); + mt352_write(fe, scan_ctl_cfg, sizeof(scan_ctl_cfg)); + mt352_write(fe, irq_cfg, sizeof(irq_cfg)); + return 0; +} + +static int mt352_pinnacle_pll_set(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params, + u8* pllbuf) +{ + static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; + static int off = TDA9887_PRESENT | TDA9887_PORT2_ACTIVE; + struct saa7134_dev *dev = fe->dvb->priv; + struct v4l2_frequency f; + + /* set frequency (mt2050) */ + f.tuner = 0; + f.type = V4L2_TUNER_DIGITAL_TV; + f.frequency = params->frequency / 1000 * 16 / 1000; + saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on); + saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f); + saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&off); + + pinnacle_antenna_pwr(dev, antenna_pwr); + /* mt352 setup */ + mt352_pinnacle_init(fe); + pllbuf[0] = 0xc2; + pllbuf[1] = 0x00; + pllbuf[2] = 0x00; + pllbuf[3] = 0x80; + pllbuf[4] = 0x00; + return 0; +} + +static struct mt352_config pinnacle_300i = { + .demod_address = 0x3c >> 1, + .adc_clock = 20333, + .if2 = 36150, + .no_tuner = 1, + .demod_init = mt352_pinnacle_init, + .pll_set = mt352_pinnacle_pll_set, +}; + +/* ------------------------------------------------------------------ */ + +static int medion_cardbus_init(struct dvb_frontend* fe) +{ + /* anything to do here ??? */ + return 0; +} + +static int medion_cardbus_pll_set(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params) +{ + struct saa7134_dev *dev = fe->dvb->priv; + struct v4l2_frequency f; + + /* + * this instructs tuner.o to set the frequency, the call will + * end up in tuner_command(), VIDIOC_S_FREQUENCY switch. + * tda9887.o will see that as well. + */ + f.tuner = 0; + f.type = V4L2_TUNER_DIGITAL_TV; + f.frequency = params->frequency / 1000 * 16 / 1000; + saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f); + return 0; +} + +static int fe_request_firmware(struct dvb_frontend* fe, + const struct firmware **fw, char* name) +{ + struct saa7134_dev *dev = fe->dvb->priv; + return request_firmware(fw, name, &dev->pci->dev); +} + +struct tda1004x_config medion_cardbus = { + .demod_address = 0x08, /* not sure this is correct */ + .invert = 0, + .invert_oclk = 0, + .pll_init = medion_cardbus_init, + .pll_set = medion_cardbus_pll_set, + .request_firmware = fe_request_firmware, +}; + +/* ------------------------------------------------------------------ */ + +static int dvb_init(struct saa7134_dev *dev) +{ /* init struct videobuf_dvb */ + dev->ts.nr_bufs = 32; + dev->ts.nr_packets = 32*4; dev->dvb.name = dev->name; videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_TOP, + V4L2_FIELD_ALTERNATE, sizeof(struct saa7134_buf), dev); - /* TODO: init frontend */ - if (NULL == dev->dvb.frontend) + switch (dev->board) { + case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: + printk("%s: pinnacle 300i dvb setup\n",dev->name); + dev->dvb.frontend = mt352_attach(&pinnacle_300i, + &dev->i2c_adap); + break; + case SAA7134_BOARD_MD7134: + dev->dvb.frontend = tda10046_attach(&medion_cardbus, + &dev->i2c_adap); + if (NULL == dev->dvb.frontend) + printk("%s: Hmm, looks like this is the old MD7134 " + "version without DVB-T support\n",dev->name); + break; + default: + printk("%s: Huh? unknown DVB card?\n",dev->name); + break; + } + + if (NULL == dev->dvb.frontend) { + printk("%s: frontend initialization failed\n",dev->name); return -1; + } /* register everything else */ - return videobuf_dvb_register(&dev->dvb); + return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev); } static int dvb_fini(struct saa7134_dev *dev) { + static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; + printk("%s: %s\n",dev->name,__FUNCTION__); + + switch (dev->board) { + case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: + /* otherwise we don't detect the tuner on next insmod */ + saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on); + break; + }; videobuf_dvb_unregister(&dev->dvb); return 0; } @@ -86,6 +262,5 @@ module_exit(dvb_unregister); /* * Local variables: * c-basic-offset: 8 - * compile-command: "make DVB=1" * End: */ Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-empress.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-empress.c 2005-03-07 10:15:53.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-empress.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-empress.c,v 1.3 2004/11/07 13:17:15 kraxel Exp $ + * $Id: saa7134-empress.c,v 1.10 2005/02/03 10:24:33 kraxel Exp $ * * (c) 2004 Gerd Knorr [SuSE Labs] * @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -50,16 +51,21 @@ MODULE_PARM_DESC(debug,"enable debug mes static void ts_reset_encoder(struct saa7134_dev* dev) { + if (!dev->empress_started) + return; + saa_writeb(SAA7134_SPECIAL_MODE, 0x00); msleep(10); saa_writeb(SAA7134_SPECIAL_MODE, 0x01); msleep(100); + dev->empress_started = 0; } -static int ts_init_encoder(struct saa7134_dev* dev, void* arg) +static int ts_init_encoder(struct saa7134_dev* dev) { ts_reset_encoder(dev); - saa7134_i2c_call_clients(dev, MPEG_SETPARAMS, arg); + saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL); + dev->empress_started = 1; return 0; } @@ -81,18 +87,19 @@ static int ts_open(struct inode *inode, return -ENODEV; dprintk("open minor=%d\n",minor); - down(&dev->empress_tsq.lock); err = -EBUSY; - if (dev->empress_users) + if (down_trylock(&dev->empress_tsq.lock)) goto done; + if (dev->empress_users) + goto done_up; dev->empress_users++; file->private_data = dev; - ts_init_encoder(dev, NULL); err = 0; - done: +done_up: up(&dev->empress_tsq.lock); +done: return err; } @@ -105,6 +112,7 @@ static int ts_release(struct inode *inod down(&dev->empress_tsq.lock); if (dev->empress_tsq.reading) videobuf_read_stop(&dev->empress_tsq); + videobuf_mmap_free(&dev->empress_tsq); dev->empress_users--; /* stop the encoder */ @@ -119,6 +127,9 @@ ts_read(struct file *file, char __user * { struct saa7134_dev *dev = file->private_data; + if (!dev->empress_started) + ts_init_encoder(dev); + return videobuf_read_stream(&dev->empress_tsq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); @@ -281,8 +292,13 @@ static int ts_do_ioctl(struct inode *ino case VIDIOC_S_CTRL: return saa7134_common_ioctl(dev, cmd, arg); - case MPEG_SETPARAMS: - return ts_init_encoder(dev, arg); + case VIDIOC_S_MPEGCOMP: + saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg); + ts_init_encoder(dev); + return 0; + case VIDIOC_G_MPEGCOMP: + saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg); + return 0; default: return -ENOIOCTLCMD; @@ -320,6 +336,26 @@ static struct video_device saa7134_empre .minor = -1, }; +static void empress_signal_update(void* data) +{ + struct saa7134_dev* dev = (struct saa7134_dev*) data; + + if (dev->nosignal) { + dprintk("no video signal\n"); + ts_reset_encoder(dev); + } else { + dprintk("video signal acquired\n"); + if (dev->empress_users) + ts_init_encoder(dev); + } +} + +static void empress_signal_change(struct saa7134_dev *dev) +{ + schedule_work(&dev->empress_workqueue); +} + + static int empress_init(struct saa7134_dev *dev) { int err; @@ -335,6 +371,8 @@ static int empress_init(struct saa7134_d "%s empress (%s)", dev->name, saa7134_boards[dev->board].name); + INIT_WORK(&dev->empress_workqueue, empress_signal_update, (void*) dev); + err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, empress_nr[dev->nr]); if (err < 0) { @@ -353,6 +391,8 @@ static int empress_init(struct saa7134_d V4L2_FIELD_ALTERNATE, sizeof(struct saa7134_buf), dev); + + empress_signal_update(dev); return 0; } @@ -362,6 +402,7 @@ static int empress_fini(struct saa7134_d if (NULL == dev->empress_dev) return 0; + flush_scheduled_work(); video_unregister_device(dev->empress_dev); dev->empress_dev = NULL; return 0; @@ -371,6 +412,7 @@ static struct saa7134_mpeg_ops empress_o .type = SAA7134_MPEG_EMPRESS, .init = empress_init, .fini = empress_fini, + .signal_change = empress_signal_change, }; static int __init empress_register(void) Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-i2c.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-i2c.c 2005-03-07 10:12:56.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-i2c.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-i2c.c,v 1.7 2004/11/07 13:17:15 kraxel Exp $ + * $Id: saa7134-i2c.c,v 1.10 2005/01/24 17:37:23 kraxel Exp $ * * device driver for philips saa7134 based TV cards * i2c interface support @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -205,7 +206,8 @@ static inline int i2c_send_byte(struct s dword &= 0x0f; dword |= (attr << 6); dword |= ((__u32)data << 8); - dword |= 0x00 << 16; + dword |= 0x00 << 16; /* 100 kHz */ +// dword |= 0x40 << 16; /* 400 kHz */ dword |= 0xf0 << 24; saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); #endif @@ -248,13 +250,24 @@ static int saa7134_i2c_xfer(struct i2c_a if (!i2c_reset(dev)) return -EIO; + d2printk("start xfer\n"); d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name); for (i = 0; i < num; i++) { if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) { /* send address */ + d2printk("send address\n"); addr = msgs[i].addr << 1; if (msgs[i].flags & I2C_M_RD) addr |= 1; + if (i > 0 && msgs[i].flags & I2C_M_RD) { + /* workaround for a saa7134 i2c bug + * needed to talk to the mt352 demux + * thanks to pinnacle for the hint */ + int quirk = 0xfd; + d1printk(" [%02x quirk]",quirk); + i2c_send_byte(dev,START,quirk); + i2c_recv_byte(dev); + } d1printk(" < %02x", addr); rc = i2c_send_byte(dev,START,addr); if (rc < 0) @@ -262,6 +275,7 @@ static int saa7134_i2c_xfer(struct i2c_a } if (msgs[i].flags & I2C_M_RD) { /* read bytes */ + d2printk("read bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { d1printk(" ="); rc = i2c_recv_byte(dev); @@ -272,6 +286,7 @@ static int saa7134_i2c_xfer(struct i2c_a } } else { /* write bytes */ + d2printk("write bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { data = msgs[i].buf[byte]; d1printk(" %02x", data); @@ -281,6 +296,7 @@ static int saa7134_i2c_xfer(struct i2c_a } } } + d2printk("xfer done\n"); d1printk(" >"); i2c_set_attr(dev,STOP); rc = -EIO; @@ -313,18 +329,6 @@ static u32 functionality(struct i2c_adap return I2C_FUNC_SMBUS_EMUL; } -#ifndef I2C_PEC -static void inc_use(struct i2c_adapter *adap) -{ - MOD_INC_USE_COUNT; -} - -static void dec_use(struct i2c_adapter *adap) -{ - MOD_DEC_USE_COUNT; -} -#endif - static int attach_inform(struct i2c_client *client) { struct saa7134_dev *dev = client->adapter->algo_data; @@ -345,12 +349,7 @@ static struct i2c_algorithm saa7134_algo }; static struct i2c_adapter saa7134_adap_template = { -#ifdef I2C_PEC .owner = THIS_MODULE, -#else - .inc_use = inc_use, - .dec_use = dec_use, -#endif #ifdef I2C_CLASS_TV_ANALOG .class = I2C_CLASS_TV_ANALOG, #endif Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-input.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-input.c 2005-03-07 10:16:31.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-input.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-input.c,v 1.12 2004/11/07 13:17:15 kraxel Exp $ + * $Id: saa7134-input.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $ * * handle saa7134 IR remotes via linux kernel input layer. * @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -258,6 +259,55 @@ static IR_KEYTAB_TYPE md2819_codes[IR_KE [ 17 ] = KEY_CHANNELDOWN, // CHANNEL/PAGE- [ 49 ] = KEY_CHANNELUP // CHANNEL/PAGE+ }; + +static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = { + [ 20 ] = KEY_MUTE, + [ 36 ] = KEY_ZOOM, + + [ 1 ] = KEY_DVD, + [ 35 ] = KEY_RADIO, + [ 0 ] = KEY_TV, + + [ 10 ] = KEY_REWIND, + [ 8 ] = KEY_PLAYPAUSE, + [ 15 ] = KEY_FORWARD, + + [ 2 ] = KEY_PREVIOUS, + [ 7 ] = KEY_STOP, + [ 6 ] = KEY_NEXT, + + [ 12 ] = KEY_UP, + [ 14 ] = KEY_DOWN, + [ 11 ] = KEY_LEFT, + [ 13 ] = KEY_RIGHT, + [ 17 ] = KEY_OK, + + [ 3 ] = KEY_MENU, + [ 9 ] = KEY_SETUP, + [ 5 ] = KEY_VIDEO, + [ 34 ] = KEY_CHANNEL, + + [ 18 ] = KEY_VOLUMEUP, + [ 21 ] = KEY_VOLUMEDOWN, + [ 16 ] = KEY_CHANNELUP, + [ 19 ] = KEY_CHANNELDOWN, + + [ 4 ] = KEY_RECORD, + + [ 22 ] = KEY_KP1, + [ 23 ] = KEY_KP2, + [ 24 ] = KEY_KP3, + [ 25 ] = KEY_KP4, + [ 26 ] = KEY_KP5, + [ 27 ] = KEY_KP6, + [ 28 ] = KEY_KP7, + [ 29 ] = KEY_KP8, + [ 30 ] = KEY_KP9, + [ 31 ] = KEY_KP0, + + [ 32 ] = KEY_LANGUAGE, + [ 33 ] = KEY_SLEEP, +}; /* ---------------------------------------------------------------------- */ static int build_key(struct saa7134_dev *dev) @@ -335,6 +385,7 @@ int saa7134_input_init1(struct saa7134_d break; case SAA7134_BOARD_CINERGY400: case SAA7134_BOARD_CINERGY600: + case SAA7134_BOARD_CINERGY600_MK3: ir_codes = cinergy_codes; mask_keycode = 0x00003f; mask_keyup = 0x040000; @@ -353,6 +404,7 @@ int saa7134_input_init1(struct saa7134_d polling = 50; // ms break; case SAA7134_BOARD_MD2819: + case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_307: ir_codes = md2819_codes; mask_keycode = 0x0007C8; @@ -362,6 +414,12 @@ int saa7134_input_init1(struct saa7134_d saa_setb(SAA7134_GPIO_GPMODE0, 0x4); saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); break; + case SAA7134_BOARD_VIDEOMATE_TV_PVR: + ir_codes = videomate_tv_pvr_codes; + mask_keycode = 0x00003F; + mask_keyup = 0x400000; + polling = 50; // ms + break; } if (NULL == ir_codes) { printk("%s: Oops: IR config error [card=%d]\n", Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-oss.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-oss.c 2005-03-07 10:16:26.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-oss.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-oss.c,v 1.11 2004/11/07 13:17:15 kraxel Exp $ + * $Id: saa7134-oss.c,v 1.13 2004/12/10 12:33:39 kraxel Exp $ * * device driver for philips saa7134 based TV cards * oss dsp interface @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -543,6 +544,7 @@ mixer_recsrc_7134(struct saa7134_dev *de break; case LINE1: case LINE2: + case LINE2_LEFT: analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08; rate = (32000 == dev->oss.rate) ? 0x01 : 0x03; saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io); @@ -566,6 +568,7 @@ mixer_recsrc_7133(struct saa7134_dev *de value = 0xbbbb32; /* AUX1 */ break; case LINE2: + case LINE2_LEFT: value = 0xbbbb54; /* AUX2 */ break; } @@ -608,6 +611,7 @@ mixer_level(struct saa7134_dev *dev, enu (100 == level) ? 0x00 : 0x10); break; case LINE2: + case LINE2_LEFT: saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20, (100 == level) ? 0x00 : 0x20); break; Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-ts.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-ts.c 2005-03-07 10:12:29.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-ts.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-ts.c,v 1.12 2004/11/07 13:17:15 kraxel Exp $ + * $Id: saa7134-ts.c,v 1.14 2005/02/03 10:24:33 kraxel Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -220,10 +221,10 @@ void saa7134_irq_ts_done(struct saa7134_ if (dev->ts_q.curr) { field = dev->ts_q.curr->vb.field; if (field == V4L2_FIELD_TOP) { - if ((status & 0x100000) != 0x100000) + if ((status & 0x100000) != 0x000000) goto done; } else { - if ((status & 0x100000) != 0x000000) + if ((status & 0x100000) != 0x100000) goto done; } saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-tvaudio.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-tvaudio.c 2005-03-07 10:12:25.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-tvaudio.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-tvaudio.c,v 1.17 2004/11/07 13:17:15 kraxel Exp $ + * $Id: saa7134-tvaudio.c,v 1.22 2005/01/07 13:11:19 kraxel Exp $ * * device driver for philips saa7134 based TV cards * tv audio decoder (fm stereo, nicam, ...) @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -237,13 +238,14 @@ static void mute_input_7134(struct saa71 if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device) /* 7134 mute */ - saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xff : 0xbb); + saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xbf : 0xbb); /* switch internal audio mux */ switch (in->amux) { - case TV: ausel=0xc0; ics=0x00; ocs=0x02; break; - case LINE1: ausel=0x80; ics=0x00; ocs=0x00; break; - case LINE2: ausel=0x80; ics=0x08; ocs=0x01; break; + case TV: ausel=0xc0; ics=0x00; ocs=0x02; break; + case LINE1: ausel=0x80; ics=0x00; ocs=0x00; break; + case LINE2: ausel=0x80; ics=0x08; ocs=0x01; break; + case LINE2_LEFT: ausel=0x80; ics=0x08; ocs=0x05; break; } saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, ausel); saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, ics); @@ -437,15 +439,16 @@ static int tvaudio_getstereo(struct saa7 nicam = saa_readb(SAA7134_NICAM_STATUS); dprintk("getstereo: nicam=0x%x\n",nicam); switch (nicam & 0x0b) { - case 0x08: - retval = V4L2_TUNER_SUB_MONO; - break; case 0x09: retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; break; case 0x0a: retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; break; + case 0x08: + default: + retval = V4L2_TUNER_SUB_MONO; + break; } break; } @@ -748,9 +751,16 @@ static int mute_input_7133(struct saa713 int mask; switch (dev->input->amux) { - case TV: reg = 0x02; break; - case LINE1: reg = 0x00; break; - case LINE2: reg = 0x01; break; + case TV: + reg = 0x02; + break; + case LINE1: + reg = 0x00; + break; + case LINE2: + case LINE2_LEFT: + reg = 0x01; + break; } if (dev->ctl_mute) reg = 0x07; @@ -869,6 +879,21 @@ static int tvaudio_thread_ddep(void *dat /* ------------------------------------------------------------------ */ /* common stuff + external entry points */ +static void saa7134_enable_i2s(struct saa7134_dev *dev) +{ + int i2s_format; + + if (!card_is_empress(dev)) + return; + i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01; + + /* enable I2S audio output for the mpeg encoder */ + saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); + saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format); + saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F); + saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01); +} + int saa7134_tvaudio_rx2mode(u32 rx) { u32 mode; @@ -911,6 +936,7 @@ void saa7134_tvaudio_setinput(struct saa mute_input_7133(dev); break; } + saa7134_enable_i2s(dev); } void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level) @@ -946,18 +972,6 @@ int saa7134_tvaudio_init2(struct saa7134 DECLARE_MUTEX_LOCKED(sem); int (*my_thread)(void *data) = NULL; - /* enable I2S audio output */ - if (card_is_empress(dev)) { - int i2sform = (48000 == dev->oss.rate) - ? 0x01 : 0x00; - - /* enable I2S output */ - saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); - saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2sform); - saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F); - saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01); - } - switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7134: my_thread = tvaudio_thread; @@ -977,9 +991,10 @@ int saa7134_tvaudio_init2(struct saa7134 if (dev->thread.pid < 0) printk(KERN_WARNING "%s: kernel_thread() failed\n", dev->name); - wake_up_interruptible(&dev->thread.wq); + saa7134_tvaudio_do_scan(dev); } + saa7134_enable_i2s(dev); return 0; } Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-vbi.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-vbi.c 2005-03-07 10:15:23.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-vbi.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-vbi.c,v 1.5 2004/11/07 13:17:15 kraxel Exp $ + * $Id: saa7134-vbi.c,v 1.6 2004/12/10 12:33:39 kraxel Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface @@ -24,6 +24,7 @@ #include #include #include +#include #include #include Index: linux-2.6.11/drivers/media/video/saa7134/saa7134-video.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134-video.c 2005-03-07 10:12:58.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134-video.c 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134-video.c,v 1.19 2004/11/07 14:44:59 kraxel Exp $ + * $Id: saa7134-video.c,v 1.28 2005/02/15 15:59:35 kraxel Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -267,6 +268,24 @@ static struct saa7134_tvnorm tvnorms[] = .chroma_ctrl2 = 0x06, .vgate_misc = 0x1c, + },{ + .name = "PAL-60", + .id = V4L2_STD_PAL_60, + + .h_start = 0, + .h_stop = 719, + .video_v_start = 22, + .video_v_stop = 22+239, + .vbi_v_start = 10, /* FIXME */ + .vbi_v_stop = 21, /* FIXME */ + .src_timing = 1, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, } }; #define TVNORMS ARRAY_SIZE(tvnorms) @@ -443,11 +462,10 @@ void res_free(struct saa7134_dev *dev, s static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - int luma_control,sync_control,mux,nosignal; + int luma_control,sync_control,mux; dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; - nosignal = (0 == (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)); mux = card_in(dev,dev->ctl_input).vmux; luma_control = norm->luma_control; @@ -455,7 +473,7 @@ static void set_tvnorm(struct saa7134_de if (mux > 5) luma_control |= 0x80; /* svideo */ - if (noninterlaced || nosignal) + if (noninterlaced || dev->nosignal) sync_control |= 0x20; /* setup cropping */ @@ -1359,6 +1377,9 @@ static int video_release(struct inode *i res_free(dev,fh,RESOURCE_VBI); } + /* free stuff */ + videobuf_mmap_free(&fh->cap); + videobuf_mmap_free(&fh->vbi); saa7134_pgtable_free(dev->pci,&fh->pt_cap); saa7134_pgtable_free(dev->pci,&fh->pt_vbi); @@ -1472,6 +1493,7 @@ static int saa7134_try_fmt(struct saa713 f->fmt.pix.width = maxw; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; + f->fmt.pix.width &= ~0x03; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = @@ -2267,7 +2289,7 @@ int saa7134_video_init1(struct saa7134_d dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; - dev->ctl_mute = ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; + dev->ctl_mute = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; dev->ctl_invert = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value; dev->ctl_automute = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value; @@ -2317,24 +2339,31 @@ int saa7134_video_fini(struct saa7134_de void saa7134_irq_video_intl(struct saa7134_dev *dev) { static const char *st[] = { - "no signal", "found NTSC", "found PAL", "found SECAM" }; - int norm; + "(no signal)", "NTSC", "PAL", "SECAM" }; + u32 st1,st2; - norm = saa_readb(SAA7134_STATUS_VIDEO1) & 0x03; - dprintk("DCSDT: %s\n",st[norm]); + st1 = saa_readb(SAA7134_STATUS_VIDEO1); + st2 = saa_readb(SAA7134_STATUS_VIDEO2); + dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n", + (st1 & 0x40) ? "not locked" : "locked", + (st2 & 0x40) ? "no" : "yes", + st[st1 & 0x03]); + dev->nosignal = (st1 & 0x40) || (st2 & 0x40); - if (0 != norm) { - /* wake up tvaudio audio carrier scan thread */ - saa7134_tvaudio_do_scan(dev); - if (!noninterlaced) - saa_clearb(SAA7134_SYNC_CTRL, 0x20); - } else { + if (dev->nosignal) { /* no video signal -> mute audio */ if (dev->ctl_automute) dev->automute = 1; saa7134_tvaudio_setmute(dev); saa_setb(SAA7134_SYNC_CTRL, 0x20); + } else { + /* wake up tvaudio audio carrier scan thread */ + saa7134_tvaudio_do_scan(dev); + if (!noninterlaced) + saa_clearb(SAA7134_SYNC_CTRL, 0x20); } + if (dev->mops && dev->mops->signal_change) + dev->mops->signal_change(dev); } void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) Index: linux-2.6.11/drivers/media/video/saa7134/saa7134.h =================================================================== --- linux-2.6.11.orig/drivers/media/video/saa7134/saa7134.h 2005-03-07 10:14:47.000000000 +0100 +++ linux-2.6.11/drivers/media/video/saa7134/saa7134.h 2005-03-08 10:33:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: saa7134.h,v 1.27 2004/11/04 11:03:52 kraxel Exp $ + * $Id: saa7134.h,v 1.38 2005/03/07 12:01:51 kraxel Exp $ * * v4l2 device driver for philips saa7134 based TV cards * @@ -64,6 +64,7 @@ enum saa7134_audio_in { TV = 1, LINE1 = 2, LINE2 = 3, + LINE2_LEFT, }; enum saa7134_video_out { @@ -156,11 +157,11 @@ struct saa7134_format { #define SAA7134_BOARD_AVACSSMARTTV 32 #define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33 #define SAA7134_BOARD_NOVAC_PRIMETV7133 34 -#define SAA7134_BOARD_AVERMEDIA_305 35 +#define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35 #define SAA7133_BOARD_UPMOST_PURPLE_TV 36 #define SAA7134_BOARD_ITEMS_MTV005 37 #define SAA7134_BOARD_CINERGY200 38 -#define SAA7134_BOARD_FLYTVPLATINUM 39 +#define SAA7134_BOARD_FLYTVPLATINUM_MINI 39 #define SAA7134_BOARD_VIDEOMATE_TV_PVR 40 #define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS 41 #define SAA7134_BOARD_SABRENT_SBTTVFM 42 @@ -169,6 +170,14 @@ struct saa7134_format { #define SAA7134_BOARD_AVERMEDIA_307 45 #define SAA7134_BOARD_AVERMEDIA_CARDBUS 46 #define SAA7134_BOARD_CINERGY400_CARDBUS 47 +#define SAA7134_BOARD_CINERGY600_MK3 48 +#define SAA7134_BOARD_VIDEOMATE_GOLD_PLUS 49 +#define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50 +#define SAA7134_BOARD_PROVIDEO_PV952 51 +#define SAA7134_BOARD_AVERMEDIA_305 52 +#define SAA7135_BOARD_ASUSTeK_TVFM7135 53 +#define SAA7134_BOARD_FLYTVPLATINUM_FM 54 +#define SAA7134_BOARD_FLYDVBTDUO 55 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 @@ -355,6 +364,7 @@ struct saa7134_mpeg_ops { struct list_head next; int (*init)(struct saa7134_dev *dev); int (*fini)(struct saa7134_dev *dev); + void (*signal_change)(struct saa7134_dev *dev); }; /* global device status */ @@ -390,6 +400,7 @@ struct saa7134_dev { unsigned int tuner_type; unsigned int tda9887_conf; unsigned int gpio_value; + unsigned int irq2_mask; /* i2c i/o */ struct i2c_adapter i2c_adap; @@ -437,6 +448,7 @@ struct saa7134_dev { struct saa7134_input *hw_input; unsigned int hw_mute; int last_carrier; + int nosignal; /* SAA7134_MPEG_* */ struct saa7134_ts ts; @@ -447,6 +459,8 @@ struct saa7134_dev { struct video_device *empress_dev; struct videobuf_queue empress_tsq; unsigned int empress_users; + struct work_struct empress_workqueue; + int empress_started; /* SAA7134_MPEG_DVB only */ struct videobuf_dvb dvb; @@ -476,7 +490,6 @@ struct saa7134_dev { /* saa7134-core.c */ extern struct list_head saa7134_devlist; -extern unsigned int saa7134_devcount; void saa7134_print_ioctl(char *name, unsigned int cmd); void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); Index: linux-2.6.11/drivers/media/video/stradis.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/stradis.c 2005-03-07 10:15:16.000000000 +0100 +++ linux-2.6.11/drivers/media/video/stradis.c 2005-03-08 10:33:15.000000000 +0100 @@ -2181,12 +2181,9 @@ static void release_saa(void) /* unmap and free memory */ saa->audhead = saa->audtail = saa->osdhead = 0; saa->vidhead = saa->vidtail = saa->osdtail = 0; - if (saa->vidbuf) - vfree(saa->vidbuf); - if (saa->audbuf) - vfree(saa->audbuf); - if (saa->osdbuf) - vfree(saa->osdbuf); + vfree(saa->vidbuf); + vfree(saa->audbuf); + vfree(saa->osdbuf); if (saa->dmavid2) kfree((void *) saa->dmavid2); saa->audbuf = saa->vidbuf = saa->osdbuf = NULL; Index: linux-2.6.11/drivers/media/video/tda8290.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/media/video/tda8290.c 2005-03-07 18:13:02.000000000 +0100 @@ -0,0 +1,224 @@ +/* + * $Id: tda8290.c,v 1.7 2005/03/07 12:01:51 kraxel Exp $ + * + * i2c tv tuner chip device driver + * controls the philips tda8290+75 tuner chip combo. + */ +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +struct freq_entry { + u16 freq; + u8 value; +}; + +static struct freq_entry band_table[] = { + { 0x2DF4, 0x1C }, + { 0x2574, 0x14 }, + { 0x22B4, 0x0C }, + { 0x20D4, 0x0B }, + { 0x1E74, 0x3B }, + { 0x1C34, 0x33 }, + { 0x16F4, 0x5B }, + { 0x1454, 0x53 }, + { 0x12D4, 0x52 }, + { 0x1034, 0x4A }, + { 0x0EE4, 0x7A }, + { 0x0D34, 0x72 }, + { 0x0B54, 0x9A }, + { 0x0914, 0x91 }, + { 0x07F4, 0x89 }, + { 0x0774, 0xB9 }, + { 0x067B, 0xB1 }, + { 0x0634, 0xD9 }, + { 0x05A4, 0xD8 }, // FM radio + { 0x0494, 0xD0 }, + { 0x03BC, 0xC8 }, + { 0x0394, 0xF8 }, // 57250000 Hz + { 0x0000, 0xF0 }, // 0 +}; + +static struct freq_entry div_table[] = { + { 0x1C34, 3 }, + { 0x0D34, 2 }, + { 0x067B, 1 }, + { 0x0000, 0 }, +}; + +static struct freq_entry agc_table[] = { + { 0x22B4, 0x8F }, + { 0x0B54, 0x9F }, + { 0x09A4, 0x8F }, + { 0x0554, 0x9F }, + { 0x0000, 0xBF }, +}; + +static __u8 get_freq_entry( struct freq_entry* table, __u16 freq) +{ + while(table->freq && table->freq > freq) + table++; + return table->value; +} + +/* ---------------------------------------------------------------------- */ + +static unsigned char i2c_enable_bridge[2] = { 0x21, 0xC0 }; +static unsigned char i2c_disable_bridge[2] = { 0x21, 0x80 }; +static unsigned char i2c_init_tda8275[14] = { 0x00, 0x00, 0x00, 0x00, + 0x7C, 0x04, 0xA3, 0x3F, + 0x2A, 0x04, 0xFF, 0x00, + 0x00, 0x40 }; +static unsigned char i2c_set_VS[2] = { 0x30, 0x6F }; +static unsigned char i2c_set_GP01_CF[2] = { 0x20, 0x0B }; +static unsigned char i2c_tda8290_reset[2] = { 0x00, 0x00 }; +static unsigned char i2c_gainset_off[2] = { 0x28, 0x14 }; +static unsigned char i2c_gainset_on[2] = { 0x28, 0x54 }; +static unsigned char i2c_agc3_00[2] = { 0x80, 0x00 }; +static unsigned char i2c_agc2_BF[2] = { 0x60, 0xBF }; +static unsigned char i2c_cb1_D2[2] = { 0x30, 0xD2 }; +static unsigned char i2c_cb1_56[2] = { 0x30, 0x56 }; +static unsigned char i2c_cb1_52[2] = { 0x30, 0x52 }; +static unsigned char i2c_cb1_50[2] = { 0x30, 0x50 }; +static unsigned char i2c_agc2_7F[2] = { 0x60, 0x7F }; +static unsigned char i2c_agc3_08[2] = { 0x80, 0x08 }; + +static struct i2c_msg i2c_msg_init[] = { + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_init_tda8275), i2c_init_tda8275 }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_VS), i2c_set_VS }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_GP01_CF), i2c_set_GP01_CF }, +}; + +static struct i2c_msg i2c_msg_prolog[] = { +// { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_easy_mode), i2c_easy_mode }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_off), i2c_gainset_off }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_reset), i2c_tda8290_reset }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge }, +}; + +static struct i2c_msg i2c_msg_config[] = { +// { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_set_freq), i2c_set_freq }, + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_00), i2c_agc3_00 }, + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_BF), i2c_agc2_BF }, + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D2), i2c_cb1_D2 }, + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_56), i2c_cb1_56 }, + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_52), i2c_cb1_52 }, +}; + +static struct i2c_msg i2c_msg_epilog[] = { + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_50), i2c_cb1_50 }, + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_7F), i2c_agc2_7F }, + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_08), i2c_agc3_08 }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_on), i2c_gainset_on }, +}; + +static int tda8290_tune(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + struct i2c_msg easy_mode = + { I2C_ADDR_TDA8290, 0, 2, t->i2c_easy_mode }; + struct i2c_msg set_freq = + { I2C_ADDR_TDA8275, 0, 8, t->i2c_set_freq }; + + i2c_transfer(c->adapter, &easy_mode, 1); + i2c_transfer(c->adapter, i2c_msg_prolog, ARRAY_SIZE(i2c_msg_prolog)); + + i2c_transfer(c->adapter, &set_freq, 1); + i2c_transfer(c->adapter, i2c_msg_config, ARRAY_SIZE(i2c_msg_config)); + + msleep(550); + i2c_transfer(c->adapter, i2c_msg_epilog, ARRAY_SIZE(i2c_msg_epilog)); + return 0; +} + +static void set_frequency(struct tuner *t, u16 ifc) +{ + u32 N = (((t->freq<<3)+ifc)&0x3fffc); + + N = N >> get_freq_entry(div_table, t->freq); + t->i2c_set_freq[0] = 0; + t->i2c_set_freq[1] = (unsigned char)(N>>8); + t->i2c_set_freq[2] = (unsigned char) N; + t->i2c_set_freq[3] = 0x40; + t->i2c_set_freq[4] = 0x52; + t->i2c_set_freq[5] = get_freq_entry(band_table, t->freq); + t->i2c_set_freq[6] = get_freq_entry(agc_table, t->freq); + t->i2c_set_freq[7] = 0x8f; +} + +#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC) +#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B) +#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H) +#define V4L2_STD_DK (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK) + +static void set_audio(struct tuner *t) +{ + t->i2c_easy_mode[0] = 0x01; + + if (t->std & V4L2_STD_MN) + t->i2c_easy_mode[1] = 0x01; + else if (t->std & V4L2_STD_B) + t->i2c_easy_mode[1] = 0x02; + else if (t->std & V4L2_STD_GH) + t->i2c_easy_mode[1] = 0x04; + else if (t->std & V4L2_STD_PAL_I) + t->i2c_easy_mode[1] = 0x08; + else if (t->std & V4L2_STD_DK) + t->i2c_easy_mode[1] = 0x10; + else if (t->std & V4L2_STD_SECAM_L) + t->i2c_easy_mode[1] = 0x20; +} + +static void set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + set_audio(t); + set_frequency(t, 864); + tda8290_tune(c); +} + +static void set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + set_frequency(t, 704); + tda8290_tune(c); +} + +static int has_signal(struct i2c_client *c) +{ + unsigned char i2c_get_afc[1] = { 0x1B }; + unsigned char afc = 0; + + i2c_master_send(c, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); + i2c_master_recv(c, &afc, 1); + return (afc & 0x80)? 65535:0; +} + +int tda8290_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + strlcpy(c->name, "tda8290+75", sizeof(c->name)); + tuner_info("tuner: type set to %s\n", c->name); + t->tv_freq = set_tv_freq; + t->radio_freq = set_radio_freq; + t->has_signal = has_signal; + + i2c_master_send(c, i2c_enable_bridge, ARRAY_SIZE(i2c_enable_bridge)); + i2c_transfer(c->adapter, i2c_msg_init, ARRAY_SIZE(i2c_msg_init)); + return 0; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/video/tda9887.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/tda9887.c 2005-03-07 10:16:07.000000000 +0100 +++ linux-2.6.11/drivers/media/video/tda9887.c 2005-03-07 18:13:01.000000000 +0100 @@ -557,7 +557,7 @@ static int tda9887_configure(struct tda9 #if 0 /* This as-is breaks some cards, must be fixed in a * card-specific way, probably using TDA9887_SET_CONFIG to - * turn on/off port2 */ + * turn on/off port2 */ if (t->std & V4L2_STD_SECAM_L) { /* secam fixup (FIXME: move this to tvnorms array?) */ buf[1] &= ~cOutputPort2Inactive; Index: linux-2.6.11/drivers/media/video/tuner-core.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/media/video/tuner-core.c 2005-03-07 18:13:01.000000000 +0100 @@ -0,0 +1,443 @@ +/* + * $Id: tuner-core.c,v 1.5 2005/02/15 15:59:35 kraxel Exp $ + * + * i2c tv tuner chip device driver + * core core, i.e. kernel interfaces, registering and so on + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define UNSET (-1U) + +/* standard i2c insmod options */ +static unsigned short normal_i2c[] = { + 0x4b, /* tda8290 */ + I2C_CLIENT_END +}; +static unsigned short normal_i2c_range[] = { + 0x60, 0x6f, + I2C_CLIENT_END +}; +I2C_CLIENT_INSMOD; + +/* insmod options used at init time => read/only */ +static unsigned int addr = 0; +module_param(addr, int, 0444); + +/* insmod options used at runtime => read/write */ +unsigned int tuner_debug = 0; +module_param(tuner_debug, int, 0644); + +static unsigned int tv_range[2] = { 44, 958 }; +static unsigned int radio_range[2] = { 65, 108 }; + +module_param_array(tv_range, int, NULL, 0644); +module_param_array(radio_range, int, NULL, 0644); + +MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + +static int this_adap; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +/* ---------------------------------------------------------------------- */ + +// Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz +static void set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (t->type == UNSET) { + tuner_info("tuner type not set\n"); + return; + } + if (NULL == t->tv_freq) { + tuner_info("Huh? tv_set is NULL?\n"); + return; + } + if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { + /* FIXME: better do that chip-specific, but + right now we don't have that in the config + struct and this way is still better than no + check at all */ + tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n", + freq/16,freq%16*100/16,tv_range[0],tv_range[1]); + return; + } + t->tv_freq(c,freq); +} + +static void set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (t->type == UNSET) { + tuner_info("tuner type not set\n"); + return; + } + if (NULL == t->radio_freq) { + tuner_info("no radio tuning for this one, sorry.\n"); + return; + } + if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { + tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", + freq/16,freq%16*100/16, + radio_range[0],radio_range[1]); + return; + } + t->radio_freq(c,freq); +} + +static void set_freq(struct i2c_client *c, unsigned long freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + switch (t->mode) { + case V4L2_TUNER_RADIO: + tuner_dbg("radio freq set to %lu.%02lu\n", + freq/16,freq%16*100/16); + set_radio_freq(c,freq); + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + tuner_dbg("tv freq set to %lu.%02lu\n", + freq/16,freq%16*100/16); + set_tv_freq(c, freq); + break; + } + t->freq = freq; +} + +static void set_type(struct i2c_client *c, unsigned int type) +{ + struct tuner *t = i2c_get_clientdata(c); + + /* sanity check */ + if (type == UNSET || type == TUNER_ABSENT) + return; + if (type >= tuner_count) + return; + + if (NULL == t->i2c.dev.driver) { + /* not registered yet */ + t->type = type; + return; + } + if (t->initialized) + /* run only once */ + return; + + t->initialized = 1; + t->type = type; + switch (t->type) { + case TUNER_MT2032: + microtune_init(c); + break; + case TUNER_PHILIPS_TDA8290: + tda8290_init(c); + break; + default: + default_tuner_init(c); + break; + } +} + +static char pal[] = "-"; +module_param_string(pal, pal, 0644, sizeof(pal)); + +static int tuner_fixup_std(struct tuner *t) +{ + if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { + /* get more precise norm info from insmod option */ + switch (pal[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + tuner_dbg("insmod fixup: PAL => PAL-BG\n"); + t->std = V4L2_STD_PAL_BG; + break; + case 'i': + case 'I': + tuner_dbg("insmod fixup: PAL => PAL-I\n"); + t->std = V4L2_STD_PAL_I; + break; + case 'd': + case 'D': + case 'k': + case 'K': + tuner_dbg("insmod fixup: PAL => PAL-DK\n"); + t->std = V4L2_STD_PAL_DK; + break; + } + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) +{ + struct tuner *t; + + if (this_adap > 0) + return -1; + this_adap++; + + client_template.adapter = adap; + client_template.addr = addr; + + t = kmalloc(sizeof(struct tuner),GFP_KERNEL); + if (NULL == t) + return -ENOMEM; + memset(t,0,sizeof(struct tuner)); + memcpy(&t->i2c,&client_template,sizeof(struct i2c_client)); + i2c_set_clientdata(&t->i2c, t); + t->type = UNSET; + t->radio_if2 = 10700*1000; // 10.7MHz - FM radio + + i2c_attach_client(&t->i2c); + tuner_info("chip found @ 0x%x (%s)\n", + addr << 1, adap->name); + set_type(&t->i2c, t->type); + return 0; +} + +static int tuner_probe(struct i2c_adapter *adap) +{ + if (0 != addr) { + normal_i2c[0] = addr; + normal_i2c_range[0] = addr; + normal_i2c_range[1] = addr; + } + this_adap = 0; + + if (adap->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, tuner_attach); + return 0; +} + +static int tuner_detach(struct i2c_client *client) +{ + struct tuner *t = i2c_get_clientdata(client); + + i2c_detach_client(&t->i2c); + kfree(t); + return 0; +} + +#define SWITCH_V4L2 if (!t->using_v4l2 && tuner_debug) \ + tuner_info("switching to v4l2\n"); \ + t->using_v4l2 = 1; +#define CHECK_V4L2 if (t->using_v4l2) { if (tuner_debug) \ + tuner_info("ignore v4l1 call\n"); \ + return 0; } + +static int +tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct tuner *t = i2c_get_clientdata(client); + unsigned int *iarg = (int*)arg; + + switch (cmd) { + + /* --- configuration --- */ + case TUNER_SET_TYPE: + set_type(client,*iarg); + break; + case AUDC_SET_RADIO: + if (V4L2_TUNER_RADIO != t->mode) { + set_tv_freq(client,400 * 16); + t->mode = V4L2_TUNER_RADIO; + } + break; + case AUDC_CONFIG_PINNACLE: + switch (*iarg) { + case 2: + tuner_dbg("pinnacle pal\n"); + t->radio_if2 = 33300 * 1000; + break; + case 3: + tuner_dbg("pinnacle ntsc\n"); + t->radio_if2 = 41300 * 1000; + break; + } + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCSCHAN: + { + static const v4l2_std_id map[] = { + [ VIDEO_MODE_PAL ] = V4L2_STD_PAL, + [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M, + [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM, + [ 4 /* bttv */ ] = V4L2_STD_PAL_M, + [ 5 /* bttv */ ] = V4L2_STD_PAL_N, + [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, + }; + struct video_channel *vc = arg; + + CHECK_V4L2; + t->mode = V4L2_TUNER_ANALOG_TV; + if (vc->norm < ARRAY_SIZE(map)) + t->std = map[vc->norm]; + tuner_fixup_std(t); + if (t->freq) + set_tv_freq(client,t->freq); + return 0; + } + case VIDIOCSFREQ: + { + unsigned long *v = arg; + + CHECK_V4L2; + set_freq(client,*v); + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner *vt = arg; + + CHECK_V4L2; + if (V4L2_TUNER_RADIO == t->mode && t->has_signal) + vt->signal = t->has_signal(client); + return 0; + } + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + CHECK_V4L2; + if (V4L2_TUNER_RADIO == t->mode && t->is_stereo) + va->mode = t->is_stereo(client) + ? VIDEO_SOUND_STEREO + : VIDEO_SOUND_MONO; + return 0; + } + + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + + SWITCH_V4L2; + t->mode = V4L2_TUNER_ANALOG_TV; + t->std = *id; + tuner_fixup_std(t); + if (t->freq) + set_freq(client,t->freq); + break; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + SWITCH_V4L2; + if (V4L2_TUNER_RADIO == f->type && + V4L2_TUNER_RADIO != t->mode) + set_tv_freq(client,400*16); + t->mode = f->type; + t->freq = f->frequency; + set_freq(client,t->freq); + break; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *tuner = arg; + + SWITCH_V4L2; + if (V4L2_TUNER_RADIO == t->mode && t->has_signal) + tuner->signal = t->has_signal(client); + break; + } + default: + /* nothing */ + break; + } + + return 0; +} + +static int tuner_suspend(struct device * dev, u32 state, u32 level) +{ + struct i2c_client *c = container_of(dev, struct i2c_client, dev); + struct tuner *t = i2c_get_clientdata(c); + + tuner_dbg("suspend\n"); + /* FIXME: power down ??? */ + return 0; +} + +static int tuner_resume(struct device * dev, u32 level) +{ + struct i2c_client *c = container_of(dev, struct i2c_client, dev); + struct tuner *t = i2c_get_clientdata(c); + + tuner_dbg("resume\n"); + if (t->freq) + set_freq(c,t->freq); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver driver = { + .owner = THIS_MODULE, + .name = "tuner", + .id = I2C_DRIVERID_TUNER, + .flags = I2C_DF_NOTIFY, + .attach_adapter = tuner_probe, + .detach_client = tuner_detach, + .command = tuner_command, + .driver = { + .suspend = tuner_suspend, + .resume = tuner_resume, + }, +}; +static struct i2c_client client_template = +{ + I2C_DEVNAME("(tuner unset)"), + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, +}; + +static int __init tuner_init_module(void) +{ + return i2c_add_driver(&driver); +} + +static void __exit tuner_cleanup_module(void) +{ + i2c_del_driver(&driver); +} + +module_init(tuner_init_module); +module_exit(tuner_cleanup_module); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/video/tuner-simple.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/media/video/tuner-simple.c 2005-03-08 10:32:50.000000000 +0100 @@ -0,0 +1,474 @@ +/* + * $Id: tuner-simple.c,v 1.10 2005/03/08 08:38:00 kraxel Exp $ + * + * i2c tv tuner chip device driver + * controls all those simple 4-control-bytes style tuners. + */ +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +/* tv standard selection for Temic 4046 FM5 + this value takes the low bits of control byte 2 + from datasheet Rev.01, Feb.00 + standard BG I L L2 D + picture IF 38.9 38.9 38.9 33.95 38.9 + sound 1 33.4 32.9 32.4 40.45 32.4 + sound 2 33.16 + NICAM 33.05 32.348 33.05 33.05 + */ +#define TEMIC_SET_PAL_I 0x05 +#define TEMIC_SET_PAL_DK 0x09 +#define TEMIC_SET_PAL_L 0x0a // SECAM ? +#define TEMIC_SET_PAL_L2 0x0b // change IF ! +#define TEMIC_SET_PAL_BG 0x0c + +/* tv tuner system standard selection for Philips FQ1216ME + this value takes the low bits of control byte 2 + from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") + standard BG DK I L L` + picture carrier 38.90 38.90 38.90 38.90 33.95 + colour 34.47 34.47 34.47 34.47 38.38 + sound 1 33.40 32.40 32.90 32.40 40.45 + sound 2 33.16 - - - - + NICAM 33.05 33.05 32.35 33.05 39.80 + */ +#define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ +#define PHILIPS_SET_PAL_BGDK 0x09 +#define PHILIPS_SET_PAL_L2 0x0a +#define PHILIPS_SET_PAL_L 0x0b + +/* system switching for Philips FI1216MF MK2 + from datasheet "1996 Jul 09", + standard BG L L' + picture carrier 38.90 38.90 33.95 + colour 34.47 34.37 38.38 + sound 1 33.40 32.40 40.45 + sound 2 33.16 - - + NICAM 33.05 33.05 39.80 + */ +#define PHILIPS_MF_SET_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ +#define PHILIPS_MF_SET_PAL_L 0x03 // France +#define PHILIPS_MF_SET_PAL_L2 0x02 // L' + + +/* ---------------------------------------------------------------------- */ + +struct tunertype +{ + char *name; + unsigned char Vendor; + unsigned char Type; + + unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ + unsigned short thresh2; /* band switch VHF_HI <=> UHF */ + unsigned char VHF_L; + unsigned char VHF_H; + unsigned char UHF; + unsigned char config; + unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, + 732 =16*45.75 NTSCi, + 940 =16*58.75 NTSC-Japan + 704 =16*44 ATSC */ +}; + +/* + * The floats in the tuner struct are computed at compile time + * by gcc and cast back to integers. Thus we don't violate the + * "no float in kernel" rule. + */ +static struct tunertype tuners[] = { + { "Temic PAL (4002 FH5)", TEMIC, PAL, + 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, + { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I, + 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, + { "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC, + 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, + { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM, + 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623}, + + { "NoTuner", NoTuner, NOTUNER, + 0,0,0x00,0x00,0x00,0x00,0x00}, + { "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL, + 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, + { "Temic NTSC (4032 FY5)", TEMIC, NTSC, + 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, + { "Temic PAL_I (4062 FY5)", TEMIC, PAL_I, + 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, + + { "Temic NTSC (4036 FY5)", TEMIC, NTSC, + 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, + { "Alps HSBH1", TEMIC, NTSC, + 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, + { "Alps TSBE1",TEMIC,PAL, + 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, + { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, + + { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, + { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, + { "Temic PAL_BG (4006FH5)", TEMIC, PAL, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "Alps TSCH6",Alps,NTSC, + 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732}, + + { "Temic PAL_DK (4016 FY5)",TEMIC,PAL, + 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623}, + { "Philips NTSC_M (MK2)",Philips,NTSC, + 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, + { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I, + 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, + { "Temic PAL* auto (4006 FN5)", TEMIC, PAL, + 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, + + { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL, + 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, + { "Temic NTSC (4039 FR5)", TEMIC, NTSC, + 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, + { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL, + 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, + { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + + { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC, + 16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732}, + + { "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, + 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, + { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ + 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 }, + + { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ + 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, + { "MT20xx universal", Microtune,PAL|NTSC, + /* see mt20xx.c for details */ }, + { "Temic PAL_BG (4106 FH5)", TEMIC, PAL, + 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, + { "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL, + 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623}, + + { "Temic NTSC (4136 FY5)", TEMIC, NTSC, + 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, + { "LG PAL (newer TAPC series)", LGINNOTEK, PAL, + 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623}, + { "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL, + 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, + { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC, + 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, + + { "HITACHI V7-J180AT", HITACHI, NTSC, + 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 }, + { "Philips PAL_MK (FI1216 MK)", Philips, PAL, + 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, + { "Philips 1236D ATSC/NTSC daul in",Philips,ATSC, + 16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732}, + { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC, + 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, + + { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC, + 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, + { "Microtune 4049 FM5",Microtune,PAL, + 16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623}, + { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC, + 16*160.00,16*454.00,0x01,0x02,0x08,0xce,940}, + { "LG NTSC (TAPE series)", LGINNOTEK, NTSC, + 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, + + { "Tenna TNF 8831 BGFF)", Philips, PAL, + 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, + { "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC, + 16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732}, + { "TCL 2002N", TCL, NTSC, + 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732}, + { "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL, + 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, + + { "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC, + 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, + { "Philips FQ1286", Philips, NTSC, + 16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, // UHF band untested + { "tda8290+75", Philips,PAL|NTSC, + /* see tda8290.c for details */ }, + { "LG PAL (TAPE series)", LGINNOTEK, PAL, + 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623}, + + { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL, + 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, + { "Philips FQ1236A MK4", Philips, NTSC, + 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, + +}; +unsigned const int tuner_count = ARRAY_SIZE(tuners); + +/* ---------------------------------------------------------------------- */ + +static int tuner_getstatus(struct i2c_client *c) +{ + unsigned char byte; + + if (1 != i2c_master_recv(c,&byte,1)) + return 0; + return byte; +} + +#define TUNER_POR 0x80 +#define TUNER_FL 0x40 +#define TUNER_MODE 0x38 +#define TUNER_AFC 0x07 + +#define TUNER_STEREO 0x10 /* radio mode */ +#define TUNER_SIGNAL 0x07 /* radio mode */ + +static int tuner_signal(struct i2c_client *c) +{ + return (tuner_getstatus(c) & TUNER_SIGNAL)<<13; +} + +static int tuner_stereo(struct i2c_client *c) +{ + return (tuner_getstatus (c) & TUNER_STEREO); +} + +#if 0 /* unused */ +static int tuner_islocked (struct i2c_client *c) +{ + return (tuner_getstatus (c) & TUNER_FL); +} + +static int tuner_afcstatus (struct i2c_client *c) +{ + return (tuner_getstatus (c) & TUNER_AFC) - 2; +} + +static int tuner_mode (struct i2c_client *c) +{ + return (tuner_getstatus (c) & TUNER_MODE) >> 3; +} +#endif + +/* ---------------------------------------------------------------------- */ + +static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + u8 config; + u16 div; + struct tunertype *tun; + unsigned char buffer[4]; + int rc; + + tun = &tuners[t->type]; + if (freq < tun->thresh1) { + config = tun->VHF_L; + tuner_dbg("tv: VHF lowrange\n"); + } else if (freq < tun->thresh2) { + config = tun->VHF_H; + tuner_dbg("tv: VHF high range\n"); + } else { + config = tun->UHF; + tuner_dbg("tv: UHF range\n"); + } + + + /* tv norm specific stuff for multi-norm tuners */ + switch (t->type) { + case TUNER_PHILIPS_SECAM: // FI1216MF + /* 0x01 -> ??? no change ??? */ + /* 0x02 -> PAL BDGHI / SECAM L */ + /* 0x04 -> ??? PAL others / SECAM others ??? */ + config &= ~0x02; + if (t->std & V4L2_STD_SECAM) + config |= 0x02; + break; + + case TUNER_TEMIC_4046FM5: + config &= ~0x0f; + + if (t->std & V4L2_STD_PAL_BG) { + config |= TEMIC_SET_PAL_BG; + + } else if (t->std & V4L2_STD_PAL_I) { + config |= TEMIC_SET_PAL_I; + + } else if (t->std & V4L2_STD_PAL_DK) { + config |= TEMIC_SET_PAL_DK; + + } else if (t->std & V4L2_STD_SECAM_L) { + config |= TEMIC_SET_PAL_L; + + } + break; + + case TUNER_PHILIPS_FQ1216ME: + config &= ~0x0f; + + if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { + config |= PHILIPS_SET_PAL_BGDK; + + } else if (t->std & V4L2_STD_PAL_I) { + config |= PHILIPS_SET_PAL_I; + + } else if (t->std & V4L2_STD_SECAM_L) { + config |= PHILIPS_SET_PAL_L; + + } + break; + + case TUNER_PHILIPS_ATSC: + /* 0x00 -> ATSC antenna input 1 */ + /* 0x01 -> ATSC antenna input 2 */ + /* 0x02 -> NTSC antenna input 1 */ + /* 0x03 -> NTSC antenna input 2 */ + config &= ~0x03; + if (!(t->std & V4L2_STD_ATSC)) + config |= 2; + /* FIXME: input */ + break; + + case TUNER_MICROTUNE_4042FI5: + /* Set the charge pump for fast tuning */ + tun->config |= 0x40; + break; + } + + /* + * Philips FI1216MK2 remark from specification : + * for channel selection involving band switching, and to ensure + * smooth tuning to the desired channel without causing + * unnecessary charge pump action, it is recommended to consider + * the difference between wanted channel frequency and the + * current channel frequency. Unnecessary charge pump action + * will result in very low tuning voltage which may drive the + * oscillator to extreme conditions. + * + * Progfou: specification says to send config data before + * frequency in case (wanted frequency < current frequency). + */ + + div=freq + tun->IFPCoff; + if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { + buffer[0] = tun->config; + buffer[1] = config; + buffer[2] = (div>>8) & 0x7f; + buffer[3] = div & 0xff; + } else { + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = tun->config; + buffer[3] = config; + } + tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0],buffer[1],buffer[2],buffer[3]); + + if (4 != (rc = i2c_master_send(c,buffer,4))) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); + + if (t->type == TUNER_MICROTUNE_4042FI5) { + // FIXME - this may also work for other tuners + unsigned long timeout = jiffies + msecs_to_jiffies(1); + u8 status_byte = 0; + + /* Wait until the PLL locks */ + for (;;) { + if (time_after(jiffies,timeout)) + return; + if (1 != (rc = i2c_master_recv(c,&status_byte,1))) { + tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); + break; + } + /* bit 6 is PLL locked indicator */ + if (status_byte & 0x40) + break; + udelay(10); + } + + /* Set the charge pump for optimized phase noise figure */ + tun->config &= ~0x40; + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = tun->config; + buffer[3] = config; + tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0],buffer[1],buffer[2],buffer[3]); + + if (4 != (rc = i2c_master_send(c,buffer,4))) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); + } +} + +static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tunertype *tun; + struct tuner *t = i2c_get_clientdata(c); + unsigned char buffer[4]; + unsigned div; + int rc; + + tun=&tuners[t->type]; + div = freq + (int)(16*10.7); + buffer[2] = tun->config; + + switch (t->type) { + case TUNER_PHILIPS_FM1216ME_MK3: + case TUNER_PHILIPS_FM1236_MK3: + buffer[3] = 0x19; + break; + case TUNER_PHILIPS_FM1256_IH3: + div = (20 * freq)/16 + 333 * 2; + buffer[2] = 0x80; + buffer[3] = 0x19; + break; + case TUNER_LG_PAL_FM: + buffer[3] = 0xa5; + break; + default: + buffer[3] = 0xa4; + break; + } + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + + tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0],buffer[1],buffer[2],buffer[3]); + + if (4 != (rc = i2c_master_send(c,buffer,4))) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); +} + +int default_tuner_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + tuner_info("type set to %d (%s)\n", + t->type, tuners[t->type].name); + strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); + + t->tv_freq = default_set_tv_freq; + t->radio_freq = default_set_radio_freq; + t->has_signal = tuner_signal; + t->is_stereo = tuner_stereo; + return 0; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/drivers/media/video/tuner.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/tuner.c 2005-03-07 10:16:33.000000000 +0100 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,1425 +0,0 @@ -/* - * $Id: tuner.c,v 1.36 2005/01/14 13:29:40 kraxel Exp $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define UNSET (-1U) - -/* standard i2c insmod options */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END}; -I2C_CLIENT_INSMOD; - -/* insmod options used at init time => read/only */ -static unsigned int type = UNSET; -static unsigned int addr = 0; -module_param(type, int, 0444); -module_param(addr, int, 0444); - -/* insmod options used at runtime => read/write */ -static unsigned int debug = 0; -static unsigned int tv_antenna = 1; -static unsigned int radio_antenna = 0; -static unsigned int optimize_vco = 1; -module_param(debug, int, 0644); -module_param(tv_antenna, int, 0644); -module_param(radio_antenna, int, 0644); -module_param(optimize_vco, int, 0644); - -static unsigned int tv_range[2] = { 44, 958 }; -static unsigned int radio_range[2] = { 65, 108 }; - -module_param_array(tv_range, int, NULL, 0644); -module_param_array(radio_range, int, NULL, 0644); - -MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); -MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -MODULE_LICENSE("GPL"); - -static int this_adap; -#define dprintk if (debug) printk - -struct tuner { - unsigned int type; /* chip type */ - unsigned int freq; /* keep track of the current settings */ - v4l2_std_id std; - int using_v4l2; - - enum v4l2_tuner_type mode; - unsigned int input; - - // only for MT2032 - unsigned int xogc; - unsigned int radio_if2; - - void (*tv_freq)(struct i2c_client *c, unsigned int freq); - void (*radio_freq)(struct i2c_client *c, unsigned int freq); -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - -/* ---------------------------------------------------------------------- */ - -/* tv standard selection for Temic 4046 FM5 - this value takes the low bits of control byte 2 - from datasheet Rev.01, Feb.00 - standard BG I L L2 D - picture IF 38.9 38.9 38.9 33.95 38.9 - sound 1 33.4 32.9 32.4 40.45 32.4 - sound 2 33.16 - NICAM 33.05 32.348 33.05 33.05 - */ -#define TEMIC_SET_PAL_I 0x05 -#define TEMIC_SET_PAL_DK 0x09 -#define TEMIC_SET_PAL_L 0x0a // SECAM ? -#define TEMIC_SET_PAL_L2 0x0b // change IF ! -#define TEMIC_SET_PAL_BG 0x0c - -/* tv tuner system standard selection for Philips FQ1216ME - this value takes the low bits of control byte 2 - from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") - standard BG DK I L L` - picture carrier 38.90 38.90 38.90 38.90 33.95 - colour 34.47 34.47 34.47 34.47 38.38 - sound 1 33.40 32.40 32.90 32.40 40.45 - sound 2 33.16 - - - - - NICAM 33.05 33.05 32.35 33.05 39.80 - */ -#define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ -#define PHILIPS_SET_PAL_BGDK 0x09 -#define PHILIPS_SET_PAL_L2 0x0a -#define PHILIPS_SET_PAL_L 0x0b - -/* system switching for Philips FI1216MF MK2 - from datasheet "1996 Jul 09", - standard BG L L' - picture carrier 38.90 38.90 33.95 - colour 34.47 34.37 38.38 - sound 1 33.40 32.40 40.45 - sound 2 33.16 - - - NICAM 33.05 33.05 39.80 - */ -#define PHILIPS_MF_SET_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ -#define PHILIPS_MF_SET_PAL_L 0x03 // France -#define PHILIPS_MF_SET_PAL_L2 0x02 // L' - - -/* ---------------------------------------------------------------------- */ - -struct tunertype -{ - char *name; - unsigned char Vendor; - unsigned char Type; - - unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ - unsigned short thresh2; /* band switch VHF_HI <=> UHF */ - unsigned char VHF_L; - unsigned char VHF_H; - unsigned char UHF; - unsigned char config; - unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, - 732 =16*45.75 NTSCi, - 940 =16*58.75 NTSC-Japan - 704 =16*44 ATSC */ -}; - -/* - * The floats in the tuner struct are computed at compile time - * by gcc and cast back to integers. Thus we don't violate the - * "no float in kernel" rule. - */ -static struct tunertype tuners[] = { - { "Temic PAL (4002 FH5)", TEMIC, PAL, - 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, - { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I, - 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, - { "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC, - 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, - { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM, - 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623}, - - { "NoTuner", NoTuner, NOTUNER, - 0,0,0x00,0x00,0x00,0x00,0x00}, - { "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL, - 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, - { "Temic NTSC (4032 FY5)", TEMIC, NTSC, - 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, - { "Temic PAL_I (4062 FY5)", TEMIC, PAL_I, - 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, - - { "Temic NTSC (4036 FY5)", TEMIC, NTSC, - 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, - { "Alps HSBH1", TEMIC, NTSC, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, - { "Alps TSBE1",TEMIC,PAL, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, - { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, - - { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, - { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, - { "Temic PAL_BG (4006FH5)", TEMIC, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "Alps TSCH6",Alps,NTSC, - 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732}, - - { "Temic PAL_DK (4016 FY5)",TEMIC,PAL, - 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623}, - { "Philips NTSC_M (MK2)",Philips,NTSC, - 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, - { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I, - 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, - { "Temic PAL* auto (4006 FN5)", TEMIC, PAL, - 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, - - { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL, - 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, - { "Temic NTSC (4039 FR5)", TEMIC, NTSC, - 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, - { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL, - 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, - { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - - { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC, - 16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732}, - - { "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, - 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, - { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ - 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 }, - - { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ - 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, - { "MT20xx universal", Microtune,PAL|NTSC, - 0,0,0,0,0,0,0}, - { "Temic PAL_BG (4106 FH5)", TEMIC, PAL, - 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, - { "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL, - 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623}, - - { "Temic NTSC (4136 FY5)", TEMIC, NTSC, - 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, - { "LG PAL (newer TAPC series)", LGINNOTEK, PAL, - 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623}, - { "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, - { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC, - 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, - - { "HITACHI V7-J180AT", HITACHI, NTSC, - 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 }, - { "Philips PAL_MK (FI1216 MK)", Philips, PAL, - 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, - { "Philips 1236D ATSC/NTSC daul in",Philips,ATSC, - 16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732}, - { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, - - { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, - { "Microtune 4049 FM5",Microtune,PAL, - 16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623}, - { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC, - 16*160.00,16*454.00,0x01,0x02,0x08,0xce,940}, - { "LG NTSC (TAPE series)", LGINNOTEK, NTSC, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, - - { "Tenna TNF 8831 BGFF)", Philips, PAL, - 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, - { "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC, - 16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732}, - { "TCL 2002N", TCL, NTSC, - 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732}, - { "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, - - { "Thomson DDT 7610 ATSC/NTSC)", THOMSON, ATSC, - 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, - { "Philips FQ1286", Philips, NTSC, - 16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, // UHF band untested - -}; -#define TUNERS ARRAY_SIZE(tuners) - -/* ---------------------------------------------------------------------- */ - -static int tuner_getstatus(struct i2c_client *c) -{ - unsigned char byte; - - struct tuner *t = i2c_get_clientdata(c); - - if (t->type == TUNER_MT2032) - return 0; - - if (1 != i2c_master_recv(c,&byte,1)) - return 0; - return byte; -} - -#define TUNER_POR 0x80 -#define TUNER_FL 0x40 -#define TUNER_MODE 0x38 -#define TUNER_AFC 0x07 - -#define TUNER_STEREO 0x10 /* radio mode */ -#define TUNER_SIGNAL 0x07 /* radio mode */ - -static int tuner_signal(struct i2c_client *c) -{ - return (tuner_getstatus(c) & TUNER_SIGNAL)<<13; -} - -static int tuner_stereo(struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_STEREO); -} - -#if 0 /* unused */ -static int tuner_islocked (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_FL); -} - -static int tuner_afcstatus (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_AFC) - 2; -} - -static int tuner_mode (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_MODE) >> 3; -} -#endif - -/* ---------------------------------------------------------------------- */ - -#define MT2032 0x04 -#define MT2030 0x06 -#define MT2040 0x07 -#define MT2050 0x42 - -static char *microtune_part[] = { - [ MT2030 ] = "MT2030", - [ MT2032 ] = "MT2032", - [ MT2040 ] = "MT2040", - [ MT2050 ] = "MT2050", -}; - -// IsSpurInBand()? -static int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to) -{ - int n1=1,n2,f; - - f1=f1/1000; //scale to kHz to avoid 32bit overflows - f2=f2/1000; - spectrum_from/=1000; - spectrum_to/=1000; - - dprintk("spurcheck f1=%d f2=%d from=%d to=%d\n",f1,f2,spectrum_from,spectrum_to); - - do { - n2=-n1; - f=n1*(f1-f2); - do { - n2--; - f=f-f2; - dprintk(" spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); - - if( (f>spectrum_from) && (f(f2-spectrum_to)) || (n2>-5)); - n1++; - } while (n1<5); - - return 1; -} - -static int mt2032_compute_freq(unsigned int rfin, - unsigned int if1, unsigned int if2, - unsigned int spectrum_from, - unsigned int spectrum_to, - unsigned char *buf, - int *ret_sel, - unsigned int xogc) //all in Hz -{ - unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, - desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; - - fref= 5250 *1000; //5.25MHz - desired_lo1=rfin+if1; - - lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); - lo1n=lo1/8; - lo1a=lo1-(lo1n*8); - - s=rfin/1000/1000+1090; - - if(optimize_vco) { - if(s>1890) sel=0; - else if(s>1720) sel=1; - else if(s>1530) sel=2; - else if(s>1370) sel=3; - else sel=4; // >1090 - } - else { - if(s>1790) sel=0; // <1958 - else if(s>1617) sel=1; - else if(s>1449) sel=2; - else if(s>1291) sel=3; - else sel=4; // >1090 - } - *ret_sel=sel; - - lo1freq=(lo1a+8*lo1n)*fref; - - dprintk("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", - rfin,lo1,lo1n,lo1a,sel,lo1freq); - - desired_lo2=lo1freq-rfin-if2; - lo2=(desired_lo2)/fref; - lo2n=lo2/8; - lo2a=lo2-(lo2n*8); - lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith - lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; - - dprintk("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", - rfin,lo2,lo2n,lo2a,lo2num,lo2freq); - - if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) { - printk("mt2032: frequency parameters out of range: %d %d %d %d\n", - lo1a, lo1n, lo2a,lo2n); - return(-1); - } - - mt2032_spurcheck(lo1freq, desired_lo2, spectrum_from, spectrum_to); - // should recalculate lo1 (one step up/down) - - // set up MT2032 register map for transfer over i2c - buf[0]=lo1n-1; - buf[1]=lo1a | (sel<<4); - buf[2]=0x86; // LOGC - buf[3]=0x0f; //reserved - buf[4]=0x1f; - buf[5]=(lo2n-1) | (lo2a<<5); - if(rfin >400*1000*1000) - buf[6]=0xe4; - else - buf[6]=0xf4; // set PKEN per rev 1.2 - buf[7]=8+xogc; - buf[8]=0xc3; //reserved - buf[9]=0x4e; //reserved - buf[10]=0xec; //reserved - buf[11]=(lo2num&0xff); - buf[12]=(lo2num>>8) |0x80; // Lo2RST - - return 0; -} - -static int mt2032_check_lo_lock(struct i2c_client *c) -{ - int try,lock=0; - unsigned char buf[2]; - for(try=0;try<10;try++) { - buf[0]=0x0e; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); - dprintk("mt2032 Reg.E=0x%02x\n",buf[0]); - lock=buf[0] &0x06; - - if (lock==6) - break; - - dprintk("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); - udelay(1000); - } - return lock; -} - -static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) -{ - unsigned char buf[2]; - int tad1; - - buf[0]=0x0f; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); - dprintk("mt2032 Reg.F=0x%02x\n",buf[0]); - tad1=buf[0]&0x07; - - if(tad1 ==0) return lock; - if(tad1 ==1) return lock; - - if(tad1==2) { - if(sel==0) - return lock; - else sel--; - } - else { - if(sel<4) - sel++; - else - return lock; - } - - dprintk("mt2032 optimize_vco: sel=%d\n",sel); - - buf[0]=0x0f; - buf[1]=sel; - i2c_master_send(c,buf,2); - lock=mt2032_check_lo_lock(c); - return lock; -} - - -static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, - unsigned int if1, unsigned int if2, - unsigned int from, unsigned int to) -{ - unsigned char buf[21]; - int lint_try,ret,sel,lock=0; - struct tuner *t = i2c_get_clientdata(c); - - dprintk("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",rfin,if1,if2,from,to); - - buf[0]=0; - ret=i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,21); - - buf[0]=0; - ret=mt2032_compute_freq(rfin,if1,if2,from,to,&buf[1],&sel,t->xogc); - if (ret<0) - return; - - // send only the relevant registers per Rev. 1.2 - buf[0]=0; - ret=i2c_master_send(c,buf,4); - buf[5]=5; - ret=i2c_master_send(c,buf+5,4); - buf[11]=11; - ret=i2c_master_send(c,buf+11,3); - if(ret!=3) - printk("mt2032_set_if_freq failed with %d\n",ret); - - // wait for PLLs to lock (per manual), retry LINT if not. - for(lint_try=0; lint_try<2; lint_try++) { - lock=mt2032_check_lo_lock(c); - - if(optimize_vco) - lock=mt2032_optimize_vco(c,sel,lock); - if(lock==6) break; - - printk("mt2032: re-init PLLs by LINT\n"); - buf[0]=7; - buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs - i2c_master_send(c,buf,2); - mdelay(10); - buf[1]=8+t->xogc; - i2c_master_send(c,buf,2); - } - - if (lock!=6) - printk("MT2032 Fatal Error: PLLs didn't lock.\n"); - - buf[0]=2; - buf[1]=0x20; // LOGC for optimal phase noise - ret=i2c_master_send(c,buf,2); - if (ret!=2) - printk("mt2032_set_if_freq2 failed with %d\n",ret); -} - - -static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = i2c_get_clientdata(c); - int if2,from,to; - - // signal bandwidth and picture carrier - if (t->std & V4L2_STD_525_60) { - // NTSC - from = 40750*1000; - to = 46750*1000; - if2 = 45750*1000; - } else { - // PAL - from = 32900*1000; - to = 39900*1000; - if2 = 38900*1000; - } - - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, - 1090*1000*1000, if2, from, to); -} - -static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = i2c_get_clientdata(c); - int if2 = t->radio_if2; - - // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, - 1085*1000*1000,if2,if2,if2); -} - -// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct i2c_client *c) -{ - struct tuner *t = i2c_get_clientdata(c); - unsigned char buf[21]; - int ret,xogc,xok=0; - - // Initialize Registers per spec. - buf[1]=2; // Index to register 2 - buf[2]=0xff; - buf[3]=0x0f; - buf[4]=0x1f; - ret=i2c_master_send(c,buf+1,4); - - buf[5]=6; // Index register 6 - buf[6]=0xe4; - buf[7]=0x8f; - buf[8]=0xc3; - buf[9]=0x4e; - buf[10]=0xec; - ret=i2c_master_send(c,buf+5,6); - - buf[12]=13; // Index register 13 - buf[13]=0x32; - ret=i2c_master_send(c,buf+12,2); - - // Adjust XOGC (register 7), wait for XOK - xogc=7; - do { - dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); - mdelay(10); - buf[0]=0x0e; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); - xok=buf[0]&0x01; - dprintk("mt2032: xok = 0x%02x\n",xok); - if (xok == 1) break; - - xogc--; - dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); - if (xogc == 3) { - xogc=4; // min. 4 per spec - break; - } - buf[0]=0x07; - buf[1]=0x88 + xogc; - ret=i2c_master_send(c,buf,2); - if (ret!=2) - printk("mt2032_init failed with %d\n",ret); - } while (xok != 1 ); - t->xogc=xogc; - - t->tv_freq = mt2032_set_tv_freq; - t->radio_freq = mt2032_set_radio_freq; - return(1); -} - -static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna) -{ - unsigned char buf[2]; - int ret; - - buf[0] = 6; - buf[1] = antenna ? 0x11 : 0x10; - ret=i2c_master_send(c,buf,2); - dprintk("mt2050: enabled antenna connector %d\n", antenna); -} - -static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) -{ - unsigned int if1=1218*1000*1000; - unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; - int ret; - unsigned char buf[6]; - - dprintk("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", - freq,if1,if2); - - f_lo1=freq+if1; - f_lo1=(f_lo1/1000000)*1000000; - - f_lo2=f_lo1-freq-if2; - f_lo2=(f_lo2/50000)*50000; - - lo1=f_lo1/4000000; - lo2=f_lo2/4000000; - - f_lo1_modulo= f_lo1-(lo1*4000000); - f_lo2_modulo= f_lo2-(lo2*4000000); - - num1=4*f_lo1_modulo/4000000; - num2=4096*(f_lo2_modulo/1000)/4000; - - // todo spurchecks - - div1a=(lo1/12)-1; - div1b=lo1-(div1a+1)*12; - - div2a=(lo2/8)-1; - div2b=lo2-(div2a+1)*8; - - if (debug > 1) { - printk("lo1 lo2 = %d %d\n", lo1, lo2); - printk("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",num1,num2,div1a,div1b,div2a,div2b); - } - - buf[0]=1; - buf[1]= 4*div1b + num1; - if(freq<275*1000*1000) buf[1] = buf[1]|0x80; - - buf[2]=div1a; - buf[3]=32*div2b + num2/256; - buf[4]=num2-(num2/256)*256; - buf[5]=div2a; - if(num2!=0) buf[5]=buf[5]|0x40; - - if (debug > 1) { - int i; - printk("bufs is: "); - for(i=0;i<6;i++) - printk("%x ",buf[i]); - printk("\n"); - } - - ret=i2c_master_send(c,buf,6); - if (ret!=6) - printk("mt2050_set_if_freq failed with %d\n",ret); -} - -static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = i2c_get_clientdata(c); - unsigned int if2; - - if (t->std & V4L2_STD_525_60) { - // NTSC - if2 = 45750*1000; - } else { - // PAL - if2 = 38900*1000; - } - if (V4L2_TUNER_DIGITAL_TV == t->mode) { - // testing for DVB ... - if2 = 36150*1000; - } - mt2050_set_if_freq(c, freq*62500, if2); - mt2050_set_antenna(c, tv_antenna); -} - -static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = i2c_get_clientdata(c); - int if2 = t->radio_if2; - - mt2050_set_if_freq(c, freq*62500, if2); - mt2050_set_antenna(c, radio_antenna); -} - -static int mt2050_init(struct i2c_client *c) -{ - struct tuner *t = i2c_get_clientdata(c); - unsigned char buf[2]; - int ret; - - buf[0]=6; - buf[1]=0x10; - ret=i2c_master_send(c,buf,2); // power - - buf[0]=0x0f; - buf[1]=0x0f; - ret=i2c_master_send(c,buf,2); // m1lo - - buf[0]=0x0d; - ret=i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); - - dprintk("mt2050: sro is %x\n",buf[0]); - t->tv_freq = mt2050_set_tv_freq; - t->radio_freq = mt2050_set_radio_freq; - return 0; -} - -static int microtune_init(struct i2c_client *c) -{ - struct tuner *t = i2c_get_clientdata(c); - char *name; - unsigned char buf[21]; - int company_code; - - memset(buf,0,sizeof(buf)); - t->tv_freq = NULL; - t->radio_freq = NULL; - name = "unknown"; - - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,21); - if(debug) { - int i; - printk(KERN_DEBUG "tuner: MT2032 hexdump:\n"); - for(i=0;i<21;i++) { - printk(" %02x",buf[i]); - if(((i+1)%8)==0) printk(" "); - if(((i+1)%16)==0) printk("\n "); - } - printk("\n "); - } - company_code = buf[0x11] << 8 | buf[0x12]; - printk("tuner: microtune: companycode=%04x part=%02x rev=%02x\n", - company_code,buf[0x13],buf[0x14]); - -#if 0 - /* seems to cause more problems than it solves ... */ - switch (company_code) { - case 0x30bf: - case 0x3cbf: - case 0x3dbf: - case 0x4d54: - case 0x8e81: - case 0x8e91: - /* ok (?) */ - break; - default: - printk("tuner: microtune: unknown companycode\n"); - return 0; - } -#endif - - if (buf[0x13] < ARRAY_SIZE(microtune_part) && - NULL != microtune_part[buf[0x13]]) - name = microtune_part[buf[0x13]]; - switch (buf[0x13]) { - case MT2032: - mt2032_init(c); - break; - case MT2050: - mt2050_init(c); - break; - default: - printk("tuner: microtune %s found, not (yet?) supported, sorry :-/\n", - name); - return 0; - } - printk("tuner: microtune %s found, OK\n",name); - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = i2c_get_clientdata(c); - u8 config; - u16 div; - struct tunertype *tun; - unsigned char buffer[4]; - int rc; - - tun = &tuners[t->type]; - if (freq < tun->thresh1) { - config = tun->VHF_L; - dprintk("tv: VHF lowrange\n"); - } else if (freq < tun->thresh2) { - config = tun->VHF_H; - dprintk("tv: VHF high range\n"); - } else { - config = tun->UHF; - dprintk("tv: UHF range\n"); - } - - - /* tv norm specific stuff for multi-norm tuners */ - switch (t->type) { - case TUNER_PHILIPS_SECAM: // FI1216MF - /* 0x01 -> ??? no change ??? */ - /* 0x02 -> PAL BDGHI / SECAM L */ - /* 0x04 -> ??? PAL others / SECAM others ??? */ - config &= ~0x02; - if (t->std & V4L2_STD_SECAM) - config |= 0x02; - break; - - case TUNER_TEMIC_4046FM5: - config &= ~0x0f; - - if (t->std & V4L2_STD_PAL_BG) { - config |= TEMIC_SET_PAL_BG; - - } else if (t->std & V4L2_STD_PAL_I) { - config |= TEMIC_SET_PAL_I; - - } else if (t->std & V4L2_STD_PAL_DK) { - config |= TEMIC_SET_PAL_DK; - - } else if (t->std & V4L2_STD_SECAM_L) { - config |= TEMIC_SET_PAL_L; - - } - break; - - case TUNER_PHILIPS_FQ1216ME: - config &= ~0x0f; - - if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { - config |= PHILIPS_SET_PAL_BGDK; - - } else if (t->std & V4L2_STD_PAL_I) { - config |= PHILIPS_SET_PAL_I; - - } else if (t->std & V4L2_STD_SECAM_L) { - config |= PHILIPS_SET_PAL_L; - - } - break; - - case TUNER_PHILIPS_ATSC: - /* 0x00 -> ATSC antenna input 1 */ - /* 0x01 -> ATSC antenna input 2 */ - /* 0x02 -> NTSC antenna input 1 */ - /* 0x03 -> NTSC antenna input 2 */ - config &= ~0x03; - if (!(t->std & V4L2_STD_ATSC)) - config |= 2; - /* FIXME: input */ - break; - - case TUNER_MICROTUNE_4042FI5: - /* Set the charge pump for fast tuning */ - tun->config |= 0x40; - break; - } - - /* - * Philips FI1216MK2 remark from specification : - * for channel selection involving band switching, and to ensure - * smooth tuning to the desired channel without causing - * unnecessary charge pump action, it is recommended to consider - * the difference between wanted channel frequency and the - * current channel frequency. Unnecessary charge pump action - * will result in very low tuning voltage which may drive the - * oscillator to extreme conditions. - * - * Progfou: specification says to send config data before - * frequency in case (wanted frequency < current frequency). - */ - - div=freq + tun->IFPCoff; - if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { - buffer[0] = tun->config; - buffer[1] = config; - buffer[2] = (div>>8) & 0x7f; - buffer[3] = div & 0xff; - } else { - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - buffer[2] = tun->config; - buffer[3] = config; - } - dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0],buffer[1],buffer[2],buffer[3]); - - if (4 != (rc = i2c_master_send(c,buffer,4))) - printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); - - if (t->type == TUNER_MICROTUNE_4042FI5) { - // FIXME - this may also work for other tuners - unsigned long timeout = jiffies + msecs_to_jiffies(1); - u8 status_byte = 0; - - /* Wait until the PLL locks */ - for (;;) { - if (time_after(jiffies,timeout)) - return; - if (1 != (rc = i2c_master_recv(c,&status_byte,1))) { - dprintk("tuner: i2c i/o read error: rc == %d (should be 1)\n",rc); - break; - } - /* bit 6 is PLL locked indicator */ - if (status_byte & 0x40) - break; - udelay(10); - } - - /* Set the charge pump for optimized phase noise figure */ - tun->config &= ~0x40; - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - buffer[2] = tun->config; - buffer[3] = config; - dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0],buffer[1],buffer[2],buffer[3]); - - if (4 != (rc = i2c_master_send(c,buffer,4))) - dprintk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); - } -} - -static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) -{ - struct tunertype *tun; - struct tuner *t = i2c_get_clientdata(c); - unsigned char buffer[4]; - unsigned div; - int rc; - - tun=&tuners[t->type]; - div = freq + (int)(16*10.7); - buffer[2] = tun->config; - - switch (t->type) { - case TUNER_PHILIPS_FM1216ME_MK3: - case TUNER_PHILIPS_FM1236_MK3: - buffer[3] = 0x19; - break; - case TUNER_PHILIPS_FM1256_IH3: - div = (20 * freq)/16 + 333 * 2; - buffer[2] = 0x80; - buffer[3] = 0x19; - break; - case TUNER_LG_PAL_FM: - buffer[3] = 0xa5; - break; - default: - buffer[3] = 0xa4; - break; - } - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - - dprintk("tuner: radio 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0],buffer[1],buffer[2],buffer[3]); - - if (4 != (rc = i2c_master_send(c,buffer,4))) - printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); -} - -/* ---------------------------------------------------------------------- */ - -// Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz -static void set_tv_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = i2c_get_clientdata(c); - - if (t->type == UNSET) { - printk("tuner: tuner type not set\n"); - return; - } - if (NULL == t->tv_freq) { - printk("tuner: Huh? tv_set is NULL?\n"); - return; - } - if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { - /* FIXME: better do that chip-specific, but - right now we don't have that in the config - struct and this way is still better than no - check at all */ - printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16,tv_range[0],tv_range[1]); - return; - } - t->tv_freq(c,freq); -} - -static void set_radio_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = i2c_get_clientdata(c); - - if (t->type == UNSET) { - printk("tuner: tuner type not set\n"); - return; - } - if (NULL == t->radio_freq) { - printk("tuner: no radio tuning for this one, sorry.\n"); - return; - } - if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { - printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16, - radio_range[0],radio_range[1]); - return; - } - t->radio_freq(c,freq); -} - -static void set_freq(struct i2c_client *c, unsigned long freq) -{ - struct tuner *t = i2c_get_clientdata(c); - - switch (t->mode) { - case V4L2_TUNER_RADIO: - dprintk("tuner: radio freq set to %lu.%02lu\n", - freq/16,freq%16*100/16); - set_radio_freq(c,freq); - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - dprintk("tuner: tv freq set to %lu.%02lu\n", - freq/16,freq%16*100/16); - set_tv_freq(c, freq); - break; - } - t->freq = freq; -} - -static void set_type(struct i2c_client *c, unsigned int type, char *source) -{ - struct tuner *t = i2c_get_clientdata(c); - - if (t->type != UNSET && t->type != TUNER_ABSENT) { - if (t->type != type) - printk("tuner: type already set to %d, " - "ignoring request for %d\n", t->type, type); - return; - } - if (type >= TUNERS) - return; - - t->type = type; - printk("tuner: type set to %d (%s) by %s\n", - t->type,tuners[t->type].name, source); - strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); - - switch (t->type) { - case TUNER_MT2032: - microtune_init(c); - break; - default: - t->tv_freq = default_set_tv_freq; - t->radio_freq = default_set_radio_freq; - break; - } -} - -static char pal[] = "-"; -module_param_string(pal, pal, 0644, sizeof(pal)); - -static int tuner_fixup_std(struct tuner *t) -{ - if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { - /* get more precise norm info from insmod option */ - switch (pal[0]) { - case 'b': - case 'B': - case 'g': - case 'G': - dprintk("insmod fixup: PAL => PAL-BG\n"); - t->std = V4L2_STD_PAL_BG; - break; - case 'i': - case 'I': - dprintk("insmod fixup: PAL => PAL-I\n"); - t->std = V4L2_STD_PAL_I; - break; - case 'd': - case 'D': - case 'k': - case 'K': - dprintk("insmod fixup: PAL => PAL-DK\n"); - t->std = V4L2_STD_PAL_DK; - break; - } - } - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) -{ - struct tuner *t; - struct i2c_client *client; - - if (this_adap > 0) - return -1; - this_adap++; - - client_template.adapter = adap; - client_template.addr = addr; - - printk("tuner: chip found at addr 0x%x i2c-bus %s\n", - addr<<1, adap->name); - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - t = kmalloc(sizeof(struct tuner),GFP_KERNEL); - if (NULL == t) { - kfree(client); - return -ENOMEM; - } - memset(t,0,sizeof(struct tuner)); - i2c_set_clientdata(client, t); - t->type = UNSET; - t->radio_if2 = 10700*1000; // 10.7MHz - FM radio - - i2c_attach_client(client); - if (type < TUNERS) { - set_type(client, type, "insmod option"); - printk("tuner: The type= insmod option will go away soon.\n"); - printk("tuner: Please use the tuner= option provided by\n"); - printk("tuner: tv aard core driver (bttv, saa7134, ...) instead.\n"); - } - return 0; -} - -static int tuner_probe(struct i2c_adapter *adap) -{ - if (0 != addr) { - normal_i2c_range[0] = addr; - normal_i2c_range[1] = addr; - } - this_adap = 0; - -#ifdef I2C_CLASS_TV_ANALOG - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, tuner_attach); -#else - switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3: - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: - case I2C_ALGO_SAA7134: - case I2C_ALGO_SAA7146: - return i2c_probe(adap, &addr_data, tuner_attach); - break; - } -#endif - return 0; -} - -static int tuner_detach(struct i2c_client *client) -{ - struct tuner *t = i2c_get_clientdata(client); - - i2c_detach_client(client); - kfree(t); - kfree(client); - return 0; -} - -#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \ - printk("tuner: switching to v4l2\n"); \ - t->using_v4l2 = 1; -#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \ - printk("tuner: ignore v4l1 call\n"); \ - return 0; } - -static int -tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct tuner *t = i2c_get_clientdata(client); - unsigned int *iarg = (int*)arg; - - switch (cmd) { - - /* --- configuration --- */ - case TUNER_SET_TYPE: - set_type(client,*iarg,client->adapter->name); - break; - case AUDC_SET_RADIO: - if (V4L2_TUNER_RADIO != t->mode) { - set_tv_freq(client,400 * 16); - t->mode = V4L2_TUNER_RADIO; - } - break; - case AUDC_CONFIG_PINNACLE: - switch (*iarg) { - case 2: - dprintk("tuner: pinnacle pal\n"); - t->radio_if2 = 33300 * 1000; - break; - case 3: - dprintk("tuner: pinnacle ntsc\n"); - t->radio_if2 = 41300 * 1000; - break; - } - break; - - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCSCHAN: - { - static const v4l2_std_id map[] = { - [ VIDEO_MODE_PAL ] = V4L2_STD_PAL, - [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M, - [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM, - [ 4 /* bttv */ ] = V4L2_STD_PAL_M, - [ 5 /* bttv */ ] = V4L2_STD_PAL_N, - [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, - }; - struct video_channel *vc = arg; - - CHECK_V4L2; - t->mode = V4L2_TUNER_ANALOG_TV; - if (vc->norm < ARRAY_SIZE(map)) - t->std = map[vc->norm]; - tuner_fixup_std(t); - if (t->freq) - set_tv_freq(client,t->freq); - return 0; - } - case VIDIOCSFREQ: - { - unsigned long *v = arg; - - CHECK_V4L2; - set_freq(client,*v); - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner *vt = arg; - - CHECK_V4L2; - if (V4L2_TUNER_RADIO == t->mode) - vt->signal = tuner_signal(client); - return 0; - } - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - CHECK_V4L2; - if (V4L2_TUNER_RADIO == t->mode) - va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO); - return 0; - } - - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - - SWITCH_V4L2; - t->mode = V4L2_TUNER_ANALOG_TV; - t->std = *id; - tuner_fixup_std(t); - if (t->freq) - set_freq(client,t->freq); - break; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - SWITCH_V4L2; - if (V4L2_TUNER_RADIO == f->type && - V4L2_TUNER_RADIO != t->mode) - set_tv_freq(client,400*16); - t->mode = f->type; - t->freq = f->frequency; - set_freq(client,t->freq); - break; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *tuner = arg; - - SWITCH_V4L2; - if (V4L2_TUNER_RADIO == t->mode) - tuner->signal = tuner_signal(client); - break; - } - default: - /* nothing */ - break; - } - - return 0; -} - -static int tuner_suspend(struct device * dev, u32 state, u32 level) -{ - dprintk("tuner: suspend\n"); - /* FIXME: power down ??? */ - return 0; -} - -static int tuner_resume(struct device * dev, u32 level) -{ - struct i2c_client *c = container_of(dev, struct i2c_client, dev); - struct tuner *t = i2c_get_clientdata(c); - - dprintk("tuner: resume\n"); - if (t->freq) - set_freq(c,t->freq); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "i2c TV tuner driver", - .id = I2C_DRIVERID_TUNER, - .flags = I2C_DF_NOTIFY, - .attach_adapter = tuner_probe, - .detach_client = tuner_detach, - .command = tuner_command, - .driver = { - .suspend = tuner_suspend, - .resume = tuner_resume, - }, -}; -static struct i2c_client client_template = -{ - I2C_DEVNAME("(tuner unset)"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init tuner_init_module(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit tuner_cleanup_module(void) -{ - i2c_del_driver(&driver); -} - -module_init(tuner_init_module); -module_exit(tuner_cleanup_module); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ Index: linux-2.6.11/drivers/media/video/tvaudio.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/tvaudio.c 2005-03-07 10:13:26.000000000 +0100 +++ linux-2.6.11/drivers/media/video/tvaudio.c 2005-03-07 18:13:02.000000000 +0100 @@ -990,7 +990,7 @@ static int tda9874a_initialize(struct CH { if (tda9874a_SIF > 2) tda9874a_SIF = 1; - if (tda9874a_STD >= 8) + if (tda9874a_STD > 8) tda9874a_STD = 0; if(tda9874a_AMSEL > 1) tda9874a_AMSEL = 0; Index: linux-2.6.11/drivers/media/video/tveeprom.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/tveeprom.c 2005-03-07 10:15:43.000000000 +0100 +++ linux-2.6.11/drivers/media/video/tveeprom.c 2005-03-08 10:33:08.000000000 +0100 @@ -30,10 +30,12 @@ #include +#include #include #include #include #include +#include #include #include @@ -73,7 +75,7 @@ hauppauge_tuner_fmt[] = { 0x00000007, "PAL(B/G)" }, { 0x00001000, "NTSC(M)" }, { 0x00000010, "PAL(I)" }, - { 0x00400000, "SECAM(L/L�)" }, + { 0x00400000, "SECAM(L/L´)" }, { 0x00000e00, "PAL(D/K)" }, { 0x03000000, "ATSC Digital" }, }; @@ -190,11 +192,13 @@ hauppauge_tuner[] = { TUNER_ABSENT, "TCL MFPE05 2"}, /* 90-99 */ { TUNER_ABSENT, "LG TALN H202T"}, - { TUNER_ABSENT, "Philips FQ1216AME MK4"}, - { TUNER_ABSENT, "Philips FQ1236A MK4"}, + { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, + { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, { TUNER_ABSENT, "Philips FQ1286A MK4"}, { TUNER_ABSENT, "Philips FQ1216ME MK5"}, { TUNER_ABSENT, "Philips FQ1236 MK5"}, + { TUNER_ABSENT, "Unspecified"}, + { TUNER_LG_PAL_TAPE, "LG PAL (TAPE Series)"}, }; static char *sndtype[] = { @@ -240,6 +244,7 @@ static int hasRadioTuner(int tunerType) case 61: //PNPEnv_TUNER_TAPE_M001D_MK3: case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM: case 89: //PNPEnv_TUNER_TCL_MFPE05_2: + case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4: return 1; } return 0; @@ -255,8 +260,8 @@ void tveeprom_hauppauge_analog(struct tv ** if packet[0] & f8 == f8, then EOD and packet[1] == checksum ** ** In our (ivtv) case we're interested in the following: - ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuners) - ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_fmts) + ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) + ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt) ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) ** audio proc: tag [02].01 or [05].00 (lower nibble indexes lut?) @@ -268,11 +273,11 @@ void tveeprom_hauppauge_analog(struct tv ** # of inputs/outputs ??? */ - int i, j, len, done, tag, tuner = 0, t_format = 0; + int i, j, len, done, beenhere, tag, tuner = 0, t_format = 0; char *t_name = NULL, *t_fmt_name = NULL; dprintk(1, "%s\n",__FUNCTION__); - tvee->revision = done = len = 0; + tvee->revision = done = len = beenhere = 0; for (i = 0; !done && i < 256; i += len) { dprintk(2, "processing pos = %02x (%02x, %02x)\n", i, eeprom_data[i], eeprom_data[i + 1]); @@ -341,9 +346,14 @@ void tveeprom_hauppauge_analog(struct tv (eeprom_data[i+7] << 16); break; case 0x0a: - tuner = eeprom_data[i+2]; - t_format = eeprom_data[i+1]; - break; + if(beenhere == 0) { + tuner = eeprom_data[i+2]; + t_format = eeprom_data[i+1]; + beenhere = 1; + break; + } else { + break; + } case 0x0e: tvee->has_radio = eeprom_data[i+1]; break; Index: linux-2.6.11/drivers/media/video/video-buf.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/video-buf.c 2005-03-07 10:13:55.000000000 +0100 +++ linux-2.6.11/drivers/media/video/video-buf.c 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: video-buf.c,v 1.17 2004/12/10 12:33:40 kraxel Exp $ + * $Id: video-buf.c,v 1.18 2005/02/24 13:32:30 kraxel Exp $ * * generic helper functions for video4linux capture buffers, to handle * memory management and PCI DMA. Right now bttv + saa7134 use it. @@ -217,9 +217,18 @@ int videobuf_dma_pci_map(struct pci_dev return -ENOMEM; } - if (!dma->bus_addr) + if (!dma->bus_addr) { dma->sglen = pci_map_sg(dev,dma->sglist,dma->nr_pages, dma->direction); + if (0 == dma->sglen) { + printk(KERN_WARNING + "%s: pci_map_sg failed\n",__FUNCTION__); + kfree(dma->sglist); + dma->sglist = NULL; + dma->sglen = 0; + return -EIO; + } + } return 0; } Index: linux-2.6.11/drivers/media/video/zoran_card.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/zoran_card.c 2005-03-07 10:14:15.000000000 +0100 +++ linux-2.6.11/drivers/media/video/zoran_card.c 2005-03-08 10:33:15.000000000 +0100 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -968,6 +969,7 @@ zoran_open_init_params (struct zoran *zr static void __devinit test_interrupts (struct zoran *zr) { + DEFINE_WAIT(wait); int timeout, icr; clear_interrupt_counters(zr); @@ -975,7 +977,9 @@ test_interrupts (struct zoran *zr) zr->testing = 1; icr = btread(ZR36057_ICR); btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR); - timeout = interruptible_sleep_on_timeout(&zr->test_q, 1 * HZ); + prepare_to_wait(&zr->test_q, &wait, TASK_INTERRUPTIBLE); + timeout = schedule_timeout(HZ); + finish_wait(&zr->test_q, &wait); btwrite(0, ZR36057_ICR); btwrite(0x78000000, ZR36057_ISR); zr->testing = 0; Index: linux-2.6.11/drivers/media/video/zoran_device.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/zoran_device.c 2005-03-07 10:14:13.000000000 +0100 +++ linux-2.6.11/drivers/media/video/zoran_device.c 2005-03-08 10:33:15.000000000 +0100 @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -696,11 +697,10 @@ wait_grab_pending (struct zoran *zr) if (!zr->v4l_memgrab_active) return 0; - while (zr->v4l_pend_tail != zr->v4l_pend_head) { - interruptible_sleep_on(&zr->v4l_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } + wait_event_interruptible(zr->v4l_capq, + (zr->v4l_pend_tail == zr->v4l_pend_head)); + if (signal_pending(current)) + return -ERESTARTSYS; spin_lock_irqsave(&zr->spinlock, flags); zr36057_set_memgrab(zr, 0); Index: linux-2.6.11/drivers/media/video/zoran_driver.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/zoran_driver.c 2005-03-07 10:14:50.000000000 +0100 +++ linux-2.6.11/drivers/media/video/zoran_driver.c 2005-03-08 10:33:15.000000000 +0100 @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -918,12 +919,12 @@ v4l_sync (struct file *file, } /* wait on this buffer to get ready */ - while (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_PEND) { - if (!interruptible_sleep_on_timeout(&zr->v4l_capq, 10 * HZ)) - return -ETIME; - else if (signal_pending(current)) - return -ERESTARTSYS; - } + if (!wait_event_interruptible_timeout(zr->v4l_capq, + (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), + 10*HZ)) + return -ETIME; + if (signal_pending(current)) + return -ERESTARTSYS; /* buffer should now be in BUZ_STATE_DONE */ if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE) @@ -1107,7 +1108,7 @@ jpg_sync (struct file *file, struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; unsigned long flags; - int frame, timeout; + int frame; if (fh->jpg_buffers.active == ZORAN_FREE) { dprintk(1, @@ -1124,29 +1125,26 @@ jpg_sync (struct file *file, ZR_DEVNAME(zr)); return -EINVAL; } - while (zr->jpg_que_tail == zr->jpg_dma_tail) { - if (zr->jpg_dma_tail == zr->jpg_dma_head) - break; - - timeout = - interruptible_sleep_on_timeout(&zr->jpg_capq, 10 * HZ); - if (!timeout) { - int isr; + if (!wait_event_interruptible_timeout(zr->jpg_capq, + (zr->jpg_que_tail != zr->jpg_dma_tail || + zr->jpg_dma_tail == zr->jpg_dma_head), + 10*HZ)) { + int isr; - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); - udelay(1); - zr->codec->control(zr->codec, CODEC_G_STATUS, + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); + udelay(1); + zr->codec->control(zr->codec, CODEC_G_STATUS, sizeof(isr), &isr); - dprintk(1, - KERN_ERR - "%s: jpg_sync() - timeout: codec isr=0x%02x\n", - ZR_DEVNAME(zr), isr); + dprintk(1, + KERN_ERR + "%s: jpg_sync() - timeout: codec isr=0x%02x\n", + ZR_DEVNAME(zr), isr); - return -ETIME; + return -ETIME; - } else if (signal_pending(current)) - return -ERESTARTSYS; } + if (signal_pending(current)) + return -ERESTARTSYS; spin_lock_irqsave(&zr->spinlock, flags); Index: linux-2.6.11/drivers/media/video/zr36120.c =================================================================== --- linux-2.6.11.orig/drivers/media/video/zr36120.c 2005-03-07 10:13:55.000000000 +0100 +++ linux-2.6.11/drivers/media/video/zr36120.c 2005-03-08 10:33:15.000000000 +0100 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -899,12 +900,11 @@ long zoran_read(struct video_device* dev zoran_cap(ztv, 1); /* wait till this buffer gets grabbed */ - while (unused->status == FBUFFER_BUSY) { - interruptible_sleep_on(&ztv->grabq); - /* see if a signal did it */ - if (signal_pending(current)) - return -EINTR; - } + wait_event_interruptible(ztv->grabq, + (unused->status != FBUFFER_BUSY)); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; done = unused; } else @@ -1326,12 +1326,11 @@ int zoran_ioctl(struct video_device* dev return -EINVAL; case FBUFFER_BUSY: /* wait till this buffer gets grabbed */ - while (ztv->grabinfo[i].status == FBUFFER_BUSY) { - interruptible_sleep_on(&ztv->grabq); - /* see if a signal did it */ - if (signal_pending(current)) - return -EINTR; - } + wait_event_interruptible(ztv->grabq, + (ztv->grabinfo[i].status != FBUFFER_BUSY)); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; /* don't fall through; a DONE buffer is not UNUSED */ break; case FBUFFER_DONE: @@ -1640,12 +1639,11 @@ long vbi_read(struct video_device* dev, zoran_cap(ztv, 1); /* wait till this buffer gets grabbed */ - while (unused->status == FBUFFER_BUSY) { - interruptible_sleep_on(&ztv->vbiq); - /* see if a signal did it */ - if (signal_pending(current)) - return -EINTR; - } + wait_event_interruptible(ztv->vbiq, + (unused->status != FBUFFER_BUSY)); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; done = unused; } else Index: linux-2.6.11/drivers/scsi/Kconfig =================================================================== --- linux-2.6.11.orig/drivers/scsi/Kconfig 2005-03-07 10:15:16.000000000 +0100 +++ linux-2.6.11/drivers/scsi/Kconfig 2005-03-07 18:13:01.000000000 +0100 @@ -137,6 +137,24 @@ config CHR_DEV_SG If unsure, say N. +config CHR_DEV_SCH + tristate "SCSI media changer support" + depends on SCSI + ---help--- + This is a driver for SCSI media changers. Most common devices are + tape libraries and MOD/CDROM jukeboxes. *Real* jukeboxes, you + don't need this for those tiny 6-slot cdrom changers. Media + changers are listed as "Type: Medium Changer" in /proc/scsi/scsi. + If you have such hardware and want to use it with linux, say Y + here. Check for details. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read and + . The module will be called ch.o. + If unsure, say N. + + comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" depends on SCSI Index: linux-2.6.11/drivers/scsi/Makefile =================================================================== --- linux-2.6.11.orig/drivers/scsi/Makefile 2005-03-07 10:14:58.000000000 +0100 +++ linux-2.6.11/drivers/scsi/Makefile 2005-03-07 18:13:01.000000000 +0100 @@ -141,6 +141,7 @@ obj-$(CONFIG_CHR_DEV_OSST) += osst.o obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o +obj-$(CONFIG_CHR_DEV_SCH) += ch.o scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_error.o scsi_lib.o \ Index: linux-2.6.11/drivers/scsi/ch.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/drivers/scsi/ch.c 2005-03-07 18:13:01.000000000 +0100 @@ -0,0 +1,1020 @@ +/* + * SCSI Media Changer device driver for Linux 2.6 + * + * (c) 1996-2003 Gerd Knorr + * + */ + +#define VERSION "0.24" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* here are all the ioctls */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CH_DT_MAX 16 +#define CH_TYPES 8 + +MODULE_DESCRIPTION("device driver for scsi media changer devices"); +MODULE_AUTHOR("Gerd Knorr "); +MODULE_LICENSE("GPL"); + +static int init = 1; +module_param(init, int, 0444); +MODULE_PARM_DESC(init, \ + "initialize element status on driver load (default: on)"); + +static int timeout_move = 300; +module_param(timeout_move, int, 0644); +MODULE_PARM_DESC(timeout_move,"timeout for move commands " + "(default: 300 seconds)"); + +static int timeout_init = 3600; +module_param(timeout_init, int, 0644); +MODULE_PARM_DESC(timeout_init,"timeout for INITIALIZE ELEMENT STATUS " + "(default: 3600 seconds)"); + +static int verbose = 1; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose,"be verbose (default: on)"); + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"enable/disable debug messages, also prints more " + "detailed sense codes on scsi errors (default: off)"); + +static int dt_id[CH_DT_MAX] = { [ 0 ... (CH_DT_MAX-1) ] = -1 }; +static int dt_lun[CH_DT_MAX]; +module_param_array(dt_id, int, NULL, 0444); +module_param_array(dt_lun, int, NULL, 0444); + +/* tell the driver about vendor-specific slots */ +static int vendor_firsts[CH_TYPES-4]; +static int vendor_counts[CH_TYPES-4]; +module_param_array(vendor_firsts, int, NULL, 0444); +module_param_array(vendor_counts, int, NULL, 0444); + +static char *vendor_labels[CH_TYPES-4] = { + "v0", "v1", "v2", "v3" +}; +// module_param_string_array(vendor_labels, NULL, 0444); + +#define dprintk(fmt, arg...) if (debug) \ + printk(KERN_DEBUG "%s: " fmt, ch->name, ##arg) +#define vprintk(fmt, arg...) if (verbose) \ + printk(KERN_INFO "%s: " fmt, ch->name, ##arg) + +/* ------------------------------------------------------------------- */ + +#define MAX_RETRIES 1 + +static int ch_probe(struct device *); +static int ch_remove(struct device *); +static int ch_open(struct inode * inode, struct file * filp); +static int ch_release(struct inode * inode, struct file * filp); +static int ch_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg); +static long ch_ioctl_compat(struct file * filp, + unsigned int cmd, unsigned long arg); + +typedef struct { + struct list_head list; + int minor; + char name[8]; + struct scsi_device *device; + struct scsi_device **dt; /* ptrs to data transfer elements */ + u_int firsts[CH_TYPES]; + u_int counts[CH_TYPES]; + u_int unit_attention; + u_int voltags; + struct semaphore lock; +} scsi_changer; + +static LIST_HEAD(ch_devlist); +static spinlock_t ch_devlist_lock = SPIN_LOCK_UNLOCKED; +static int ch_devcount; + +struct scsi_driver ch_template = +{ + .owner = THIS_MODULE, + .gendrv = { + .name = "ch", + .probe = ch_probe, + .remove = ch_remove, + }, +}; + +static struct file_operations changer_fops = +{ + .owner = THIS_MODULE, + .open = ch_open, + .release = ch_release, + .ioctl = ch_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ch_ioctl_compat, +#endif +}; + +static struct { + unsigned char sense; + unsigned char asc; + unsigned char ascq; + int errno; +} err[] = { +/* Just filled in what looks right. Hav'nt checked any standard paper for + these errno assignments, so they may be wrong... */ + { + .sense = ILLEGAL_REQUEST, + .asc = 0x21, + .ascq = 0x01, + .errno = EBADSLT, /* Invalid element address */ + },{ + .sense = ILLEGAL_REQUEST, + .asc = 0x28, + .ascq = 0x01, + .errno = EBADE, /* Import or export element accessed */ + },{ + .sense = ILLEGAL_REQUEST, + .asc = 0x3B, + .ascq = 0x0D, + .errno = EXFULL, /* Medium destination element full */ + },{ + .sense = ILLEGAL_REQUEST, + .asc = 0x3B, + .ascq = 0x0E, + .errno = EBADE, /* Medium source element empty */ + },{ + .sense = ILLEGAL_REQUEST, + .asc = 0x20, + .ascq = 0x00, + .errno = EBADRQC, /* Invalid command operation code */ + },{ + /* end of list */ + } +}; + +/* ------------------------------------------------------------------- */ + +static int ch_find_errno(unsigned char *sense_buffer) +{ + int i,errno = 0; + + /* Check to see if additional sense information is available */ + if (sense_buffer[7] > 5 && + sense_buffer[12] != 0) { + for (i = 0; err[i].errno != 0; i++) { + if (err[i].sense == sense_buffer[ 2] && + err[i].asc == sense_buffer[12] && + err[i].ascq == sense_buffer[13]) { + errno = -err[i].errno; + break; + } + } + } + if (errno == 0) + errno = -EIO; + return errno; +} + +static void +ch_request_done(struct scsi_cmnd *sc) +{ + sc->request->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + if (sc->request->waiting != NULL) + complete(sc->request->waiting); +} + +static int +ch_do_scsi(scsi_changer *ch, unsigned char *cmd, + void *buffer, unsigned buflength) +{ + int errno, retries = 0, timeout; + DECLARE_COMPLETION(wait); + struct scsi_request *sr; + + sr = scsi_allocate_request(ch->device, GFP_KERNEL); + if (NULL == sr) + return -ENOMEM; + + retry: + errno = 0; + if (debug) { + dprintk("command: "); + __scsi_print_command(cmd); + } + + sr->sr_request->waiting = &wait; + timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) + ? timeout_init : timeout_move; + scsi_do_req(sr, cmd, buffer, buflength, ch_request_done, + timeout * HZ, MAX_RETRIES); + wait_for_completion(&wait); + sr->sr_request->waiting = NULL; + + dprintk("result: 0x%x\n",sr->sr_result); + if (driver_byte(sr->sr_result) != 0) { + if (debug) + scsi_print_req_sense(ch->name, sr); + errno = ch_find_errno(sr->sr_sense_buffer); + + switch(sr->sr_sense_buffer[2] & 0xf) { + case UNIT_ATTENTION: + ch->unit_attention = 1; + if (retries++ < 3) + goto retry; + break; + } + } + scsi_release_request(sr); + return errno; +} + +/* ------------------------------------------------------------------------ */ + +static int +ch_elem_to_typecode(scsi_changer *ch, u_int elem) +{ + int i; + + for (i = 0; i < CH_TYPES; i++) { + if (elem >= ch->firsts[i] && + elem < ch->firsts[i] + + ch->counts[i]) + return i+1; + } + return 0; +} + +static int +ch_read_element_status(scsi_changer *ch, u_int elem, char *data) +{ + u_char cmd[12]; + u_char *buffer; + int result; + + buffer = kmalloc(512, GFP_KERNEL); + if(!buffer) + return -ENOMEM; + + retry: + memset(cmd,0,sizeof(cmd)); + cmd[0] = READ_ELEMENT_STATUS; + cmd[1] = (ch->device->lun << 5) | + (ch->voltags ? 0x10 : 0) | + ch_elem_to_typecode(ch,elem); + cmd[2] = (elem >> 8) & 0xff; + cmd[3] = elem & 0xff; + cmd[5] = 1; + cmd[9] = 255; + if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256))) { + if (((buffer[16] << 8) | buffer[17]) != elem) { + dprintk("asked for element 0x%02x, got 0x%02x\n", + elem,(buffer[16] << 8) | buffer[17]); + kfree(buffer); + return -EIO; + } + memcpy(data,buffer+16,16); + } else { + if (ch->voltags) { + ch->voltags = 0; + vprintk("device has no volume tag support%s\n",""); + goto retry; + } + dprintk("READ ELEMENT STATUS for element 0x%x failed\n",elem); + } + kfree(buffer); + return result; +} + +static int +ch_init_elem(scsi_changer *ch) +{ + int err; + u_char cmd[6]; + + vprintk("INITIALIZE ELEMENT STATUS, may take some time ...%s\n",""); + memset(cmd,0,sizeof(cmd)); + cmd[0] = INITIALIZE_ELEMENT_STATUS; + cmd[1] = ch->device->lun << 5; + err = ch_do_scsi(ch, cmd, NULL, 0); + vprintk("... finished%s\n",""); + return err; +} + +static int +ch_readconfig(scsi_changer *ch) +{ + u_char cmd[10], data[16]; + u_char *buffer; + int result,id,lun,i; + u_int elem; + + buffer = kmalloc(512, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + memset(buffer,0,512); + + memset(cmd,0,sizeof(cmd)); + cmd[0] = MODE_SENSE; + cmd[1] = ch->device->lun << 5; + cmd[2] = 0x1d; + cmd[4] = 255; + result = ch_do_scsi(ch, cmd, buffer, 255); + if (0 != result) { + cmd[1] |= (1<<3); + result = ch_do_scsi(ch, cmd, buffer, 255); + } + if (0 == result) { + ch->firsts[CHET_MT] = + (buffer[buffer[3]+ 6] << 8) | buffer[buffer[3]+ 7]; + ch->counts[CHET_MT] = + (buffer[buffer[3]+ 8] << 8) | buffer[buffer[3]+ 9]; + ch->firsts[CHET_ST] = + (buffer[buffer[3]+10] << 8) | buffer[buffer[3]+11]; + ch->counts[CHET_ST] = + (buffer[buffer[3]+12] << 8) | buffer[buffer[3]+13]; + ch->firsts[CHET_IE] = + (buffer[buffer[3]+14] << 8) | buffer[buffer[3]+15]; + ch->counts[CHET_IE] = + (buffer[buffer[3]+16] << 8) | buffer[buffer[3]+17]; + ch->firsts[CHET_DT] = + (buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19]; + ch->counts[CHET_DT] = + (buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21]; + vprintk("type #1 (mt): 0x%x+%d [medium transport]\n", + ch->firsts[CHET_MT], + ch->counts[CHET_MT]); + vprintk("type #2 (st): 0x%x+%d [storage]\n", + ch->firsts[CHET_ST], + ch->counts[CHET_ST]); + vprintk("type #3 (ie): 0x%x+%d [import/export]\n", + ch->firsts[CHET_IE], + ch->counts[CHET_IE]); + vprintk("type #4 (dt): 0x%x+%d [data transfer]\n", + ch->firsts[CHET_DT], + ch->counts[CHET_DT]); + } else { + vprintk("reading element address assigment page failed!%s\n", + ""); + } + + /* vendor specific element types */ + for (i = 0; i < 4; i++) { + if (0 == vendor_counts[i]) + continue; + if (NULL == vendor_labels[i]) + continue; + ch->firsts[CHET_V1+i] = vendor_firsts[i]; + ch->counts[CHET_V1+i] = vendor_counts[i]; + vprintk("type #%d (v%d): 0x%x+%d [%s, vendor specific]\n", + i+5,i+1,vendor_firsts[i],vendor_counts[i], + vendor_labels[i]); + } + + /* look up the devices of the data transfer elements */ + ch->dt = kmalloc(ch->counts[CHET_DT]*sizeof(struct scsi_device), + GFP_KERNEL); + for (elem = 0; elem < ch->counts[CHET_DT]; elem++) { + id = -1; + lun = 0; + if (-1 != dt_id[elem]) { + id = dt_id[elem]; + lun = dt_lun[elem]; + vprintk("dt 0x%x: [insmod option] ", + elem+ch->firsts[CHET_DT]); + } else if (0 != ch_read_element_status + (ch,elem+ch->firsts[CHET_DT],data)) { + vprintk("dt 0x%x: READ ELEMENT STATUS failed\n", + elem+ch->firsts[CHET_DT]); + } else { + vprintk("dt 0x%x: ",elem+ch->firsts[CHET_DT]); + if (data[6] & 0x80) { + if (verbose) + printk("not this SCSI bus\n"); + ch->dt[elem] = NULL; + } else if (0 == (data[6] & 0x30)) { + if (verbose) + printk("ID/LUN unknown\n"); + ch->dt[elem] = NULL; + } else { + id = ch->device->id; + lun = 0; + if (data[6] & 0x20) id = data[7]; + if (data[6] & 0x10) lun = data[6] & 7; + } + } + if (-1 != id) { + if (verbose) + printk("ID %i, LUN %i, ",id,lun); + ch->dt[elem] = + scsi_device_lookup(ch->device->host, + ch->device->channel, + id,lun); + if (!ch->dt[elem]) { + /* should not happen */ + if (verbose) + printk("Huh? device not found!\n"); + } else { + if (verbose) + printk("name: %8.8s %16.16s %4.4s\n", + ch->dt[elem]->vendor, + ch->dt[elem]->model, + ch->dt[elem]->rev); + } + } + } + ch->voltags = 1; + kfree(buffer); + + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static int +ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate) +{ + u_char cmd[10]; + + dprintk("position: 0x%x\n",elem); + if (0 == trans) + trans = ch->firsts[CHET_MT]; + memset(cmd,0,sizeof(cmd)); + cmd[0] = POSITION_TO_ELEMENT; + cmd[1] = ch->device->lun << 5; + cmd[2] = (trans >> 8) & 0xff; + cmd[3] = trans & 0xff; + cmd[4] = (elem >> 8) & 0xff; + cmd[5] = elem & 0xff; + cmd[8] = rotate ? 1 : 0; + return ch_do_scsi(ch, cmd, NULL,0); +} + +static int +ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) +{ + u_char cmd[12]; + + dprintk("move: 0x%x => 0x%x\n",src,dest); + if (0 == trans) + trans = ch->firsts[CHET_MT]; + memset(cmd,0,sizeof(cmd)); + cmd[0] = MOVE_MEDIUM; + cmd[1] = ch->device->lun << 5; + cmd[2] = (trans >> 8) & 0xff; + cmd[3] = trans & 0xff; + cmd[4] = (src >> 8) & 0xff; + cmd[5] = src & 0xff; + cmd[6] = (dest >> 8) & 0xff; + cmd[7] = dest & 0xff; + cmd[10] = rotate ? 1 : 0; + return ch_do_scsi(ch, cmd, NULL,0); +} + +static int +ch_exchange(scsi_changer *ch, u_int trans, u_int src, + u_int dest1, u_int dest2, int rotate1, int rotate2) +{ + u_char cmd[12]; + + dprintk("exchange: 0x%x => 0x%x => 0x%x\n", + src,dest1,dest2); + if (0 == trans) + trans = ch->firsts[CHET_MT]; + memset(cmd,0,sizeof(cmd)); + cmd[0] = EXCHANGE_MEDIUM; + cmd[1] = ch->device->lun << 5; + cmd[2] = (trans >> 8) & 0xff; + cmd[3] = trans & 0xff; + cmd[4] = (src >> 8) & 0xff; + cmd[5] = src & 0xff; + cmd[6] = (dest1 >> 8) & 0xff; + cmd[7] = dest1 & 0xff; + cmd[8] = (dest2 >> 8) & 0xff; + cmd[9] = dest2 & 0xff; + cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0); + + return ch_do_scsi(ch, cmd, NULL,0); +} + +static void +ch_check_voltag(char *tag) +{ + int i; + + for (i = 0; i < 32; i++) { + /* restrict to ascii */ + if (tag[i] >= 0x7f || tag[i] < 0x20) + tag[i] = ' '; + /* don't allow search wildcards */ + if (tag[i] == '?' || + tag[i] == '*') + tag[i] = ' '; + } +} + +static int +ch_set_voltag(scsi_changer *ch, u_int elem, + int alternate, int clear, u_char *tag) +{ + u_char cmd[12]; + u_char *buffer; + int result; + + buffer = kmalloc(512, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + memset(buffer,0,512); + + dprintk("%s %s voltag: 0x%x => \"%s\"\n", + clear ? "clear" : "set", + alternate ? "alternate" : "primary", + elem, tag); + memset(cmd,0,sizeof(cmd)); + cmd[0] = SEND_VOLUME_TAG; + cmd[1] = (ch->device->lun << 5) | + ch_elem_to_typecode(ch,elem); + cmd[2] = (elem >> 8) & 0xff; + cmd[3] = elem & 0xff; + cmd[5] = clear + ? (alternate ? 0x0d : 0x0c) + : (alternate ? 0x0b : 0x0a); + + cmd[9] = 255; + + memcpy(buffer,tag,32); + ch_check_voltag(buffer); + + result = ch_do_scsi(ch, cmd, buffer, 256); + kfree(buffer); + return result; +} + +static int ch_gstatus(scsi_changer *ch, int type, unsigned char *dest) +{ + int retval = 0; + u_char data[16]; + unsigned int i; + + down(&ch->lock); + for (i = 0; i < ch->counts[type]; i++) { + if (0 != ch_read_element_status + (ch, ch->firsts[type]+i,data)) { + retval = -EIO; + break; + } + put_user(data[2], dest+i); + if (data[2] & CESTATUS_EXCEPT) + vprintk("element 0x%x: asc=0x%x, ascq=0x%x\n", + ch->firsts[type]+i, + (int)data[4],(int)data[5]); + retval = ch_read_element_status + (ch, ch->firsts[type]+i,data); + if (0 != retval) + break; + } + up(&ch->lock); + return retval; +} + +/* ------------------------------------------------------------------------ */ + +static int +ch_release(struct inode *inode, struct file *file) +{ + scsi_changer *ch = file->private_data; + + scsi_device_put(ch->device); + file->private_data = NULL; + return 0; +} + +static int +ch_open(struct inode *inode, struct file *file) +{ + scsi_changer *tmp, *ch; + int minor = iminor(inode); + + spin_lock(&ch_devlist_lock); + ch = NULL; + list_for_each_entry(tmp,&ch_devlist,list) { + if (tmp->minor == minor) + ch = tmp; + } + if (NULL == ch || scsi_device_get(ch->device)) { + spin_unlock(&ch_devlist_lock); + return -ENXIO; + } + spin_unlock(&ch_devlist_lock); + + file->private_data = ch; + return 0; +} + +static int +ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit) +{ + if (type >= CH_TYPES || unit >= ch->counts[type]) + return -1; + return 0; +} + +static int ch_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + scsi_changer *ch = file->private_data; + int retval; + + switch (cmd) { + case CHIOGPARAMS: + { + struct changer_params params; + + params.cp_curpicker = 0; + params.cp_npickers = ch->counts[CHET_MT]; + params.cp_nslots = ch->counts[CHET_ST]; + params.cp_nportals = ch->counts[CHET_IE]; + params.cp_ndrives = ch->counts[CHET_DT]; + + if (copy_to_user((void *) arg, ¶ms, sizeof(params))) + return -EFAULT; + return 0; + } + case CHIOGVPARAMS: + { + struct changer_vendor_params vparams; + + memset(&vparams,0,sizeof(vparams)); + if (ch->counts[CHET_V1]) { + vparams.cvp_n1 = ch->counts[CHET_V1]; + strncpy(vparams.cvp_label1,vendor_labels[0],16); + } + if (ch->counts[CHET_V2]) { + vparams.cvp_n2 = ch->counts[CHET_V2]; + strncpy(vparams.cvp_label2,vendor_labels[1],16); + } + if (ch->counts[CHET_V3]) { + vparams.cvp_n3 = ch->counts[CHET_V3]; + strncpy(vparams.cvp_label3,vendor_labels[2],16); + } + if (ch->counts[CHET_V4]) { + vparams.cvp_n4 = ch->counts[CHET_V4]; + strncpy(vparams.cvp_label4,vendor_labels[3],16); + } + if (copy_to_user((void *) arg, &vparams, sizeof(vparams))) + return -EFAULT; + return 0; + } + + case CHIOPOSITION: + { + struct changer_position pos; + + if (copy_from_user(&pos, (void*)arg, sizeof (pos))) + return -EFAULT; + + if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) { + dprintk("CHIOPOSITION: invalid parameter%s\n",""); + return -EBADSLT; + } + down(&ch->lock); + retval = ch_position(ch,0, + ch->firsts[pos.cp_type] + pos.cp_unit, + pos.cp_flags & CP_INVERT); + up(&ch->lock); + return retval; + } + + case CHIOMOVE: + { + struct changer_move mv; + + if (copy_from_user(&mv, (void*)arg, sizeof (mv))) + return -EFAULT; + + if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) || + 0 != ch_checkrange(ch, mv.cm_totype, mv.cm_tounit )) { + dprintk("CHIOMOVE: invalid parameter%s\n",""); + return -EBADSLT; + } + + down(&ch->lock); + retval = ch_move(ch,0, + ch->firsts[mv.cm_fromtype] + mv.cm_fromunit, + ch->firsts[mv.cm_totype] + mv.cm_tounit, + mv.cm_flags & CM_INVERT); + up(&ch->lock); + return retval; + } + + case CHIOEXCHANGE: + { + struct changer_exchange mv; + + if (copy_from_user(&mv, (void*)arg, sizeof (mv))) + return -EFAULT; + + if (0 != ch_checkrange(ch, mv.ce_srctype, mv.ce_srcunit ) || + 0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) || + 0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) { + dprintk("CHIOEXCHANGE: invalid parameter%s\n",""); + return -EBADSLT; + } + + down(&ch->lock); + retval = ch_exchange + (ch,0, + ch->firsts[mv.ce_srctype] + mv.ce_srcunit, + ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit, + ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit, + mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2); + up(&ch->lock); + return retval; + } + + case CHIOGSTATUS: + { + struct changer_element_status ces; + + if (copy_from_user(&ces, (void*)arg, sizeof (ces))) + return -EFAULT; + if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES) + return -EINVAL; + + return ch_gstatus(ch, ces.ces_type, ces.ces_data); + } + + case CHIOGELEM: + { + struct changer_get_element cge; + u_char cmd[12]; + u_char *buffer; + unsigned int elem; + int result,i; + + if (copy_from_user(&cge, (void*)arg, sizeof (cge))) + return -EFAULT; + + if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) + return -EINVAL; + elem = ch->firsts[cge.cge_type] + cge.cge_unit; + + buffer = kmalloc(512, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + down(&ch->lock); + + voltag_retry: + memset(cmd,0,sizeof(cmd)); + cmd[0] = READ_ELEMENT_STATUS; + cmd[1] = (ch->device->lun << 5) | + (ch->voltags ? 0x10 : 0) | + ch_elem_to_typecode(ch,elem); + cmd[2] = (elem >> 8) & 0xff; + cmd[3] = elem & 0xff; + cmd[5] = 1; + cmd[9] = 255; + + if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256))) { + cge.cge_status = buffer[18]; + cge.cge_flags = 0; + if (buffer[18] & CESTATUS_EXCEPT) { + /* FIXME: fill cge_errno */ + } + if (buffer[25] & 0x80) { + cge.cge_flags |= CGE_SRC; + if (buffer[25] & 0x40) + cge.cge_flags |= CGE_INVERT; + elem = (buffer[26]<<8) | buffer[27]; + for (i = 0; i < 4; i++) { + if (elem >= ch->firsts[i] && + elem < ch->firsts[i] + ch->counts[i]) { + cge.cge_srctype = i; + cge.cge_srcunit = elem-ch->firsts[i]; + } + } + } + if ((buffer[22] & 0x30) == 0x30) { + cge.cge_flags |= CGE_IDLUN; + cge.cge_id = buffer[23]; + cge.cge_lun = buffer[22] & 7; + } + if (buffer[9] & 0x80) { + cge.cge_flags |= CGE_PVOLTAG; + memcpy(cge.cge_pvoltag,buffer+28,36); + } + if (buffer[9] & 0x40) { + cge.cge_flags |= CGE_AVOLTAG; + memcpy(cge.cge_avoltag,buffer+64,36); + } + } else if (ch->voltags) { + ch->voltags = 0; + vprintk("device has no volume tag support%s\n",""); + goto voltag_retry; + } + kfree(buffer); + up(&ch->lock); + + if (copy_to_user((void*)arg, &cge, sizeof (cge))) + return -EFAULT; + return result; + } + + case CHIOINITELEM: + { + down(&ch->lock); + retval = ch_init_elem(ch); + up(&ch->lock); + return retval; + } + + case CHIOSVOLTAG: + { + struct changer_set_voltag csv; + int elem; + + if (copy_from_user(&csv, (void*)arg, sizeof(csv))) + return -EFAULT; + + if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) { + dprintk("CHIOSVOLTAG: invalid parameter%s\n",""); + return -EBADSLT; + } + elem = ch->firsts[csv.csv_type] + csv.csv_unit; + down(&ch->lock); + retval = ch_set_voltag(ch, elem, + csv.csv_flags & CSV_AVOLTAG, + csv.csv_flags & CSV_CLEARTAG, + csv.csv_voltag); + up(&ch->lock); + return retval; + } + + default: + return scsi_ioctl(ch->device, cmd, (void*)arg); + + } +} + +#ifdef CONFIG_COMPAT + +struct changer_element_status32 { + int ces_type; + compat_uptr_t ces_data; +}; +#define CHIOGSTATUS32 _IOW('c', 8,struct changer_element_status32) + +static long ch_ioctl_compat(struct file * file, + unsigned int cmd, unsigned long arg) +{ + scsi_changer *ch = file->private_data; + + switch (cmd) { + case CHIOGPARAMS: + case CHIOGVPARAMS: + case CHIOPOSITION: + case CHIOMOVE: + case CHIOEXCHANGE: + case CHIOGELEM: + case CHIOINITELEM: + case CHIOSVOLTAG: + /* compatible */ + return ch_ioctl(NULL /* inode, unused */, + file, cmd, arg); + case CHIOGSTATUS32: + { + struct changer_element_status32 ces32; + unsigned char *data; + + if (copy_from_user(&ces32, (void*)arg, sizeof (ces32))) + return -EFAULT; + if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES) + return -EINVAL; + + data = compat_ptr(ces32.ces_data); + return ch_gstatus(ch, ces32.ces_type, data); + } + default: + // return scsi_ioctl_compat(ch->device, cmd, (void*)arg); + return -ENOIOCTLCMD; + + } +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int ch_probe(struct device *dev) +{ + struct scsi_device *sd = to_scsi_device(dev); + scsi_changer *ch; + + if (sd->type != TYPE_MEDIUM_CHANGER) + return -ENODEV; + + ch = kmalloc(sizeof(*ch), GFP_KERNEL); + if (NULL == ch) + return -ENOMEM; + + memset(ch,0,sizeof(*ch)); + ch->minor = ch_devcount; + sprintf(ch->name,"ch%d",ch->minor); + init_MUTEX(&ch->lock); + ch->device = sd; + ch_readconfig(ch); + if (init) + ch_init_elem(ch); + + devfs_mk_cdev(MKDEV(SCSI_CHANGER_MAJOR,ch->minor), + S_IFCHR | S_IRUGO | S_IWUGO, ch->name); + + printk(KERN_INFO "Attached scsi changer %s " + "at scsi%d, channel %d, id %d, lun %d\n", + ch->name, sd->host->host_no, sd->channel, sd->id, sd->lun); + + spin_lock(&ch_devlist_lock); + list_add_tail(&ch->list,&ch_devlist); + ch_devcount++; + spin_unlock(&ch_devlist_lock); + return 0; +} + +static int ch_remove(struct device *dev) +{ + struct scsi_device *sd = to_scsi_device(dev); + scsi_changer *tmp, *ch; + + spin_lock(&ch_devlist_lock); + ch = NULL; + list_for_each_entry(tmp,&ch_devlist,list) { + if (tmp->device == sd) + ch = tmp; + } + BUG_ON(NULL == ch); + list_del(&ch->list); + spin_unlock(&ch_devlist_lock); + + devfs_remove(ch->name); + kfree(ch->dt); + kfree(ch); + ch_devcount--; + return 0; +} + +static int __init init_ch_module(void) +{ + int rc; + + printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n"); + rc = register_chrdev(SCSI_CHANGER_MAJOR,"ch",&changer_fops); + if (rc < 0) { + printk("Unable to get major %d for SCSI-Changer\n", + SCSI_CHANGER_MAJOR); + return rc; + } + rc = scsi_register_driver(&ch_template.gendrv); + if (rc < 0) + goto fail1; + return 0; + + fail1: + unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); + return rc; +} + +static void __exit exit_ch_module(void) +{ + scsi_unregister_driver(&ch_template.gendrv); + unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); +} + +module_init(init_ch_module); +module_exit(exit_ch_module); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/include/asm-alpha/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-alpha/ioctls.h 2005-03-07 10:14:47.000000000 +0100 +++ linux-2.6.11/include/asm-alpha/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -91,6 +91,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 Index: linux-2.6.11/include/asm-arm/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-arm/ioctls.h 2005-03-07 10:13:49.000000000 +0100 +++ linux-2.6.11/include/asm-arm/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -48,6 +48,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 Index: linux-2.6.11/include/asm-i386/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-i386/ioctls.h 2005-03-07 10:12:46.000000000 +0100 +++ linux-2.6.11/include/asm-i386/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -49,6 +49,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 #define FIOCLEX 0x5451 Index: linux-2.6.11/include/asm-ia64/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-ia64/ioctls.h 2005-03-07 10:12:52.000000000 +0100 +++ linux-2.6.11/include/asm-ia64/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -55,6 +55,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 Index: linux-2.6.11/include/asm-m68k/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-m68k/ioctls.h 2005-03-07 10:14:32.000000000 +0100 +++ linux-2.6.11/include/asm-m68k/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -48,6 +48,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 Index: linux-2.6.11/include/asm-mips/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-mips/ioctls.h 2005-03-07 10:15:10.000000000 +0100 +++ linux-2.6.11/include/asm-mips/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -79,6 +79,7 @@ #define TIOCGSID 0x7416 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ /* I hope the range from 0x5480 on is free ... */ #define TIOCSCTTY 0x5480 /* become controlling tty */ Index: linux-2.6.11/include/asm-ppc/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-ppc/ioctls.h 2005-03-07 10:14:59.000000000 +0100 +++ linux-2.6.11/include/asm-ppc/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -88,6 +88,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 Index: linux-2.6.11/include/asm-ppc64/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-ppc64/ioctls.h 2005-03-07 10:12:24.000000000 +0100 +++ linux-2.6.11/include/asm-ppc64/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -95,6 +95,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define TIOCSERCONFIG 0x5453 #define TIOCSERGWILD 0x5454 Index: linux-2.6.11/include/asm-s390/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-s390/ioctls.h 2005-03-07 10:14:12.000000000 +0100 +++ linux-2.6.11/include/asm-s390/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -56,6 +56,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 Index: linux-2.6.11/include/asm-sh/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-sh/ioctls.h 2005-03-07 10:14:29.000000000 +0100 +++ linux-2.6.11/include/asm-sh/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -80,6 +80,7 @@ #define TIOCGSID _IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */ #define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */ Index: linux-2.6.11/include/asm-sparc/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-sparc/ioctls.h 2005-03-07 10:13:48.000000000 +0100 +++ linux-2.6.11/include/asm-sparc/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -15,6 +15,7 @@ #define TCSETS _IOW('T', 9, struct termios) #define TCSETSW _IOW('T', 10, struct termios) #define TCSETSF _IOW('T', 11, struct termios) +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ /* Note that all the ioctls that are not available in Linux have a * double underscore on the front to: a) avoid some programs to Index: linux-2.6.11/include/asm-sparc64/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-sparc64/ioctls.h 2005-03-07 10:14:05.000000000 +0100 +++ linux-2.6.11/include/asm-sparc64/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -16,6 +16,7 @@ #define TCSETS _IOW('T', 9, struct termios) #define TCSETSW _IOW('T', 10, struct termios) #define TCSETSF _IOW('T', 11, struct termios) +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ /* Note that all the ioctls that are not available in Linux have a * double underscore on the front to: a) avoid some programs to Index: linux-2.6.11/include/asm-x86_64/ioctls.h =================================================================== --- linux-2.6.11.orig/include/asm-x86_64/ioctls.h 2005-03-07 10:15:44.000000000 +0100 +++ linux-2.6.11/include/asm-x86_64/ioctls.h 2005-03-08 10:33:27.000000000 +0100 @@ -48,6 +48,7 @@ #define TIOCGSID 0x5429 /* Return the session ID of FD */ #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 Index: linux-2.6.11/include/linux/chio.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/include/linux/chio.h 2005-03-07 18:13:01.000000000 +0100 @@ -0,0 +1,168 @@ +/* + * ioctl interface for the scsi media changer driver + */ + +/* changer element types */ +#define CHET_MT 0 /* media transport element (robot) */ +#define CHET_ST 1 /* storage element (media slots) */ +#define CHET_IE 2 /* import/export element */ +#define CHET_DT 3 /* data transfer element (tape/cdrom/whatever) */ +#define CHET_V1 4 /* vendor specific #1 */ +#define CHET_V2 5 /* vendor specific #2 */ +#define CHET_V3 6 /* vendor specific #3 */ +#define CHET_V4 7 /* vendor specific #4 */ + + +/* + * CHIOGPARAMS + * query changer properties + * + * CHIOVGPARAMS + * query vendor-specific element types + * + * accessing elements works by specifing type and unit of the element. + * for eample, storage elements are addressed with type = CHET_ST and + * unit = 0 .. cp_nslots-1 + * + */ +struct changer_params { + int cp_curpicker; /* current transport element */ + int cp_npickers; /* number of transport elements (CHET_MT) */ + int cp_nslots; /* number of storage elements (CHET_ST) */ + int cp_nportals; /* number of import/export elements (CHET_IE) */ + int cp_ndrives; /* number of data transfer elements (CHET_DT) */ +}; +struct changer_vendor_params { + int cvp_n1; /* number of vendor specific elems (CHET_V1) */ + char cvp_label1[16]; + int cvp_n2; /* number of vendor specific elems (CHET_V2) */ + char cvp_label2[16]; + int cvp_n3; /* number of vendor specific elems (CHET_V3) */ + char cvp_label3[16]; + int cvp_n4; /* number of vendor specific elems (CHET_V4) */ + char cvp_label4[16]; + int reserved[8]; +}; + + +/* + * CHIOMOVE + * move a medium from one element to another + */ +struct changer_move { + int cm_fromtype; /* type/unit of source element */ + int cm_fromunit; + int cm_totype; /* type/unit of destination element */ + int cm_tounit; + int cm_flags; +}; +#define CM_INVERT 1 /* flag: rotate media (for double-sided like MOD) */ + + +/* + * CHIOEXCHANGE + * move one medium from element #1 to element #2, + * and another one from element #2 to element #3. + * element #1 and #3 are allowed to be identical. + */ +struct changer_exchange { + int ce_srctype; /* type/unit of element #1 */ + int ce_srcunit; + int ce_fdsttype; /* type/unit of element #2 */ + int ce_fdstunit; + int ce_sdsttype; /* type/unit of element #3 */ + int ce_sdstunit; + int ce_flags; +}; +#define CE_INVERT1 1 +#define CE_INVERT2 2 + + +/* + * CHIOPOSITION + * move the transport element (robot arm) to a specific element. + */ +struct changer_position { + int cp_type; + int cp_unit; + int cp_flags; +}; +#define CP_INVERT 1 + + +/* + * CHIOGSTATUS + * get element status for all elements of a specific type + */ +struct changer_element_status { + int ces_type; + unsigned char *ces_data; +}; +#define CESTATUS_FULL 0x01 /* full */ +#define CESTATUS_IMPEXP 0x02 /* media was imported (inserted by sysop) */ +#define CESTATUS_EXCEPT 0x04 /* error condition */ +#define CESTATUS_ACCESS 0x08 /* access allowed */ +#define CESTATUS_EXENAB 0x10 /* element can export media */ +#define CESTATUS_INENAB 0x20 /* element can import media */ + + +/* + * CHIOGELEM + * get more detailed status informtion for a single element + */ +struct changer_get_element { + int cge_type; /* type/unit */ + int cge_unit; + int cge_status; /* status */ + int cge_errno; /* errno */ + int cge_srctype; /* source element of the last move/exchange */ + int cge_srcunit; + int cge_id; /* scsi id (for data transfer elements) */ + int cge_lun; /* scsi lun (for data transfer elements) */ + char cge_pvoltag[36]; /* primary volume tag */ + char cge_avoltag[36]; /* alternate volume tag */ + int cge_flags; +}; +/* flags */ +#define CGE_ERRNO 0x01 /* errno available */ +#define CGE_INVERT 0x02 /* media inverted */ +#define CGE_SRC 0x04 /* media src available */ +#define CGE_IDLUN 0x08 /* ID+LUN available */ +#define CGE_PVOLTAG 0x10 /* primary volume tag available */ +#define CGE_AVOLTAG 0x20 /* alternate volume tag available */ + + +/* + * CHIOSVOLTAG + * set volume tag + */ +struct changer_set_voltag { + int csv_type; /* type/unit */ + int csv_unit; + char csv_voltag[36]; /* volume tag */ + int csv_flags; +}; +#define CSV_PVOLTAG 0x01 /* primary volume tag */ +#define CSV_AVOLTAG 0x02 /* alternate volume tag */ +#define CSV_CLEARTAG 0x04 /* clear volume tag */ + +/* ioctls */ +#define CHIOMOVE _IOW('c', 1,struct changer_move) +#define CHIOEXCHANGE _IOW('c', 2,struct changer_exchange) +#define CHIOPOSITION _IOW('c', 3,struct changer_position) +#define CHIOGPICKER _IOR('c', 4,int) /* not impl. */ +#define CHIOSPICKER _IOW('c', 5,int) /* not impl. */ +#define CHIOGPARAMS _IOR('c', 6,struct changer_params) +#define CHIOGSTATUS _IOW('c', 8,struct changer_element_status) +#define CHIOGELEM _IOW('c',16,struct changer_get_element) +#define CHIOINITELEM _IO('c',17) +#define CHIOSVOLTAG _IOW('c',18,struct changer_set_voltag) +#define CHIOGVPARAMS _IOR('c',19,struct changer_vendor_params) + +/* ---------------------------------------------------------------------- */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/include/linux/compat_ioctl.h =================================================================== --- linux-2.6.11.orig/include/linux/compat_ioctl.h 2005-03-07 10:15:29.000000000 +0100 +++ linux-2.6.11/include/linux/compat_ioctl.h 2005-03-08 10:33:27.000000000 +0100 @@ -27,6 +27,7 @@ COMPATIBLE_IOCTL(TIOCSBRK) COMPATIBLE_IOCTL(TIOCCBRK) ULONG_IOCTL(TIOCMIWAIT) COMPATIBLE_IOCTL(TIOCGICOUNT) +COMPATIBLE_IOCTL(TIOCGDEV) /* Little t */ COMPATIBLE_IOCTL(TIOCGETD) COMPATIBLE_IOCTL(TIOCSETD) Index: linux-2.6.11/include/linux/major.h =================================================================== --- linux-2.6.11.orig/include/linux/major.h 2005-03-07 10:13:10.000000000 +0100 +++ linux-2.6.11/include/linux/major.h 2005-03-07 18:13:01.000000000 +0100 @@ -101,6 +101,7 @@ #define I2O_MAJOR 80 /* 80->87 */ #define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ +#define SCSI_CHANGER_MAJOR 86 #define IDE6_MAJOR 88 #define IDE7_MAJOR 89 Index: linux-2.6.11/include/linux/videodev2.h =================================================================== --- linux-2.6.11.orig/include/linux/videodev2.h 2005-03-07 10:14:30.000000000 +0100 +++ linux-2.6.11/include/linux/videodev2.h 2005-03-08 10:33:27.000000000 +0100 @@ -268,64 +268,92 @@ struct v4l2_timecode /* The above is based on SMPTE timecodes */ +#if 1 /* - * C O M P R E S S I O N P A R A M E T E R S + * M P E G C O M P R E S S I O N P A R A M E T E R S + * + * ### WARNING: this is still work-in-progress right now, most likely + * ### there will be some incompatible changes. + * */ -#if 0 -/* ### generic compression settings don't work, there is too much - * ### codec-specific stuff. Maybe reuse that for MPEG codec settings - * ### later ... */ -struct v4l2_compression -{ - __u32 quality; - __u32 keyframerate; - __u32 pframerate; - __u32 reserved[5]; -/* what we'll need for MPEG, extracted from some postings on - the v4l list (Gert Vervoort, PlasmaJohn). -system stream: - - type: elementary stream(ES), packatised elementary stream(s) (PES) - program stream(PS), transport stream(TS) - - system bitrate - - PS packet size (DVD: 2048 bytes, VCD: 2324 bytes) - - TS video PID - - TS audio PID - - TS PCR PID - - TS system information tables (PAT, PMT, CAT, NIT and SIT) - - (MPEG-1 systems stream vs. MPEG-2 program stream (TS not supported - by MPEG-1 systems) +enum v4l2_bitrate_mode { + V4L2_BITRATE_NONE = 0, /* not specified */ + V4L2_BITRATE_CBR, /* constant bitrate */ + V4L2_BITRATE_VBR, /* variable bitrate */ +}; +struct v4l2_bitrate { + /* rates are specified in kbit/sec */ + enum v4l2_bitrate_mode mode; + __u32 min; + __u32 target; /* use this one for CBR */ + __u32 max; +}; -audio: - - type: MPEG (+Layer I,II,III), AC-3, LPCM - - bitrate - - sampling frequency (DVD: 48 Khz, VCD: 44.1 KHz, 32 kHz) - - Trick Modes? (ff, rew) - - Copyright - - Inverse Telecine +enum v4l2_mpeg_streamtype { + V4L2_MPEG_SS_1, /* MPEG-1 system stream */ + V4L2_MPEG_PS_2, /* MPEG-2 program stream */ + V4L2_MPEG_TS_2, /* MPEG-2 transport stream */ + V4L2_MPEG_PS_DVD, /* MPEG-2 program stream with DVD header fixups */ +}; +enum v4l2_mpeg_audiotype { + V4L2_MPEG_AU_2_I, /* MPEG-2 layer 1 */ + V4L2_MPEG_AU_2_II, /* MPEG-2 layer 2 */ + V4L2_MPEG_AU_2_III, /* MPEG-2 layer 3 */ + V4L2_MPEG_AC3, /* AC3 */ + V4L2_MPEG_LPCM, /* LPCM */ +}; +enum v4l2_mpeg_videotype { + V4L2_MPEG_VI_1, /* MPEG-1 */ + V4L2_MPEG_VI_2, /* MPEG-2 */ +}; +enum v4l2_mpeg_aspectratio { + V4L2_MPEG_ASPECT_SQUARE = 1, /* square pixel */ + V4L2_MPEG_ASPECT_4_3 = 2, /* 4 : 3 */ + V4L2_MPEG_ASPECT_16_9 = 3, /* 16 : 9 */ + V4L2_MPEG_ASPECT_1_221 = 4, /* 1 : 2,21 */ +}; -video: - - picturesize (SIF, 1/2 D1, 2/3 D1, D1) and PAL/NTSC norm can be set - through excisting V4L2 controls - - noise reduction, parameters encoder specific? - - MPEG video version: MPEG-1, MPEG-2 - - GOP (Group Of Pictures) definition: - - N: number of frames per GOP - - M: distance between reference (I,P) frames - - open/closed GOP - - quantiser matrix: inter Q matrix (64 bytes) and intra Q matrix (64 bytes) - - quantiser scale: linear or logarithmic - - scanning: alternate or zigzag - - bitrate mode: CBR (constant bitrate) or VBR (variable bitrate). - - target video bitrate for CBR - - target video bitrate for VBR - - maximum video bitrate for VBR - min. quantiser value for VBR - - max. quantiser value for VBR - - adaptive quantisation value - - return the number of bytes per GOP or bitrate for bitrate monitoring +struct v4l2_mpeg_compression { + /* general */ + enum v4l2_mpeg_streamtype st_type; + struct v4l2_bitrate st_bitrate; -*/ + /* transport streams */ + __u16 ts_pid_pmt; + __u16 ts_pid_audio; + __u16 ts_pid_video; + __u16 ts_pid_pcr; + + /* program stream */ + __u16 ps_size; + __u16 reserved_1; /* align */ + + /* audio */ + enum v4l2_mpeg_audiotype au_type; + struct v4l2_bitrate au_bitrate; + __u32 au_sample_rate; + __u8 au_pesid; + __u8 reserved_2[3]; /* align */ + + /* video */ + enum v4l2_mpeg_videotype vi_type; + enum v4l2_mpeg_aspectratio vi_aspect_ratio; + struct v4l2_bitrate vi_bitrate; + __u32 vi_frame_rate; + __u16 vi_frames_per_gop; + __u16 vi_bframes_count; + __u8 vi_pesid; + __u8 reserved_3[3]; /* align */ + + /* misc flags */ + __u32 closed_gops:1; + __u32 pulldown:1; + __u32 reserved_4:30; /* align */ + + /* I don't expect the above being perfect yet ;) */ + __u32 reserved_5[8]; }; #endif @@ -841,9 +869,9 @@ struct v4l2_streamparm #define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc) #define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format) #define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format) -#if 0 -#define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression) -#define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression) +#if 1 /* experimental */ +#define VIDIOC_G_MPEGCOMP _IOR ('V', 6, struct v4l2_mpeg_compression) +#define VIDIOC_S_MPEGCOMP _IOW ('V', 7, struct v4l2_mpeg_compression) #endif #define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers) #define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) Index: linux-2.6.11/include/media/ir-common.h =================================================================== --- linux-2.6.11.orig/include/media/ir-common.h 2005-03-07 10:15:15.000000000 +0100 +++ linux-2.6.11/include/media/ir-common.h 2005-03-07 18:13:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - * $Id: ir-common.h,v 1.6 2004/09/15 16:15:24 kraxel Exp $ + * $Id: ir-common.h,v 1.8 2005/02/22 12:28:40 kraxel Exp $ * * some common structs and functions to handle infrared remotes via * input layer ... @@ -47,7 +47,9 @@ struct ir_input_state { }; extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE]; void ir_input_init(struct input_dev *dev, struct ir_input_state *ir, int ir_type, IR_KEYTAB_TYPE *ir_codes); @@ -55,6 +57,8 @@ void ir_input_nokey(struct input_dev *de void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, u32 ir_key, u32 ir_raw); u32 ir_extract_bits(u32 data, u32 mask); +int ir_dump_samples(u32 *samples, int count); +int ir_decode_biphase(u32 *samples, int count, int low, int high); /* * Local variables: Index: linux-2.6.11/include/media/saa6752hs.h =================================================================== --- linux-2.6.11.orig/include/media/saa6752hs.h 2005-03-07 10:16:30.000000000 +0100 +++ linux-2.6.11/include/media/saa6752hs.h 2005-03-08 10:33:27.000000000 +0100 @@ -18,14 +18,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef _SAA6752HS_H +#if 0 /* ndef _SAA6752HS_H */ #define _SAA6752HS_H -enum mpeg_bitrate_mode { - MPEG_BITRATE_MODE_VBR = 0, /* Variable bitrate */ - MPEG_BITRATE_MODE_CBR = 1, /* Constant bitrate */ +enum mpeg_video_bitrate_mode { + MPEG_VIDEO_BITRATE_MODE_VBR = 0, /* Variable bitrate */ + MPEG_VIDEO_BITRATE_MODE_CBR = 1, /* Constant bitrate */ - MPEG_BITRATE_MODE_MAX + MPEG_VIDEO_BITRATE_MODE_MAX }; enum mpeg_audio_bitrate { @@ -35,16 +35,33 @@ enum mpeg_audio_bitrate { MPEG_AUDIO_BITRATE_MAX }; +enum mpeg_video_format { + MPEG_VIDEO_FORMAT_D1 = 0, + MPEG_VIDEO_FORMAT_2_3_D1 = 1, + MPEG_VIDEO_FORMAT_1_2_D1 = 2, + MPEG_VIDEO_FORMAT_SIF = 3, + + MPEG_VIDEO_FORMAT_MAX +}; + #define MPEG_VIDEO_TARGET_BITRATE_MAX 27000 #define MPEG_VIDEO_MAX_BITRATE_MAX 27000 #define MPEG_TOTAL_BITRATE_MAX 27000 +#define MPEG_PID_MAX ((1 << 14) - 1) struct mpeg_params { - enum mpeg_bitrate_mode bitrate_mode; + enum mpeg_video_bitrate_mode video_bitrate_mode; unsigned int video_target_bitrate; unsigned int video_max_bitrate; // only used for VBR enum mpeg_audio_bitrate audio_bitrate; unsigned int total_bitrate; + + unsigned int pmt_pid; + unsigned int video_pid; + unsigned int audio_pid; + unsigned int pcr_pid; + + enum mpeg_video_format video_format; }; #define MPEG_SETPARAMS _IOW('6',100,struct mpeg_params) Index: linux-2.6.11/include/media/tuner.h =================================================================== --- linux-2.6.11.orig/include/media/tuner.h 2005-03-07 10:14:42.000000000 +0100 +++ linux-2.6.11/include/media/tuner.h 2005-03-08 10:32:50.000000000 +0100 @@ -29,55 +29,74 @@ #define TUNER_PHILIPS_PAL_I 1 #define TUNER_PHILIPS_NTSC 2 #define TUNER_PHILIPS_SECAM 3 /* you must actively select B/G, L, L` */ + #define TUNER_ABSENT 4 #define TUNER_PHILIPS_PAL 5 #define TUNER_TEMIC_NTSC 6 /* 4032 FY5 (3X 7004, 9498, 9789) */ #define TUNER_TEMIC_PAL_I 7 /* 4062 FY5 (3X 8501, 9957) */ + #define TUNER_TEMIC_4036FY5_NTSC 8 /* 4036 FY5 (3X 1223, 1981, 7686) */ #define TUNER_ALPS_TSBH1_NTSC 9 #define TUNER_ALPS_TSBE1_PAL 10 #define TUNER_ALPS_TSBB5_PAL_I 11 + #define TUNER_ALPS_TSBE5_PAL 12 #define TUNER_ALPS_TSBC5_PAL 13 #define TUNER_TEMIC_4006FH5_PAL 14 /* 4006 FH5 (3X 9500, 9501, 7291) */ #define TUNER_ALPS_TSHC6_NTSC 15 + #define TUNER_TEMIC_PAL_DK 16 /* 4016 FY5 (3X 1392, 1393) */ #define TUNER_PHILIPS_NTSC_M 17 #define TUNER_TEMIC_4066FY5_PAL_I 18 /* 4066 FY5 (3X 7032, 7035) */ #define TUNER_TEMIC_4006FN5_MULTI_PAL 19 /* B/G, I and D/K autodetected (3X 7595, 7606, 7657)*/ + #define TUNER_TEMIC_4009FR5_PAL 20 /* incl. FM radio (3X 7607, 7488, 7711)*/ #define TUNER_TEMIC_4039FR5_NTSC 21 /* incl. FM radio (3X 7246, 7578, 7732)*/ #define TUNER_TEMIC_4046FM5 22 /* you must actively select B/G, D/K, I, L, L` ! (3X 7804, 7806, 8103, 8104)*/ #define TUNER_PHILIPS_PAL_DK 23 + #define TUNER_PHILIPS_FQ1216ME 24 /* you must actively select B/G/D/K, I, L, L` */ #define TUNER_LG_PAL_I_FM 25 #define TUNER_LG_PAL_I 26 #define TUNER_LG_NTSC_FM 27 + #define TUNER_LG_PAL_FM 28 #define TUNER_LG_PAL 29 #define TUNER_TEMIC_4009FN5_MULTI_PAL_FM 30 /* B/G, I and D/K autodetected (3X 8155, 8160, 8163)*/ #define TUNER_SHARP_2U5JF5540_NTSC 31 + #define TUNER_Samsung_PAL_TCPM9091PD27 32 #define TUNER_MT2032 33 #define TUNER_TEMIC_4106FH5 34 /* 4106 FH5 (3X 7808, 7865)*/ #define TUNER_TEMIC_4012FY5 35 /* 4012 FY5 (3X 0971, 1099)*/ + #define TUNER_TEMIC_4136FY5 36 /* 4136 FY5 (3X 7708, 7746)*/ #define TUNER_LG_PAL_NEW_TAPC 37 #define TUNER_PHILIPS_FM1216ME_MK3 38 #define TUNER_LG_NTSC_NEW_TAPC 39 + #define TUNER_HITACHI_NTSC 40 #define TUNER_PHILIPS_PAL_MK 41 #define TUNER_PHILIPS_ATSC 42 #define TUNER_PHILIPS_FM1236_MK3 43 + #define TUNER_PHILIPS_4IN1 44 /* ATI TV Wonder Pro - Conexant */ /* Microtune mergeged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */ #define TUNER_MICROTUNE_4049FM5 45 #define TUNER_LG_NTSC_TAPE 47 + #define TUNER_TNF_8831BGFF 48 #define TUNER_MICROTUNE_4042FI5 49 /* FusionHDTV 3 Gold - 4042 FI5 (3X 8147) */ #define TUNER_TCL_2002N 50 #define TUNER_PHILIPS_FM1256_IH3 51 + #define TUNER_THOMSON_DTT7610 52 +#define TUNER_PHILIPS_FQ1286 53 +#define TUNER_PHILIPS_TDA8290 54 +#define TUNER_LG_PAL_TAPE 55 /* Hauppauge PVR-150 PAL */ + +#define TUNER_PHILIPS_FQ1216AME_MK4 56 /* Hauppauge PVR-150 PAL */ +#define TUNER_PHILIPS_FQ1236A_MK4 57 /* Hauppauge PVR-500MCE NTSC */ #define NOTUNER 0 #define PAL 1 /* PAL_BG */ @@ -102,10 +121,6 @@ #define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */ #define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */ -#if 0 /* obsolete */ -# define TUNER_SET_RADIOFREQ _IOW('t',3,int) /* set radio freq */ -# define TUNER_SET_MODE _IOW('t',4,int) /* set tuner mode */ -#endif #define TDA9887_SET_CONFIG _IOW('t',5,int) /* tv card specific */ @@ -123,4 +138,62 @@ # define TDA9887_DEEMPHASIS_75 (3<<16) # define TDA9887_AUTOMUTE (1<<18) +#ifdef __KERNEL__ + +#define I2C_ADDR_TDA8290 0x4b +#define I2C_ADDR_TDA8275 0x61 + +struct tuner { + /* device */ + struct i2c_client i2c; + + /* state + config */ + unsigned int initialized; + unsigned int type; /* chip type */ + unsigned int freq; /* keep track of the current settings */ + v4l2_std_id std; + int using_v4l2; + + enum v4l2_tuner_type mode; + unsigned int input; + + /* used by MT2032 */ + unsigned int xogc; + unsigned int radio_if2; + + /* used by tda8290 */ + unsigned char i2c_easy_mode[2]; + unsigned char i2c_set_freq[8]; + + /* function ptrs */ + void (*tv_freq)(struct i2c_client *c, unsigned int freq); + void (*radio_freq)(struct i2c_client *c, unsigned int freq); + int (*has_signal)(struct i2c_client *c); + int (*is_stereo)(struct i2c_client *c); +}; + +extern unsigned int tuner_debug; +extern unsigned const int tuner_count; + +extern int microtune_init(struct i2c_client *c); +extern int tda8290_init(struct i2c_client *c); +extern int default_tuner_init(struct i2c_client *c); + +#define tuner_warn(fmt, arg...) \ + dev_printk(KERN_WARNING , &t->i2c.dev , fmt , ## arg) +#define tuner_info(fmt, arg...) \ + dev_printk(KERN_INFO , &t->i2c.dev , fmt , ## arg) +#define tuner_dbg(fmt, arg...) \ + if (tuner_debug) dev_printk(KERN_DEBUG , &t->i2c.dev , fmt , ## arg) + +#endif /* __KERNEL__ */ + #endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ Index: linux-2.6.11/include/scsi/scsi.h =================================================================== --- linux-2.6.11.orig/include/scsi/scsi.h 2005-03-07 10:15:45.000000000 +0100 +++ linux-2.6.11/include/scsi/scsi.h 2005-03-07 18:13:01.000000000 +0100 @@ -41,6 +41,7 @@ extern const char *const scsi_device_typ #define FORMAT_UNIT 0x04 #define READ_BLOCK_LIMITS 0x05 #define REASSIGN_BLOCKS 0x07 +#define INITIALIZE_ELEMENT_STATUS 0x07 #define READ_6 0x08 #define WRITE_6 0x0a #define SEEK_6 0x0b @@ -65,6 +66,7 @@ extern const char *const scsi_device_typ #define READ_10 0x28 #define WRITE_10 0x2a #define SEEK_10 0x2b +#define POSITION_TO_ELEMENT 0x2b #define WRITE_VERIFY 0x2e #define VERIFY 0x2f #define SEARCH_HIGH 0x30 @@ -97,6 +99,7 @@ extern const char *const scsi_device_typ #define PERSISTENT_RESERVE_OUT 0x5f #define REPORT_LUNS 0xa0 #define MOVE_MEDIUM 0xa5 +#define EXCHANGE_MEDIUM 0xa6 #define READ_12 0xa8 #define WRITE_12 0xaa #define WRITE_VERIFY_12 0xae Index: linux-2.6.11/localversion-kraxel =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.11/localversion-kraxel 2005-03-07 18:13:01.000000000 +0100 @@ -0,0 +1 @@ +-kraxel1